Générer du code pour des boutons eux même générés dans un UserForm
Bonjour,
Comme expliqué dans mon titre, j'aimerais générer du code pour des boutons eux même générés dans un UserForm.
Donc j'ai un UserForm qui s'initialise qui génère des choses (peu importe quoi) y compris des Label qui reprenne le nom d'une feuille du classeur. A côté, j'ai un bouton "Go" qui permet de sélectionner cette feuille.
Mon UserForm doit s'adapter aux nombre de feuilles qu'il y a dans mon classeur.
J'ai donc un code qui ressemble à ça :
Private Sub UserForm_Initialize()
Dim ws As Worksheet
Dim obj As Object
Dim n As Integer
Dim Code As String
n = 0
Me.Height = 30
Me.Width = 230
For Each ws In Application.Workbooks("Classeur1").Worksheets
n = n + 1
Me.Height = Me.Height + 30
Set obj = Me.Controls.Add("Forms.Label.1", "Label1", True)
With obj
.Name = "Label" & n
.Caption = ws.Name
.Top = Me.Height - 49
.Left = 18
.Height = 12
.Width = 162
End With
Set obj = Me.Controls.Add("Forms.CommandButton.1", "CommandButton1", True)
With obj
.Name = "CommandButton" & n
.Caption = "Go"
.Top = Me.Height - 54
.Left = 186
.Height = 20
.Width = 20
End With
Next ws
End Sub
Ensuite pour chaque CommandButton(n) je voudrais qu'un code similaire à ça :
Private Sub CommandButton1_Click()
On Error Resume Next
Sheets(Me.Controls("Label" & n).Value).Select
End Sub
J'ai quand même fait des recherches (y compris pour construire ce code) et j'ai cru comprendre qu'il est recommandé d'utiliser un module de classe.
Sauf que... J'ai du mal à comprendre le fonctionnement : soit les exemples que je trouve sont trop faciles et je n'arrive pas à l'adapter pour moi, soit c'est juste trop compliqué et je ne comprend pas !
Je n'ai encore jamais utilisé les modules de classes
Merci d'avance pour votre aide.
Bonjour,
Je ne m'y connais pas très bien en module de classe, j'ai donc fait du bricolage à partir d'un post d'un autre membre sur un sujet où il avait utilisé un module de classe, voici ce que je te propose:
Le sujet dont je parle:
https://forum.excel-pratique.com/viewtopic.php?f=2&t=120672
Voir le post de ThauThème
Bonjour à tous,
Ok, facile :
Tu commences par créer un module de classe "Classe1" par exemple.
Le code de ce module sera du genre :
Public WithEvents Bt As Msforms.CommandButton
Private Sub Bt_Click()
Dim n As Integer
n = Mid(Bt.Name, 14)
On Error Resume Next
Sheets(UserForm1.Controls("Label" & n).Caption).Select
End Sub
(/!\ un label n'a pas de Value, mais un Caption)
Ensuite dans un module quelconque, on déclare une collection :
Public Coll_Usf As Object
Puis dans le code de l'userform, on déclare une classe objet
Private Sub UserForm_Initialize()
Dim Usf_Class As Object
Et chaque fois qu'un bouton est crée on l'ajoute à la classe :
Set obj = Me.Controls.Add("Forms.CommandButton.1", "CommandButton1", True)
With obj
.Name = "CommandButton" & n
.Caption = "Go"
.Top = Me.Height - 54
.Left = 186
.Height = 20
.Width = 20
End With
Set Usf_Class = New Classe1
Set Usf_Class.Bt = Me.Controls("CommandButton" & n)
Coll_Usf.Add Usf_Class
C'est tout!
Pierre
Merci Ausecour, i20100 et Pierre !
Déjà mon premier problème qui est celui du titre est résolut ! J'ai regardé vos fichiers et effectivement ça n'a pas l'air trop compliqué.
Superbe les explications Pierre
(Bien vu pour le label.value, je n'avais pas fait attention
Mais je n'ai pas encore tout compris (j'suis du genre à bloquer sur tout dès que je ne comprend pas un détail
- Qu'est-ce qu'une collection ? (à quoi ça sert pour le programme)
- Qu'est-ce qu'une classe objet ? (à quoi ça sert pour le programme)
- Si j'ai bien compris, l'ajout du bouton à la classe lui fait utiliser le programme Bt_Click() ? Par contre j'ai du mal à voir comment VBA fait le lien entre le bouton et le programme que le bouton exécute.
- C'est quoi le "Mid(Bt.Name, 14)" dans ta première partie ?
Edit → J'ai compris, c'est pour extraire la valeur de n en prenant le numéro du nom du CommandButtonX (le dernier caractère est le 14 ième qui est dans mon exemple le X.).
Une collection sert à collectionner (!) les boutons dans une classe.
Tiens d'ailleurs, dans le code donné précédemment j'ai oublié d'initialiser la collection au début de UserForm_Initialize()
Set Coll_Usf = New Collection
La classe (le module de ...) est un contenant d'objets divers (ici des boutons, mais on peut y mettre d'autres types de contrôle) avec du code qui sera exécuté de la même façon par tous les objets similaires de cette classe.
Ainsi la seule procédure Bt_click est déclenchée par tous les objets de type "bouton" (Bt) de la classe. Il est donc inutile de recopier n fois la même procédure. C'est du code "générique"
Mid(Bt.Name, 14) fait plus que d'extraire le 14ème caractère : si un bouton est le
CommandButton36000, ça retourne le code 36000.
- Messages
- 4'090
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonjour,
Une classe par définition regroupe des objets ayant les mêmes propriétés, les mêmes événements et les mêmes méthodes (actions).
Il existe une kyrielle de classes prédéfinies: Workbook, WorkSheet, Range, UserForm …..
Un module de classe permet de définir des propriétés, événements ou méthodes personnalisés pour un objet. Dans le cas qui nous occupe, cet objet est un CommandButton.
Après il faut associer à chaque CommandButton un élément de cette classe, cet élément étant appelé dans le jargon VBA, une instance. Chaque instance doit être stockée au niveau du code pour que ce dernier puisse y faire appel.
Ces instances qui sont des objets, sont stockées en général dans une classe VBA de type collection : Collection ou Dictionary mais il existe d'autres possibilités de stockage.
Pour être associé à l'instance, chaque bouton est stocké dans une variable de l'instance. Dans l'exemple fourni par pierrep56, il s'agit de la variable objet "Bt" définie par : Public WithEvents Bt As Msforms.CommandButton
Cela dit, il est plus logique à partir du module de classe, de ramener l'événement "Clic" au niveau du UserForm et donc de gérer le code lié à cet événement, ici : "Sheets(UserForm1.Controls("Label" & n).Caption).Select", non dans le module de classe, mais dans le code du UserForm.
Merci Ausecour, i20100 et Pierre !
Déjà mon premier problème qui est celui du titre est résolut ! J'ai regardé vos fichiers et effectivement ça n'a pas l'air trop compliqué.
Superbe les explications Pierre
(Bien vu pour le label.value, je n'avais pas fait attention
) Mais je n'ai pas encore tout compris (j'suis du genre à bloquer sur tout dès que je ne comprend pas un détail
:
- Qu'est-ce qu'une collection ? (à quoi ça sert pour le programme)
- Qu'est-ce qu'une classe objet ? (à quoi ça sert pour le programme)
- Si j'ai bien compris, l'ajout du bouton à la classe lui fait utiliser le programme Bt_Click() ? Par contre j'ai du mal à voir comment VBA fait le lien entre le bouton et le programme que le bouton exécute.
- C'est quoi le "Mid(Bt.Name, 14)" dans ta première partie ?
Edit → J'ai compris, c'est pour extraire la valeur de n en prenant le numéro du nom du CommandButtonX (le dernier caractère est le 14 ième qui est dans mon exemple le X.).
De rien
J'ai bien fait de mettre ce sujet en favori je crois, plein d'explications qui me seront utiles quand je voudrai utiliser à nouveau des modules de classe, je suis comme toi par rapport à ça, un peu paumé
Bonne lecture
Merci Pierre et thev pour vos explications détaillées !
Effectivement il manquait quelque chose dans le programme, je comprend mieux pourquoi maintenant
Le fonctionnement des modules de classes est encore flou pour moi, mais à force d'en utiliser je finirai par l'assimiler !
Encore merci, j'espère que comme l'a dit Ausecour, ce post servira à beaucoup d'autre.
Du coup je viens de comprendre comment je pouvais mettre un calendrier dans un userform grâce au module de classe!
Je le mets là, ça pourrait me servir plus tard si j'en ai besoin
Du coup je viens de comprendre comment je pouvais mettre un calendrier dans un userform grâce au module de classe!
Bonjour à tous,
Le défaut majeur du DTPicker, c'est que ce contrôle n'est pas toujours présent selon les versions et selon les config d'Office.
Alors profitons des possibilités d'un module de classe pour créer un calendrier perso avec des contrôles standards, de simples 'Label' en fait.
Voici une démo avec 2 méthodes différentes (avec ou sans module de classe) pour saisie d'une date sur un userform ou saisie sur la feuille via un calendrier "façon Windows10" (+ et - pour changer d'année, < et > pour changer de mois)
Pierre
Bonjour pierrep56
Je ne savais pas que ça poserait des problèmes de compatibilité
L'idée d'utiliser des Label me semble en effet mieux, je me poserai le défi de créer un contrôle de ce genre à l'avenir, ça me fera travailler sur les modules de classe
Sinon je n'avais pas vu, on peut simplement ajouter le DatePicker aux outils de la boite à outils en faisant clic droit dessus et en choisissant contrôles supplémentaires... Je suis passé à côté de cette option pendant tout ce temps
- Messages
- 4'090
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonjour,
ci-dessous un exemple de module de classe (nommé "CmdButton") relatif à un CommandButton.
Option Explicit
'# Instance de la clase
Public instance_button As Object
'# Formulaire appelant
Private USF As Object
'# Evénement déclenché par la classe
Public Event Click()
'# Evénements pour bouton de commande
Private WithEvents button As MSForms.CommandButton
Public Property Set Init(ByVal instance As Object, ByVal contrôle As Object)
Set instance_button = instance
Set button = contrôle
Set USF = button.Parent
End Property
Public Property Get caption() As String
caption = button.caption
End Property
Public Property Get name() As String
name = button.name
End Property
Private Sub button_Click()
'assignation de la variable "bouton" du formulaire pour activation des événements de la classe
Set USF.bouton = instance_button
'activation événement Click dans le formulaire
RaiseEvent Click
End Sub
Ce module est d'abord composé de 3 variables :
instance_button : stocke l'objet instance,
USF : stocke l'objet formulaire appelant,
button défini par "Private WithEvents button As MSForms.CommandButton" : stocke l'objet CommandButton,
Ensuite, d'un événement "Click",
défini par "Public Event Click()" pour être utilisé dans le formulaire ,
Après, de propriétés :
Init : permet d'assigner les 3 variables du module à partir du formulaire,
caption et name : reprennent les propriétés du CommandButton stocké dans la variable "button" pour être utilisées dans le formulaire.
Enfin, de la gestion de l'événement "Clic" dans le module de classe qui permet :
1- de créer l'événement "Clic" qui sera utilisé dans le formulaire : "RaiseEvent Click"
2- d'assigner dans le formulaire l'instance associée au bouton qui a déclenché l'événement : "Set USF.bouton = instance_button", où "bouton" est dans le formulaire la variable d'instance de la classe CmdButton.
ci-dessous code du formulaire :
' définition événements bouton
Public WithEvents bouton As CmdButton
Private Sub UserForm_Initialize()
Dim ws As Worksheet
Dim obj As Object
Dim n As Integer
Dim Code As String
n = 0
Me.Height = 30
Me.Width = 230
For Each ws In ThisWorkbook.Worksheets
n = n + 1
Me.Height = Me.Height + 30
Set obj = Me.Controls.Add("Forms.Label.1", "Label1", True)
With obj
.name = "Label" & n
.caption = ws.name
.Top = Me.Height - 49
.Left = 18
.Height = 12
.Width = 162
End With
Set obj = Me.Controls.Add("Forms.CommandButton.1", "CommandButton1", True)
With obj
.name = "CommandButton" & n
.caption = "Go"
.Top = Me.Height - 54
.Left = 186
.Height = 20
.Width = 20
End With
Dim instance As Object
'création pour le bouton de commande du formulaire, d'une instance de la classe "CmdButton"
Set instance = New CmdButton
'stockage dans l'instance créée des 2 objets : l'instance et le commandbutton
Set instance.Init(instance) = obj
Next ws
End Sub
Private Sub bouton_Click()
On Error Resume Next
n = Right(bouton.name, 1)
Sheets(Me.Controls("Label" & n).caption).Select
End Sub
ci-joint fichier
- Messages
- 4'090
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonjour,
Veuillez trouver ci-joint le calendrier que j'ai développé à partir du module de classe ci-dessus, utilisable dans un formulaire ou dans une feuille. Ce calendrier gère les jours fériés et les week-end et se positionne en fonction de la zone à remplir.
Sa mise en place est simple :
1- stocker le contrôle dans le répertoire de votre choix
2- ouvrir le classeur où vous voulez ajouter le contrôle
3- à partir du classeur, menu fichier --> ouvrir le contrôle
4- sauvegarder votre classeur
Le contrôle est à présent actif et sera désormais systématiquement chargé à chaque ouverture de votre classeur.
Son utilisation est simple :
appeler la procédure "afficher_calendrier(objet)" où objet est une Textbox ou une cellule Range.
Exemple de code associé à une feuille pour la cellule "A1"
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Address = Range("A1").Address Then
'affichage calendrier
Call afficher_calendrier(Target)
End If
End Sub
Exemple de code associé à un TextBox dans un UserForm :
Private Sub TextBox1_Enter()
'affichage calendrier
Call afficher_calendrier(TextBox1)
End Sub