Voir le flux RSS

Pierre Fauconnier

De la bonne utilisation des userforms en VBA (1)

Noter ce billet
par , 25/03/2018 à 12h36 (641 Affichages)
Salut.

Voici ma réponse lors d'une demande de modification de variable globale au sein d'un userform. Outre le fait que les variables globales ne doivent être utilisées qu'en dernier recours car les procédures qui utilisent ces variables sont difficilement réutilisables ailleurs sans modifications, elles amènent à une mauvaise utilisation des userforms.

Ce que j'expose dans cette discussion est pour moi la bonne façon de travailler avec les userforms, qui ne sont que des collecteurs/afficheurs d'informations, mais qui ne peuvent normalement pas traiter l'information (sauf vérifications légères de saisie). C'est pourquoi j'ai créé ce billet avec ma contribution à ce problème.

Citation Envoyé par Pierre Fauconnier Voir le message
En fait, il y a trois états d'un userform:
  1. non chargé
  2. chargé mais non visible
  3. 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:
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
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.
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
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.)

Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Viadeo Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Twitter Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Google Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Facebook Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Digg Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Delicious Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog MySpace Envoyer le billet « De la bonne utilisation des userforms en VBA (1) » dans le blog Yahoo

Mis à jour 08/08/2018 à 10h13 par Pierre Fauconnier

Catégories
Programmation , VBA , MS Office

Commentaires