Class Module pour associer une macro à un bouton dynamiquement crée
Bonjour tout le monde,
J'ai besoin de votre aide. Je bloque sur l’exécution de mon "class module" et je n'arrive pas à trouver la solution. Je vous explique la macro :
- Un Userform demande à l'utilisateur de renseigner les données d'entrées concernant le nombre de document par catégorie (4 catégories : GT, ST, Gen, HRSG)
- En fonction des inputs du Userform2, un autre UserForm (UserForm3) s'ouvre pour demander à l'utilisateur de charger des documents référence (dans l'exemple ci dessous les inputs sont GT = 4, ST = 2, Gen = 2, HRSG = 2)
- Lorsque qu'on click sur les boutons "Load Source", je veux qu'un explorateur de fichier s'ouvre afin de sélectionner le fichier souhaité
Le problème que je rencontre est le suivant : J'ai réussi à ouvrir un explorateur de fichier quand on click sur le bouton mais ceci fonctionne seulement pour le dernier bouton de chaque catégorie. Pour chaque bouton créer je veux que la macro du class module 2 s'éxécute.
Voici le code dans mon UserForm2
' Déclarez la collection globalement pour gérer les instances des handlers de boutons
Public ButtonHandlers As Collection
Public ButtonHandlers2 As Collection
Sub InitializeButtonHandlers()
Set ButtonHandlers = New Collection
End Sub
Sub InitializeButtonHandlers2()
Set ButtonHandlers2 = New Collection
End Sub
Public Sub BtnUF2_Click()
Dim uf3 As UserForm3
Set uf3 = New UserForm3
' Retrieve values from UserForm2 textboxes
Dim GTcount As Integer
Dim STcount As Integer
Dim Gencount As Integer
Dim HRSGcount As Integer
GTcount = Val(Me.GTinput.Value)
STcount = Val(Me.STinput.Value)
Gencount = Val(Me.Geninput.Value)
HRSGcount = Val(Me.HRSGinput.Value)
' Initialize the collection if needed
If ButtonHandlers Is Nothing Then
Set ButtonHandlers = New Collection
End If
If ButtonHandlers2 Is Nothing Then
Set ButtonHandlers2 = New Collection
End If
'--------------------------------------------------------------------------------------------------
' Create textboxes and buttons for GT
Dim i As Integer
Dim topPosGT As Integer
topPosGT = 30 ' Initial vertical position of controls
For i = 1 To GTcount
Dim tbGT As MSForms.TextBox
Set tbGT = uf3.Controls.Add("Forms.TextBox.1")
tbGT.Name = "GTfile" & i
tbGT.Top = topPosGT
tbGT.Left = 25
tbGT.Width = 100
Dim btnGT As MSForms.CommandButton
Set btnGT = uf3.Controls.Add("Forms.CommandButton.1")
btnGT.Caption = "Load GT Source " & i
btnGT.Name = "GTbutton" & i
btnGT.Top = topPosGT + 20
btnGT.Left = 25
btnGT.Width = 100
' Create an event handler for the button
Dim btnGTHandler As clsButtonHandler2
Set btnGTHandler = New clsButtonHandler2
Set btnGTHandler.btn = btnGT
btnGTHandler.SetTextBox tbGT
' Add the handler to the collection to keep it alive
ButtonHandlers2.Add btnGTHandler
topPosGT = topPosGT + 50
Next i
'-------------Repeat the process for ST, Gen, and HRSG-------------
' Create textboxes and buttons for ST
Dim j As Integer
Dim topPosST As Integer
topPosST = 30
For j = 1 To STcount
Dim tbST As MSForms.TextBox
Set tbST = uf3.Controls.Add("Forms.TextBox.1")
tbST.Name = "STfile" & j
tbST.Top = topPosST
tbST.Left = 175
tbST.Width = 100
Dim btnST As MSForms.CommandButton
Set btnST = uf3.Controls.Add("Forms.CommandButton.1")
btnST.Caption = "Load ST Source " & j
btnST.Name = "STbutton" & j
btnST.Top = topPosST + 20
btnST.Left = 175
btnST.Width = 100
' Create an event handler for the button
Dim btnSTHandler As clsButtonHandler2
Set btnSTHandler = New clsButtonHandler2
Set btnSTHandler.btn = btnST
btnSTHandler.SetTextBox tbST
' Add the handler to the collection to keep it alive
ButtonHandlers2.Add btnSTHandler
topPosST = topPosST + 50
Next j
'----------------------------------------------------------
' Create textboxes and buttons for Gen
Dim k As Integer
Dim topPosGen As Integer
topPosGen = 30
For k = 1 To Gencount
Dim tbGen As MSForms.TextBox
Set tbGen = uf3.Controls.Add("Forms.TextBox.1")
tbGen.Name = "Genfile" & k
tbGen.Top = topPosGen
tbGen.Left = 325
tbGen.Width = 100
Dim btnGen As MSForms.CommandButton
Set btnGen = uf3.Controls.Add("Forms.CommandButton.1")
btnGen.Caption = "Load Gen Source " & k
btnGen.Name = "Genbutton" & k
btnGen.Top = topPosGen + 20
btnGen.Left = 325
btnGen.Width = 100
' Create an event handler for the button
Dim btnGenHandler As clsButtonHandler2
Set btnGenHandler = New clsButtonHandler2
Set btnGenHandler.btn = btnGen
btnGenHandler.SetTextBox tbGen
' Add the handler to the collection to keep it alive
ButtonHandlers2.Add btnGenHandler
topPosGen = topPosGen + 50
Next k
'----------------------------------------------------------
' Create textboxes and buttons for HRSG
Dim l As Integer
Dim topPosHRSG As Integer
topPosHRSG = 30
For l = 1 To HRSGcount
Dim tbHRSG As MSForms.TextBox
Set tbHRSG = uf3.Controls.Add("Forms.TextBox.1")
tbHRSG.Name = "HRSGfile" & l
tbHRSG.Top = topPosHRSG
tbHRSG.Left = 475
tbHRSG.Width = 100
Dim btnHRSG As MSForms.CommandButton
Set btnHRSG = uf3.Controls.Add("Forms.CommandButton.1")
btnHRSG.Caption = "Load HRSG Source " & l
btnHRSG.Name = "HRSGbutton" & l
btnHRSG.Top = topPosHRSG + 20
btnHRSG.Left = 475
btnHRSG.Width = 100
' Create an event handler for the button
Dim btnHRSGHandler As clsButtonHandler2
Set btnHRSGHandler = New clsButtonHandler2
Set btnHRSGHandler.btn = btnHRSG
btnHRSGHandler.SetTextBox tbHRSG
' Add the handler to the collection to keep it alive
ButtonHandlers2.Add btnHRSGHandler
topPosHRSG = topPosHRSG + 50
Next l
'--------------------------------------------------------------------------------------------------
' Calculate the height needed for UserForm3
Dim maxHeight As Integer
maxHeight = Application.WorksheetFunction.Max(topPosGT, topPosST, topPosGen, topPosHRSG) + 50
' Adjust the size of UserForm3
uf3.Width = 600
uf3.Height = maxHeight
' Add the UF3Btn button
Dim btnUF3 As MSForms.CommandButton
Set btnUF3 = uf3.Controls.Add("Forms.CommandButton.1")
btnUF3.Caption = "Go To Work"
btnUF3.Name = "UF3Btn"
btnUF3.Top = maxHeight - 50
btnUF3.Left = 25
btnUF3.Width = 550
btnUF3.Height = 20
' Create an event handler for the button
Dim btnUF3Handler As clsButtonHandler
Set btnUF3Handler = New clsButtonHandler
Set btnUF3Handler.btn = btnUF3
' Add the handler to the collection to keep it alive
ButtonHandlers.Add btnUF3Handler
' Show UserForm3 and hide UserForm2
Unload Me
uf3.Show
End SubVoici le code dans mon class module 2 :
' Dans la classe clsButtonHandler2
Public WithEvents btn As MSForms.CommandButton
Public associatedTextBox As MSForms.TextBox
' Setter pour associer une TextBox
Public Sub SetTextBox(tb As MSForms.TextBox)
Set associatedTextBox = tb
End Sub
Private Sub btn_Click()
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Title = "Select a file"
.AllowMultiSelect = False
.Filters.Clear
.Filters.Add "All Files", "*.*"
If .Show = -1 Then
' File selected, update the associated TextBox
associatedTextBox.Text = .SelectedItems(1)
End If
End With
End SubJe vous remercie de votre aide, et si des informations supplémentaire sont nécessaire dite le moi.
Bonne Journée
Bonjour stepniak,
Sans fichier pour tester ...
on click sur le bouton mais ceci fonctionne seulement pour le dernier bouton de chaque catégorie.
C'est normal actuellement, car une bouche "For" recommence le traitement pour tous les boutons de la section.
Au lieu du "For", teste i = x , x représentant le numéro du bouton de cette section. C'est pareil pour j et k.
Le tout suivi de l'action à faire.
Bizz
Merci beaucoup pour ton retour. Cependant le problème est toujours présent.
Trouvez en pièce jointe fichier excel afin de tester.
Bonjour,
Le fichier joint n'aide en rien car sans vos documents liés on ne peut atteindre l'UF en question...
Vous devriez ajouter l'initialisation de vos collections dans le sub Userform_Initialize(), activé automatiquement lors de la création de l'instance. Ca éviterai vos "tests if needed".
Ensuite je pense que vous avez un(/ de nombreux ?) problèmes de scopes/portée de vos variables. Si les collections/leurs boutons se trouvent dans l'UF3, que font-elles dans l'UF2 ?
Si vous souhaitez approcher les userforms d'une manière orientée objet (ce que je salue), vous devriez vraiment revoir votre code :
Les UF sont des interfaces, définir vos objets représentant vos données à l'intérieur meme de leurs définitions/fonctions est vraiment une mauvaise idée : si un UF est fermé/mis a jour ou autre vos datas disparaissent de manière mystérieuse... comme c'est le cas pour vos listes de boutons en l'occurence.
Typiquement tout le processus de construction de UF3 devrait se trouver dans le module de UF3 / une procédure, au lieu de BtnUF2_Click.
La démarche a suivre, robuste, consiste à définir d'un coté :
- votre Modèle avec ses données et opérations
- de l'autre votre interface faisant appel auxdites opérations. Aucun lien direct avec les données.
Cela demande une certaine abstraction et du recul, pas facile quand on débute...
Essayez donc de modifier l'emplacement de définition de vos listes de boutons et je pense que vous pouvez résoudre votre problème.
Enfin de manière générale, avec l'utilisation de classes votre code devrait etre structuré ainsi :
Modules de classes : objets et opérations les concernant
Modules UFs : interface utilisateur pour la manipulation de ces classes, via les opérations prédéfinies dans vos classes
Modules classiques : Structure du programme, par exemple :
Sub clickInitial()
Dim obj As myClass
Set obj = New myClass
Dim interface1 As UserForm1
SetAttr interface1 = New UserForm1
interface1.Show
' appel de doSecondStep via les clics dans l'interface
End Sub
Sub doSecondStep(myDatas As myClass)
myDatas.doOperation
End SubSans un fichier plus fonctionnel, difficile de vous aider davantage.
Classe UserForm2 :
Public Sub BtnUF2_Click()
Dim uf3 As UserForm3
Set uf3 = New UserForm3
' Show UserForm3 and hide UserForm2
uf3.DefineInterface Val(Me.GTinput.Value), Val(Me.STinput.Value), Val(Me.Geninput.Value), Val(Me.HRSGinput.Value)
Unload Me
uf3.Show
End SubClasse UserForm3 :
' Déclarez la collection globalement pour gérer les instances des handlers de boutons
Private ButtonHandlers As Collection
Private ButtonHandlers2 As Collection
Private Sub InitializeButtonHandlers()
Set ButtonHandlers = New Collection
End Sub
Private Sub InitializeButtonHandlers2()
Set ButtonHandlers2 = New Collection
End Sub
Sub UF3Btn_Click()
Unload UserForm3
End Sub
Private Sub UserForm_Initialize()
Me.Caption = "UserForm3"
InitializeButtonHandlers
InitializeButtonHandlers2
End Sub
Public Sub DefineInterface(GTcount As Long, STcount As Long, Gencount As Long, HRSGcount As Long)
'------------ 1/4 Create textboxes and buttons for GT ------------
Dim i As Long
Dim topPosGT As Long
topPosGT = 30 ' Initiai verticai position of controls
For i = 1 To GTcount
Dim tbGT As MSForms.TextBox
Set tbGT = Me.Controls.Add("Forms.TextBox.1")
tbGT.Name = "GTfile" & i
tbGT.Top = topPosGT
tbGT.Left = 25
tbGT.Width = 100
Dim btnGT As MSForms.CommandButton
Set btnGT = Me.Controls.Add("Forms.CommandButton.1")
btnGT.Caption = "Load GT Source " & i
btnGT.Name = "GTbutton" & i
btnGT.Top = topPosGT + 20
btnGT.Left = 25
btnGT.Width = 100
' Create an event handler for the button
Dim btnGTHandler As clsButtonHandler2
Set btnGTHandler = New clsButtonHandler2
Set btnGTHandler.btn = btnGT
btnGTHandler.SetTextBox tbGT
' Add the handler to the collection to ieep it alive
ButtonHandlers2.Add btnGTHandler
topPosGT = topPosGT + 50
Next i
'-------------2/4 Repeat the process for ST-------------
Dim topPosST As Long
topPosST = 30
For i = 1 To STcount
Dim tbST As MSForms.TextBox
Set tbST = Me.Controls.Add("Forms.TextBox.1")
tbST.Name = "STfile" & i
tbST.Top = topPosST
tbST.Left = 175
tbST.Width = 100
Dim btnST As MSForms.CommandButton
Set btnST = Me.Controls.Add("Forms.CommandButton.1")
btnST.Caption = "Load ST Source " & i
btnST.Name = "STbutton" & i
btnST.Top = topPosST + 20
btnST.Left = 175
btnST.Width = 100
' Create an event handler for the button
Dim btnSTHandler As clsButtonHandler2
Set btnSTHandler = New clsButtonHandler2
Set btnSTHandler.btn = btnST
btnSTHandler.SetTextBox tbST
' Add the handler to the collection to ieep it alive
ButtonHandlers2.Add btnSTHandler
topPosST = topPosST + 50
Next i
' ------------ 3/4 Create textboxes and buttons for Gen ------------
Dim topPosGen As Long
topPosGen = 30
For i = 1 To Gencount
Dim tbGen As MSForms.TextBox
Set tbGen = Me.Controls.Add("Forms.TextBox.1")
tbGen.Name = "Genfile" & i
tbGen.Top = topPosGen
tbGen.Left = 325
tbGen.Width = 100
Dim btnGen As MSForms.CommandButton
Set btnGen = Me.Controls.Add("Forms.CommandButton.1")
btnGen.Caption = "Load Gen Source " & i
btnGen.Name = "Genbutton" & i
btnGen.Top = topPosGen + 20
btnGen.Left = 325
btnGen.Width = 100
' Create an event handler for the button
Dim btnGenHandler As clsButtonHandler2
Set btnGenHandler = New clsButtonHandler2
Set btnGenHandler.btn = btnGen
btnGenHandler.SetTextBox tbGen
' Add the handler to the collection to ieep it alive
ButtonHandlers2.Add btnGenHandler
topPosGen = topPosGen + 50
Next i
'----------------------------------------------------------
' Create textboxes and buttons for HRSG
Dim topPosHRSG As Long
topPosHRSG = 30
For i = 1 To HRSGcount
Dim tbHRSG As MSForms.TextBox
Set tbHRSG = Me.Controls.Add("Forms.TextBox.1")
tbHRSG.Name = "HRSGfile" & i
tbHRSG.Top = topPosHRSG
tbHRSG.Left = 475
tbHRSG.Width = 100
Dim btnHRSG As MSForms.CommandButton
Set btnHRSG = Me.Controls.Add("Forms.CommandButton.1")
btnHRSG.Caption = "Load HRSG Source " & i
btnHRSG.Name = "HRSGbutton" & i
btnHRSG.Top = topPosHRSG + 20
btnHRSG.Left = 475
btnHRSG.Width = 100
' Create an event handler for the button
Dim btnHRSGHandler As clsButtonHandler2
Set btnHRSGHandler = New clsButtonHandler2
Set btnHRSGHandler.btn = btnHRSG
btnHRSGHandler.SetTextBox tbHRSG
' Add the handler to the collection to ieep it alive
ButtonHandlers2.Add btnHRSGHandler
topPosHRSG = topPosHRSG + 50
Next i
'--------------------------------------------------------------------------------------------------
' Calculate the height needed for UserForm3
Dim maxHeight As Long
maxHeight = Application.WorksheetFunction.Max(topPosGT, topPosST, topPosGen, topPosHRSG) + 50
' Adiust the size of UserForm3
Me.Width = 600
Me.Height = maxHeight
' Add the UF3Btn button
Dim btnUF3 As MSForms.CommandButton
Set btnUF3 = Me.Controls.Add("Forms.CommandButton.1")
btnUF3.Caption = "Go To Work"
btnUF3.Name = "UF3Btn"
btnUF3.Top = maxHeight - 50
btnUF3.Left = 25
btnUF3.Width = 550
btnUF3.Height = 20
' Create an event handler for the button
Dim btnUF3Handler As clsButtonHandler
Set btnUF3Handler = New clsButtonHandler
Set btnUF3Handler.btn = btnUF3
' Add the handler to the collection to ieep it alive
ButtonHandlers.Add btnUF3Handler
End SubMerci beaucoup pour tous vos retour et commentaire, et merci pour la résolution de mon problème !
Bonne journée à vous !