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:

49test-userform.xlsm (24.17 Ko)

Le sujet dont je parle:

https://forum.excel-pratique.com/viewtopic.php?f=2&t=120672

Voir le post de ThauThème

Bonjour Skiinck,

voici un exemple,

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.

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é J'ai encore un peu du mal avec la logique pour tout t'avouer, j'ai réussi à te faire ça par pur hasard contrairement aux autres qui ont l'air de déjà plus connaître la chose

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!

49date-picker.xlsm (20.44 Ko)

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.

rs6y

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

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

91exemple1.xlsm (31.76 Ko)

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
84calendrier.xlam (56.13 Ko)
Rechercher des sujets similaires à "generer code boutons meme generes userform"