XL 2010 Création dynamique de Controles et du code event associé

CC76

XLDnaute Nouveau
Bonjour
J'essaie de créer dynamiquement sur une forme un bouton (ça, ça marche), et le code de l'événement Click associé, et ça ça ne marche pas.
J'ai une erreur sur l'utilisation de CreateEventProc. ( 'Erreur d'exécution '57017' Gestionnaire d'événements non valide).
Quelqu'un peut-il m'expliquer pourquoi ça ne marche pas
Grand merci d'avance

Voilà le code complet de la proc:
Public Sub AjouteCtrl()
Dim CtrlName As String, MyCode As String, CodeMacro As String, TextLoc As Long
'Tentative de créer un bouton TestButton sur la form "FormJeu" et de
'créer la Sub TestButton_Click
CtrlName = "TestButton"
CodeMacro = " msgbox coucou"
'Création du bouton - OK, ça marche
With FormJeu
.Controls.Add "Forms.CommandButton.1", CtrlName
With .Controls(CtrlName)
.Caption = CtrlName
.Visible = True
.Locked = False
End With
End With
'Création de la sub associée à l'événement Click - ça ne marche pas -
With Application.VBE.ActiveVBProject.VBComponents("FormJeu").CodeModule
TextLoc = .CreateEventProc("Click", CtrlName) 'Erreur d'exécution '57017' Gestionnaire d'événements non valide
.InsertLines TextLoc + 1, CodeMacro
End With
'Alors que le code suivant fonctionne (presque)
MyCode = "Private Sub TestButton_Click()" & vbCrLf & CodeMacro & vbCrLf & "End Sub"

With Application.VBE.ActiveVBProject.VBComponents("FormJeu")
.CodeModule.AddFromString MyCode 'ça, ça marche - La proc est ajoutée, mais le bouton ne réagit pas quand on click dessus
End With
FormJeu.Show
End Sub
 
Solution
La collection Cln sert à conserver en mémoire les exemplaires de SupportImage créés.
Une Public Sub dans un module de classe, ça s'appelle une méthode, pour qu'on se souvienne qu'elle ne peut être invoquée sans être qualifiée de l'objet qui la possède.
La méthode Init, donc, sert simplement à initialiser les objets propre à l'exemplaire, l'objet parent pour pouvoir invoquer celle de ses méthodes qui prendra en charge le clic, et l'image supportée.
Avoir renommé MaFormeVirtuelle le SupportsImages, je veux bien, mais ça ne désigne plus du tout ce que ça représente, à savoir une collection d'éléments SupportImage.
Et MéthodeRéservéeÀSupportImage avait le mérite d'indiquer qu'elle ne devait pas être employée par le programmeur d'application...

sylvanu

XLDnaute Barbatruc
Supporter XLD
Bonjour CC,
J'ai testé ça et ça marche :
VB:
Sub Macro1()
    ActiveSheet.Shapes("Ellipse 1").OnAction = "essai"
    [A1].Select
End Sub
On affecte la macro "essai" à la forme Ellipse1.
Si vous avez le nom de votre dessin et le nom de la macro qui doit être appelé alors cela ferait du genre :
Code:
Sub Macro1()
    MonDessin = "Ellipse 1"
    Macro = "test"
    
    ActiveSheet.Shapes(MonDessin).OnAction = MaMacro
    [A1].Select
End Sub
 

patricktoulon

XLDnaute Barbatruc
bonjour
pour un control dans une userform mieux vaut classer
l’accès au vbcomponents tout le monde ne l'accepte pas d’emblée
le code classe et event est deja dans le userform ou dans un module classe et c'est tout

a quel moment tu ajoute ton bouton parce c'est plus que confu ton code
quand l'userform est affiché ou non?
 

CC76

XLDnaute Nouveau
Merci, mais cela ne répond pas à mon problème. Je veux que le contrôle soit sur une forme, pas dans une feuille excel (ça je l'ai déjà fait, et ça marche). Pour les contrôles de forme, il n'y a pas de propriété "onaction"
Merci quand même
bonjour
pour un control dans une userform mieux vaut classer
l’accès au vbcomponents tout le monde ne l'accepte pas d’emblée
le code classe et event est deja dans le userform ou dans un module classe et c'est tout

a quel moment tu ajoute ton bouton parce c'est plus que confu ton code
quand l'userform est affiché ou non?
J'ai simplifié mon code pour qu'il soit moins "confus:" La Forme s'appelle FormJeu.
CtrlName = "TestButton": CodeMacro = " msgbox coucou"
'1ère étape - Création du bouton
FormJeu.Controls.Add "Forms.CommandButton.1", CtrlName
'2ème étape : Création de la sub TestButton_Click
With Application.VBE.ActiveVBProject.VBComponents("FormJeu").CodeModule
TextLoc = .CreateEventProc("Click", CtrlName)
.InsertLines TextLoc + 1, CodeMacro
End With
'3 ème étape : affichage de la forme
FormJeu.Show

Je ne peux pas faire plus simple.
Quant à ton commentaire du début, peux tu expliquer ? Pour moi, "Classer l'accès au VB components", c'est incompréhensible.
Merci d'avance
 

CC76

XLDnaute Nouveau
si c'est a partir du userform que tu tente d'avoir acces au module et au code de l'userform t'es marron on ne peut pas le modifier le code module , quand il est affiché
je t'ai demandé a partir d'ou tu ajoute ce bouton ?????,
J'ajoute le bouton avec le code suivant:
FormJeu.Controls.Add "Forms.CommandButton.1", CtrlName
ce code est inclus dans la sub AjouteCtrl () que j'ai décrite in extenso dans mon premier post.
Cette sub est appelée depuis un programme VB, pas depuis une forme.
 

patricktoulon

XLDnaute Barbatruc
alors
ecoute bien
tu va ouvrir un classeur vierge
tu va lui mettre un userform et un module
le userform tu va l'appeler "FormJeu"

dans le code du module tu va coller ceci:
VB:
Sub test()
    Dim forme, I&, B
    With FormJeu
        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

maintenant dans le userform vierge tu colle ce code
VB:
Public WithEvents bouton As MSForms.CommandButton
Dim cls()  As New FormJeu

Private Sub bouton_Click()
MsgBox "vous avez cliqué sur le bouton """ & bouton.Name & """"
End Sub

Private Sub UserForm_Activate()
For Each ctrl In Me.Controls
MsgBox "prise en charge du bouton""" & ctrl.Name & """"
If ctrl.Name Like "bouton*" Then I = I + 1: ReDim Preserve cls(1 To I): Set cls(I).bouton = ctrl
Next
End Sub

voila maintenant si tu lance la sub test du module ton userform devrait avoir 3 boutons cliquable
plus couramment on utilise les module classe pour faire ça par ce que beaucoup ignore que les module userform sont des module classe aussi
fait ce que je te dis ,teste ,et demande ce que tu ne comprends pas
;)
 

Dranreb

XLDnaute Barbatruc
Bonsoir.
Si vous avez besoin d'un grand nombre de CommandButton comme pour les jours d'un calendrier ou une palette de couleurs, vous auriez intérêt à leur définir une classe support qui prendra en charge le clic de chacun.
Sinon ça ne se justifie pas de les créer dynamiquement. Il vaut mieux en définir suffisamment, non visibles, qu'on changera selon les cisconstances et qui auront leurs procédures fixes de prise en charge du click.
De toute façon, contrairement aux contrôles que vous pouvez y ajouter aussi, temporairement, lors de l'exécution, vous ne pouvez pas créer de code dans un UserForm chargé, car c'est seulement un exemplaire, ne contenant que des données, fut-ce des descriptions de contrôles, attachées à une programmation qui doit avoir été compilée pour cela, et qu'on ne peut plus changer. Vous pouvez seulement ajouter du code dans son VBComponent, et dans ce cas ce serait aussi dans celui ci que les contrôles devraient être créés. En dur, en somme, depuis un projet VBA externe, en dehors de toute compilation et exécution du projet cible.
 
Dernière édition:

Dranreb

XLDnaute Barbatruc
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.
 

CC76

XLDnaute Nouveau
alors
ecoute bien
tu va ouvrir un classeur vierge
tu va lui mettre un userform et un module
le userform tu va l'appeler "FormJeu"

dans le code du module tu va coller ceci:
VB:
Sub test()
    Dim forme, I&, B
    With FormJeu
        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

maintenant dans le userform vierge tu colle ce code
VB:
Public WithEvents bouton As MSForms.CommandButton
Dim cls()  As New FormJeu

Private Sub bouton_Click()
MsgBox "vous avez cliqué sur le bouton """ & bouton.Name & """"
End Sub

Private Sub UserForm_Activate()
For Each ctrl In Me.Controls
MsgBox "prise en charge du bouton""" & ctrl.Name & """"
If ctrl.Name Like "bouton*" Then I = I + 1: ReDim Preserve cls(1 To I): Set cls(I).bouton = ctrl
Next
End Sub

voila maintenant si tu lance la sub test du module ton userform devrait avoir 3 boutons cliquable
plus couramment on utilise les module classe pour faire ça par ce que beaucoup ignore que les module userform sont des module classe aussi
fait ce que je te dis ,teste ,et demande ce que tu ne comprends pas
;)
ça marche parfaitement, et ça correspond exactement à ce que je veux faire. Mais comme j'ai besoin de plus 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. Mais j'ai essayé avec 100 boutons, et ça se passe bien.
Donc, merci beaucoup.
En revanche, je ne sais toujours pas pourquoi le "CreateEventProc("Click", CtrlName)" que je voulais utiliser initialement ne fonctionne pas, et me retourne cette erreur "Erreur d'exécution '57017' Gestionnaire d'événements non valide"
Mais bon, maintenant, je n'en ai plus besoin, c'est juste pour essayer de comprendre.
Merci encore
 

Discussions similaires

F
Réponses
7
Affichages
3 K
E

Statistiques des forums

Discussions
311 720
Messages
2 081 912
Membres
101 837
dernier inscrit
Ugo