En fait, il y a trois états d'un userform:
- non chargé
- chargé mais non visible
- visible
Et ces trois états sont modifiés durant les étapes de la vie du userform dans le projet. En programmation trois couches (trois tiers), le userform fait partie de la couche appelée IHM (Interface Homme Machine ou encore PL pour Presentation Layer). Cette couche ne gère
que les interactions entre le programme et l'utilisateur (pour faire simple). Elle ne réalise donc normalement aucun traitement métier (à part des vérifications de saisie, éventuellement) et encore moins des traitements de stockage ou de lecture de données sur un support de données (DB, feuille Excel, fichiers de divers types, ...)
Au vu de ce qui précède, le userform sert
uniquement à afficher de l'info à l'utilisateur et à en collecter en provenance de cet utilisateur. C'est pourquoi ce n'est pas à lui de compter les points récoltés dans tes différents userforms.
Une procédure charge un userform, lui passe éventuellement des infos, l'ouvre, puis lorsque l'utilisateur ferme le userform, la procédure qui l'a ouvert reprend la main, collecte les infos dudit userform, le décharge puis appelle le suivant de la même manière. Dès lors, la procédure sur le click du bouton de fermeture du userform se résume en gros à le rendre invisible (ce qui rend la main à la procédure appelante).
Eventuellement, si on n'a rien à faire entre le chargement et l'affichage, on peut directement utiliser la méthode
.Show qui charge le formulaire s'il ne l'est pas.
Normalement, le userform est dit
encapsulé, c'est-à dire qu'il ne doit normalement pas avoir besoin de ressources extérieures (en termes de variables, notamment, et donc, pas de variables globales). En quelque sorte, il est autonome. En fait, il doit être écrit de manière à pouvoir être réutilisé dans un autre contexte dans lequel il doit jouer le même rôle sans dépendre de code externe (et notamment de variables globales).
On va imaginer un scénario complet pour que tu vois le principe de fonctionnement. On doit ouvrir un userform1, lui passer un message qui doit être affiché sur la barre de titre, l'afficher, puis récupérer les infos saisies, puis le fermer et passer à la suite du traitement.
Dans l'exemple qui suit, on dispose de deux userforms identiques: textbox
tboAnswer et deux boutons de commande
btnValidate et
btnCancel. Le code des userforms est le suivant:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| Option Explicit
Public Choice As String
Public Points As Integer
Private Sub btnCancel_Click()
Choice = "Cancel"
Me.Hide
End Sub
Private Sub btnValidate_Click()
If AnswerIsOk Then
TransferValues
Choice = "Validate"
Me.Hide
Else
MsgBox "Veuillez corriger votre saisie svp", vbExclamation
End If
End Sub
Function AnswerIsOk() As Boolean
' ...
' ...
' ...
AnswerIsOk = True
End Function
Sub TransferValues()
Points = txtAnswer.Value * 1
End Sub |
On voit donc le rôle réduit de
btnValidate. Il appelle la procédure de vérification, si c'est ok, il appelle la procédure de transfert des données (on pourrait jouer autrement pour cela, il y a des variantes possibles), puis masque le userform, ce qui rend la main à la procédure qui appelle le userform. On voit donc qu'il ne fait aucun traitement: il ne vérifie pas, il ne transfère pas. Il appelle les procédures ad hoc dont c'est la responsabilité.
On remarque au passage que ce bouton attribue la valeur "Validate" à la variable publique
Choice et que la variable
Points du userform reçoit la valeur saisie dans le textbox si correcte (selon la fonction, fictive dans ce cas-ci, de vérification). Le second userform a, dans ton cas, un fonctionnement identique.
Au départ, le Userform1 est déchargé (Etat 1). La procédure appelante charge d'abord le userform1 sans l'afficher (état 2), ce qui permet de lui passer le texte à afficher sur la barre du userform, puis on l'affiche (Etat 3). Après un clic sur Validate ou Cancel, la main est rendue à la procédure appelante grâce à
Me.Hide. Le userform repasse à l'état 2, il est donc toujours chargé et on peut en récupérer des valeurs, puis on le décharge (Etat 1) et on passe à la suite.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| Option Explicit
Sub Play()
Dim Points As Integer
Dim Choice As String
Load UserForm1
UserForm1.Caption = "Bonjour" + Application.UserName
UserForm1.Show
Choice = UserForm1.Choice
If Choice = "Validate" Then
Points = UserForm1.Points
End If
Unload UserForm1
If Choice = "Validate" Then
Load UserForm2
UserForm2.Caption = "Bonjour" + Application.UserName
UserForm2.Show
Choice = UserForm2.Choice
If Choice = "Validate" Then
Points = Points + UserForm2.Points
End If
Unload UserForm2
End If
End Sub |
Ca paraît évidemment plus lourd que ton code actuel, mais c'est le fonctionnement normal d'un userform si tu souhaites coder proprement et faciliter la maintenance de ton code. Ca fait quelques lignes supplémentaires mais la qualité d'un code ne se mesure pas au nombre de lignes produites.
En codant tous mes userforms sur le même moule, d'abord ça va vite car cela devient une habitude, puis je m'y retrouve beaucoup plus facilement lorsque je dois m'y replonger.
Option Explicit
Au passage, tu dis que tu n'as pas
Option Explicit au début de tes modules. Je ne peux que t'encourager à ce que cette ligne soit présente. Elle t'obligera à déclarer
sytématiquement tes variables avant de les utiliser, ce qui évitera bien des erreurs (comme probablement celle que tu as rencontrée).
Pour la placer automatiquement sur tes
nouveaux modules, va dans Outils\Options\Editeur et coche
Déclaration des variables obligatoire (au passage, décoche si ce n'est déjà fait
Vérification automatique de la syntaxe, la ligne en erreur de syntaxe sera bien marquée en rouge mais au moins tu n'auras pas ce message intempestif en plein milieu de l'écran, brise-biscuits lorsque tu réalises des copier-coller de parties de code).
La case
Déclaration... cochée imposera à ton éditeur de placer
Option Explicit au début de chaque nouveau module. Pour les modules existants, à toi de choisir si tu la mets à la main ou pas (perso, je conseille de le faire, mais cela risque de t'amener à devoir modifier pas mal de code pour déclarer tes variables.)