Bonjour,Bonjour @CC76
Pour résumer le principe: Il est tout à fait possible de rendre opérationnels des CommandButton créés dynamiquement dans un UserForm chargé, mais seulement par du code qui a déjà été prévu pour cela, et dont la résidence normale est un module de classe. Je pourrais vous indiquer la meilleure façon de l'écrire si vous m'en disiez davantage sur ce que vous voudriez. Dans l'UserForm, vous auriez une procédure unique pour tous les CommandButton créés dynamiquement, qui s'exécuterait quand on clique sur l'un d'eux. À vous de me dire quel(s) argument(s) vous aimeriez qu'elle transmette pour vous permettre de savoir ce qu'il y a lieu d'y exécuter, selon celui qui aura été actionné.
Le mieux ce serait même de joindre un fichier montrant d'avantage le contexte.
de 100 boutons, j'étais un peu inquiet pour les performances du fait de la création d'une centaine d'instances de la forme initiale.
public function quoi()
quoi="chocolat"
end function
sub test()
msgbox "j'aime le " & UserForm1.quoi
end sub
Un module de classe sert à définir un type d'objet personnalisé, avec ses propriétés, méthodes et évènements. Les exemplaires qui en sont ensuite créés à l'aide du mot clé New ne contiennent que des données. On dit parfois ainsi que les données sont propre à l'exemplaire tandis que les méthodes sont propre au type. Pour les propriétés, leurs noms sont propres au type mais leurs valeurs sont propres à l'exemplaire. Mais toutes les données sauf les variables Static sont propres à l'exemplaire, y compris le contenu des variables Private du module de classe.Je n'ai jamais utilisé de module de classe, et je ne sais pas à quoi cela sert, mais je ne demande pas mieux que d'apprendre
dis comme ça c'est faux car c'est mal interprétéLa solution de @patricktoulon revient bien à créer autant d'exemplaire de l'UserForm, avec leurs propres collections Controls, et autres sans doute, qu'il y a de CommandButton à traiter dans celui affiché. Seule la programmation du module de l'UserForm reste commune à tous ces exemplaires.
car les object mappés dans la classes sont mappés avec "set" qui instancie un object , de la même manière que je le fait dans le userform OU!! que l'userform le fait en interne lorsque les objects sont ajoutés mano mano dans VBELa solution de @Dranreb revient bien à créer autant d'exemplaire du module classe, avec leurs propres collections Controls, et autres sans doute, qu'il y a de CommandButton à traiter dans celui affiché. Seule la programmation du module de la classe reste commune à tous ces exemplaires.
Sub test()
Dim forme, I&, B
With UserForm1
For I = 1 To 3
Set B = .Controls.Add("Forms.CommandButton.1")
B.Name = "bouton" & I
B.Caption = B.Name
B.Top = (20 * (I - 1)) + (10 * I)
Next
.Show 0
End With
End Sub
Dim cls() As New UserForm2
Private Sub UserForm_Activate()
For Each ctrl In Me.Controls
If ctrl.Name Like "bouton*" Then I = I + 1
ReDim Preserve cls(1 To I): Set cls(I).bouton = ctrl
MsgBox "prise en charge du bouton""" & ctrl.Name & """"
Next
End Sub
Public WithEvents bouton As MSForms.CommandButton
Private Sub bouton_Click()
MsgBox "vous avez cliqué sur le bouton """ & bouton.Name & """"
End Sub
Merci pour cette proposition, mais je ne connais pas les modules de classe, je ne m'en suis jamais servi. Mais je ne demande pas mieux que d'apprendre... Ce dont j'ai besoin est très simple : Je veux créer dynamiquement une centaine d'objets clickables sur une forme (des objets pouvant héberger une image, donc plutôt des contrôles "image" ou "label"). Et quand l'utilisateur clique dessus, je veux pouvoir récupérer le nom de l'objet.Bonjour @CC76
Pour résumer le principe: Il est tout à fait possible de rendre opérationnels des CommandButton créés dynamiquement dans un UserForm chargé, mais seulement par du code qui a déjà été prévu pour cela, et dont la résidence normale est un module de classe. Je pourrais vous indiquer la meilleure façon de l'écrire si vous m'en disiez davantage sur ce que vous voudriez. Dans l'UserForm, vous auriez une procédure unique pour tous les CommandButton créés dynamiquement, qui s'exécuterait quand on clique sur l'un d'eux. À vous de me dire quel(s) argument(s) vous aimeriez qu'elle transmette pour vous permettre de savoir ce qu'il y a lieu d'y exécuter, selon celui qui aura été actionné.
Le mieux ce serait même de joindre un fichier montrant d'avantage le contexte.
Option Explicit
Implements CAsso
Private Parent As ControlsAssociés, WithEvents Img As MSForms.Image, Index As Long, _
Colonne As Long, Dossier As String, UsMode, RéfFic As String, Conteneur As Object
Private Sub CAsso_Init(ByVal Lui As ControlsAssociés, ByVal Ctl As MSForms.IControl, ByVal Idx As Long, _
ByVal Col As Long, ByVal Fmt As String, ByVal Mode As Variant)
Dim ImOBn As MSForms.OptionButton, CAssoOBn As CAssoOBn
Set Parent = Lui: Set Img = Ctl: Index = Idx: Colonne = Col: UsMode = Mode
Dossier = Fmt
Set Conteneur = Ctl.Parent
End Sub
Private Function CAsso_Ctl() As MSForms.IControl
Set CAsso_Ctl = Img
End Function
Private Function CAsso_Index() As Long
CAsso_Index = Index
End Function
Private Function CAsso_Col() As Long
CAsso_Col = Colonne
End Function
Private Function CAsso_Format() As String
CAsso_Format = Dossier
End Function
Private Function CAsso_Mode() As Variant
CAsso_Mode = UsMode
End Function
Private Property Let CAsso_Valeur(ByVal RHS As Variant)
On Error Resume Next
If Dossier <> "" And RHS <> "" Then
Img.Picture = LoadPicture(Dossier & "\" & RHS)
Else
Img.Picture = LoadPicture(RHS)
End If
If Err = 0 Then RéfFic = RHS Else MsgBox RHS & vbLf & Err.Description, vbExclamation, "Image"
Conteneur.Repaint
End Property
Private Property Get CAsso_Valeur() As Variant
CAsso_Valeur = RéfFic
End Property
Private Sub Img_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Dim GOFn
If Button = 1 Then
If Dossier <> "" Then ChDrive Dossier: ChDir Dossier
GOFn = Application.GetOpenFilename("Image,*.jpg;*.gif;*.bmp")
If VarType(GOFn) <> vbString Then Exit Sub
If Dossier <> "" Then If Left$(GOFn, Len(Dossier) + 1) <> Dossier & "\" Then MsgBox _
"Image non rattachée au dossier :" & vbLf & Dossier, vbCritical, "Image" _
Else CAsso_Valeur = Mid$(GOFn, Len(Dossier) + 2) Else CAsso_Valeur = GOFn
ElseIf Button = 2 Then
If CAsso_Valeur = "" Then Exit Sub
If MsgBox("Voulez-vous effacer cette image ?", vbYesNo, "Clic droit") = vbNo Then Exit Sub
CAsso_Valeur = ""
End If
Parent.CAM_Change Me
End Sub
Public Sub Add(ByVal Ctl As MSForms.Control, Optional ByVal Colonne As Variant = -1, _
Optional ByVal Format As String = "", Optional ByVal Mode = Empty)
' — Arguments :
' Ctl : Le contrôle à ajouter.
' Colonne : La colonne dans le tableau.
' Format : Le format de conversion de la valeur en le texte affiché dans le contrôle.
' Mode : Ce que vous aimeriez retrouver en CAM.Mode pour orienter un traitement d'évènement.
Dim I As Long
CorrigerColonne Colonne, "Add Me." & Ctl.Name
I = Me.Count + 1: ReDim Preserve TCAssos(1 To I) As CAsso
Select Case True
Case TypeOf Ctl Is MSForms.TextBox: Set TCAssos(I) = New CAssoTBx
Case TypeOf Ctl Is MSForms.ComboBox: Set TCAssos(I) = New CAssoCBx
Case TypeOf Ctl Is MSForms.OptionButton: MsgBox "Contrôle de type ""OptionButton"" non supporté," _
& vbLf & "mais un ""Frame"" en contenenant serait accepté.", _
vbCritical, "ControlsAssociés Add Me." & Ctl.Name: End
Case TypeOf Ctl Is MSForms.CheckBox: Set TCAssos(I) = New CassoCkx
Case TypeOf Ctl Is MSForms.Frame: Set TCAssos(I) = New CAssoFrm
Case TypeOf Ctl Is MSForms.Image: Set TCAssos(I) = New CAssoImg
Case Else: MsgBox "Contrôle de type """ & TypeName(Ctl) & """ non supporté actuellement", _
vbCritical, "ControlsAssociés Add Me." & Ctl.Name: End: End Select
TCAssos(I).Init Me, Ctl, I, Colonne, Format, Mode
End Sub
Merci,
J'ai fini, avec quelques difficultés je l'avoue, de comprendre votre code, et j'ai pas mal de questions. Trop pour les poser à cet endroit, d'autant plus qu'on s'éloigne de la question initiale. Comment puis-je vous les communiquer ?
Merci encore
Ok, voir l'onglet Questions du fichier ci-jointNon, ça ne peut pas être trop, parce qu'il n'y a pas tant de choses à savoir sur le principe des objets VBA
Posez vos question ici, l'une après l'autre.