VBA - Userforms & boutons dynamiques
Bonjour à tous,
Dans le cas de la population d'userform "depuis le code", c'est à dire dynamiquement, avec un nombre d'éléments ajoutés variables. J'aimerai que vous me donniez la confirmation comme qui il faille nécessairement passer par un module de classe pour gérer les callbacks éventuels, notamment sur les boutons.
Car dès lors que l'on a un nombre de boutons variables on ne peut pas vraiment les déclarer dans l'userform de manière explicite, tous les exemples passent par une collection qui garde les pointeurs vers ladite classe en mémoire pour gérer tous les boutons.
Sinon l'alternative que j'ai pu trouver est de passer par des évènements et faire du cas par cas en fonction de l'event levé.
Ci-après un petit exemple de ce que j'entends par classe de gestion du callback :
' Classe CButtonHandler
Option Explicit
Public WithEvents Btn As MSForms.CommandButton ' le contrôle réel
Private mHost As Object ' référence vers l’UserForm (ou un autre hôte)
Private mAction As String ' (optionnel) nom de macro pour Application.Run
' Initialisation du bouton + liaison des callbacks
Public Sub Init(ByVal Host As Object, ByVal Parent As Object, _
ByVal Name As String, ByVal Caption As String, _
ByVal Left As Single, ByVal Top As Single, _
Optional ByVal Action As String = "")
Set mHost = Host
mAction = Action
' Ajoute le contrôle sur l’UserForm
Set Btn = Parent.Controls.Add("Forms.CommandButton.1", Name, True)
With Btn
.Caption = Caption
.Left = Left
.Top = Top
.Width = 100
.Height = 26
.Tag = Action ' tu peux stocker ce que tu veux dans Tag
End With
End Sub
Private Sub Btn_Click()
' 1) Callback vers l'hôte (plus sûr, typé à la compile si tu veux)
On Error Resume Next
CallByName mHost, "OnDynamicButtonClick", VbMethod, Me ' passe l’instance de handler
If Err.Number = 0 Then Exit Sub
Err.Clear
' 2) (Optionnel) Sinon, fallback via Application.Run (late-binding)
If Len(mAction) > 0 Then
' Tu peux passer des arguments supplémentaires ici
Application.Run mAction, Btn.Name, Btn.Tag
Else
MsgBox "Clic sur " & Btn.Name, vbInformation
End If
End Sub
Public Property Get Action() As String
Action = mAction
End PropertyBonjour
Voila ce que l'IA donne comme conseils
Vous avez raison, dans le cas de la création dynamique d’éléments d’interface utilisateur comme des boutons sur un UserForm, il est nécessaire d’utiliser un module de classe pour gérer les événements de manière efficace. Cela est particulièrement vrai lorsque le nombre d’éléments (comme les boutons) peut varier, car vous ne pouvez pas déclarer ces contrôles de manière explicite à l’avance.
L’utilisation d’une classe pour gérer les événements permet de garder une référence à chaque bouton tout en vous permettant de traiter les événements de manière centralisée et organisée. Voici quelques points clés à considérer :
En résumé, votre approche en utilisant un module de classe pour gérer les événements des boutons créés dynamiquement est bien fondée. Cela facilite la maintenance et l’évolution de votre code, surtout dans le cas où le nombre d’éléments est variable.
bonjour,
en fait pour gérer les évènements li faut un objet de type WithEvents .
on aurait envi de déclarer un tableau WithEvents mais ce n'est pas un type de variables c'est une interface d'écoute de la com d'un objet bien déterminé c'est comme ça que les évènements de l'objet sont intercepté.
un WithEvents un objet.
Private WithEvents TB1 As MSForms.TextBox
Private WithEvents TB2 As MSForms.TextBox
Private WithEvents TB3 As MSForms.TextBox.
c'est pour cela qu'on utilise des modules de classe pour avoir une instance un objet même si l'objet de l'instance de la classe est un autre contrôle. même code autres contrôles.
dim tb(12) as new classe1
on notera également que la méthode terminate du userform ne suffira pas pour décharger les modules de classe car les évènements peuvent continuer à survivre après le unload du formulaire.
on notera également que la méthode terminate du userform ne suffira pas pour décharger les modules de classe car les évènements peuvent continuer à survivre après le unload du formulaire.
Bonjour,
Oui disons qu'il faut faire attention aux références (pointeurs) vers les instances de classe en question. Si nettoyé correctement dans le Terminate pas de soucis a priori, c'est le principe meme du garbage collector.
Quant au tableau oui c'est vrai. Le contournement possible est de passer par une classe "wrapper" de collection desdits objets. J'ai trouvé un petit article ici.