IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

Comment réunir UserForm et Module de classe en un seul module exportable?


Sujet :

Macros et VBA Excel

  1. #1
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut Comment réunir UserForm et Module de classe en un seul module exportable?
    Bonjour,

    Soit un UserForm (UserForm1) comportant un nombre "dynamique" de boutons.
    J'ai dans ce projet besoin :
    - d'un module Userform :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    Private Sub UserForm_Initialize()
    Dim Obj As Control
    Dim i As Integer
    Dim Cl As Classe1
     
    Set Collect = New Collection
     
    For i = 1 To 7
        Set Obj = Me.Controls.Add("forms.CommandButton.1")
        With Obj
            .Name = "Bouton" & i
            .Object.Caption = "Bouton " & i
            .Width = 100
            .Height = 30
            .Left = 20
            .Top = .Height * (i - 1) + 5
        End With
        Set Cl = New Classe1
        Set Cl.Bouton = Obj
        Collect.Add Cl
    Next i
    With Me
        .Height = Obj.Height + Obj.Top + (5 * (i - 2))
        .Width = (Obj.Left * 2) + Obj.Width
    End With
    Set Obj = Nothing
    End Sub
    - d'un module standard :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Option Explicit
     
    Public Collect As Collection
    - d'un module de classe (Classe1) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Option Explicit
     
    Public WithEvents Bouton As MSForms.CommandButton
     
    Private Sub Bouton_Click()
    MsgBox Bouton.Name
    End Sub
    Très efficace, tout fonctionne.
    Mais, mon but est d'exploiter cet UserForm dans de nombreux projets Excel.
    Je souhaite donc n'avoir qu'un seul module à exporter et importer.
    Dans un premier temps, j'ai songé à intégrer le module de classe dans l'Userform de cette manière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    Option Explicit
     
    Public WithEvents Bouton As MSForms.CommandButton
     
    Private Sub Bouton_Click()
    MsgBox Bouton.Name
    End Sub
     
    Private Sub UserForm_Initialize()
    Dim Obj As Control
    Dim i As Integer
    Dim Cl As Classe1
     
    Set Collect = New Collection
     
    For i = 1 To 7
        Set Obj = Me.Controls.Add("forms.CommandButton.1")
        With Obj
            .Name = "Bouton" & i
            .Object.Caption = "Bouton " & i
            .Width = 100
            .Height = 30
            .Left = 20
            .Top = .Height * (i - 1) + 5
        End With
        Set Obj = Me.Bouton
    Next i
    With Me
        .Height = Obj.Height + Obj.Top + (5 * (i - 2))
        .Width = (Obj.Left * 2) + Obj.Width
    End With
    Set Obj = Nothing
    End Sub
    Mais cela ne fonctionne pas, une variable With Events ne pouvant être un tableau... Dans le code ci-dessus seul le dernier bouton réagit. Normal!
    Je pourrais, bien entendu, déclarer chaque bouton dans une variable With Events :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Public WithEvents Bouton1 As MSForms.CommandButton
    Public WithEvents Bouton2 As MSForms.CommandButton
    Public WithEvents Bouton3 As MSForms.CommandButton
    Public WithEvents Bouton4 As MSForms.CommandButton
    Public WithEvents Bouton5 As MSForms.CommandButton
    Public WithEvents Bouton6 As MSForms.CommandButton
    Public WithEvents Bouton7 As MSForms.CommandButton
    Mais le but est que cela soit réellement dynamique.
    Avez-vous donc une solution pour "intégrer" ces trois modules en un seul?
    Peut être créer l'userfom depuis le module de classe... Mais je n'y arrive pas...
    Merci d'avance
    Cordialement,
    Franck

  2. #2
    Expert éminent

    Homme Profil pro
    Curieux
    Inscrit en
    Juillet 2012
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Curieux
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2012
    Messages : 5 073
    Points : 9 853
    Points
    9 853
    Billets dans le blog
    5

  3. #3
    Membre expert
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 267
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 2 267
    Points : 3 663
    Points
    3 663
    Par défaut
    Bonjour,

    Ceci t’intéressera peut-être : http://www.spreadsheet1.com/move-exc...o-another.html
    Tombé dessus il y a qq jours seulement j'avoue ne pas avoir encore testé .
    Il y a d'autres trucs intéressants sur ce site...

    eric

  4. #4
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 942
    Points
    55 942
    Billets dans le blog
    131
    Par défaut
    Salut.

    De manière native, il n'est pas possible de "fusionner" des modules de classe. Or, le module d'un userform est un module de classe. Tu devras donc toujours avoir un module (et donc un fichier) par classe créée.
    A mon avis, il faut d'abord déterminer si tu veux exporter des modules exploitables directement (1), c'est-à-dire finis, ou si tu souhaites pouvoir disposer de squelettes de modules à adapter à tes classeurs (2).

    (1) Modules exploitables directement
    (1.1) Soit tu sauves les deux modules (userform et classe perso) dans ton dossiers d'outils VBA et tu les ajoutes aux projets qui doivent les utiliser...
    (1.2) Soit tu crées un xlam et les projets qui en ont besoin y font référence ou le chargent.

    (2)
    (2.1) Soit tu fais comme au point 1.1 et tu complètes en fonction de tes besoins
    (2.2) soit dans ton carnet électronique de notes VBA, tu copies les bouts de code et tu les références pour pouvoir les réutiliser au besoin. (C'est la méthode que j'utilise)

    Perso, je ne suis pas chaud pour les solutions externes qui ajoutent des addins à Excel. Chacun son choix en ce domaine, bien sûr...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  5. #5
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    Bonjour à tous,

    Le but, et j'aurais du le préciser au départ, n'est pas pour m'en servir personnellement dans tous mes projets.
    ça je sais faire. S'il s'agit d'exporter et d'importer 3 malheureux modules, je peux maitriser.
    Le but de ce sujet est de faciliter la mise à disposition d'un projet relativement complexe à nos internautes.
    Lorsque nous mettons à disposition des codes comportant plusieurs modules (classe, Userform...), comportant chacun moult codes et fonctions, l'internaute ne maitrisant pas VBA pourrait être intéressé, mais la difficulté à intégrer cela à son classeur, risque de le rebuter.
    C'est à ceux là que je pense en leur livrant clef en main un module importable et "appelable" en une ligne.
    Ce que j'ai voulu faire au départ dans cet exemple est de :
    - placer tous les codes dans le Module de l'Usf (pour n'avoir que lui à importer/exporter)
    - dire à l'internaute : pour que cela fonctionne, tu importes l'usf, tu l'appelles avec telle ligne de code et tu modifies telle fonction pour restituer tes données dans ta feuille ou ailleurs.

    L'idée de Pierre Fauconnier de placer le tout dans un xlam (ou plutôt un xla pour que tous y aient accès) est la plus approchante de ce que je souhaitais initialement.

    Pour l'heure, c'est dimanche, je ne vous embête donc pas plus et reviens demain avec d'autres informations.

    Merci, en tout cas, pour vos précisions.
    A+
    Cordialement,
    Franck

  6. #6
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 379
    Points : 12 075
    Points
    12 075
    Billets dans le blog
    8
    Par défaut re
    Bonjour
    en general une classe de control est faite pour eviter de gérer leur evement par un seul
    donc pour moi ici il y a un soucis de comprehention du contexte
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Public WithEvents Bouton As MSForms.CommandButton
    Public WithEvents Bouton2 As MSForms.CommandButton
    Public WithEvents Bouton3 As MSForms.CommandButton
    Public WithEvents Bouton4 As MSForms.CommandButton
    Public WithEvents Bouton5 As MSForms.CommandButton
    Public WithEvents Bouton6 As MSForms.CommandButton
    Public WithEvents Bouton7 As MSForms.CommandButton
    un seul sffit
    et dans levenement clic de la classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    select case bouton.name
    case "bouton1
    case "bouton2"  'etc....
    end select
    regarde dans les contrib tu a des exemple de userform avec l'effet mouse in/out regarde comment j'intègre les boutons et le userform dns la même classe
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  7. #7
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    Bonjour,

    Je ne cherche pas à créer une classe pour les boutons d'un Userform, mais bel et bien de réunir tout le projet en un seul module.
    J'ai tenté de tout placer dans le module de l'userform, mais cela ne peut fonctionner.

    Le but est de créer un objet (type userform perso) contenant des boutons de commande qui doivent réagir.

    J'ai donc tenté de créer une classe qui créerait mon userform.

    Pour l'instant, cela donne ceci :
    Code du module de Classe (UsfPerso):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Private Usf As Object
     
    Private Sub Class_Initialize()
    Set Usf = ThisWorkbook.VBProject.VBComponents.Add(3)
    MsgBox "Userform créé"
    End Sub
     
    Private Sub Class_Terminate()
    ThisWorkbook.VBProject.VBComponents.Remove Usf
    MsgBox "Userform effacé"
    End Sub
    Que l'on appelle, depuis un Module par exemple, grâce au code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Public MyUsf As Object
     
    Sub test()
    'création userform
    Set MyUsf = New UsfPerso
    'suppression userform
    Set MyUsf = Nothing
    End Sub
    Pensez vous que je puisse donc ajouter à la classe UsfPerso toutes les propriétés d'un userform, ainsi que les codes pour ajouter dynamiquement mes boutons de commande?

    De cette manière, je n'ai plus qu'un seul Module, celui de ma Classe...
    Cordialement,
    Franck

  8. #8
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 379
    Points : 12 075
    Points
    12 075
    Billets dans le blog
    8
    Par défaut re
    Bonjour
    oui de la même manière que si le userform était déjà présent
    mais ca implique que tout tes fichier récepteurs de la classe auront le même userform

    moi je préfèrerais un xla
    avec les sub correspondante au boutons etc.....
    et dans chaque fichiers récepteurs activer le xla
    ainsi il n'y a pas de userform a ajouter dynamiquement
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  9. #9
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    Le but est vraiment de simplifier la manoeuvre pour un internaute.
    Je pourrais prendre un exemple bien précis, mais j'aimerais que cette discussion demeure généraliste.

    En fait, je parviens bien à créer dynamiquement mon Userform et ses contrôles depuis ma classe, mais ne parviens pas à faire réagir mes boutons...

    J'en suis là de mon code :

    Module (procédure d'appel) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Public MyUsf As Object
     
    Sub test()
    'création userform
    Set MyUsf = New UsfPerso
    'suppression userform
    Set MyUsf = Nothing
    End Sub
    Module de classe (nommé UsfPerso)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    Private Usf As Object
    Public WithEvents Bouton As MSForms.CommandButton
     
    Private Sub Class_Initialize()
        Set Usf = ThisWorkbook.VBProject.VBComponents.Add(3)
        Call AjoutButton(8)
        VBA.UserForms.Add(Usf.Name).Show
    End Sub
     
    Private Sub AjoutButton(cptButton As Byte)
    Dim Obj As Object, i As Byte
     
        With Usf
            For i = 1 To cptButton
                Set Obj = .Designer.Controls.Add("forms.CommandButton.1")
                With Obj
                    .Name = "Bouton" & i
                    .Object.Caption = "Bouton " & i
                    .Width = 100
                    .Height = 30
                    .Left = 20
                    .Top = .Height * (i - 1) + 5
                End With
            Next i
            .Properties("Height") = Obj.Height + Obj.Top + (5 * (i - 2))
            .Properties("Width") = (Obj.Left * 2) + Obj.Width
        End With
    End Sub
     
    Private Sub Bouton_Click()
        MsgBox Bouton.Name
    End Sub
     
    Private Sub Class_Terminate()
        ThisWorkbook.VBProject.VBComponents.Remove Usf
    End Sub
    Ce qu'il me manque c'est de savoir s'il est possible de faire fonctionner mes boutons ainsi et, si oui, comment? quel code??
    Merci d'avance.

    @Patricktoulon :
    mais ca implique que tout tes fichier récepteurs de la classe auront le même userform
    C'est le but...
    Cordialement,
    Franck

  10. #10
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 942
    Points
    55 942
    Billets dans le blog
    131
    Par défaut
    Tu t'embarques dans un truc pas trop piqué des hannetons...

    Tu vas devoir créer dynamiquement ton userform, ainsi que le code des boutons que tu crées

    Pour cela, j'ai créé une classe perso. Cela permettrait, à l'extrême, de créer dynamiquement des userforms différents avec la même classe. Je développerai plus bas...

    Dans un premier temps, on ne crée que des boutons, dont on peut déterminer le nombre. On a donc une classe perso pourvue d'une seule méthode Init qui reçoit le nombre de boutons à créer.
    Cette classe va créer le userform, créer les x boutons et les placer l'un en dessous de l'autre.
    Cette classe doit aussi créer le code qui réagira au clic des boutons. Il faut noter ici que chaque bouton aura sa propre proc.
    Lorsque ce code est créé, le userform est rendu visible. Il est modal. Dès qu'on le ferme, il est détruit.

    Pour amorcer cela, un code dans un module standard crée simplement un nouvel objet basé sur la classe et lance la proc Init avec en paramètres le nombre de boutons à créer
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Sub Test()
      Dim myForm As New CustomForm
     
      myForm.Init 5
    End Sub

    Le code de la classe perso, nommée CustomForm
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    Option Explicit
     
    Private oForm
    Private oClass
     
    Public Sub Init(CountOfButtons As Integer)
      Dim Counter As Integer
      Dim LineCounter As Long
      Dim CodeButton As String
      Dim CodeTemp As String
      Dim OButton As MSForms.CommandButton
     
      ' Initialisation
      Set oForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ComponentType.vbext_ct_MSForm)
      oForm.Name = "PersoForm"
      CodeButton = "Private sub [button]_Click()" & vbCrLf & _
        "msgbox [button].name" & vbCrLf & _
        "End Sub"
     
      ' Création des boutons
      For Counter = 1 To CountOfButtons
        Set OButton = oForm.Designer.Controls.Add("forms.Commandbutton.1")
        With OButton
          .Name = "Button_" & Counter
          .Top = 6 + (Counter - 1) * 18
          .Left = 6
          .Caption = "Button_" & Counter
          .Width = 100
        End With
     
        ' Création du code du bouton
        CodeTemp = Replace(CodeButton, "[button]", OButton.Name)
        With oForm.CodeModule
          LineCounter = .CountOfLines
          .InsertLines LineCounter + 1, CodeTemp
        End With
      Next
     
      ' Affichage puis destruction
      ' A priori, il faudrait enregistrer le classeur après destruction
      ' si une nouvelle création devait être demandée.
      VBA.UserForms.Add(oForm.Name).Show
      ThisWorkbook.VBProject.VBComponents.Remove oForm
    End Sub

    Limites du système:
    • Tel quel, tout objet créé aura toujours le même nom et la même présentation;
    • Le classeur doit être enregistré entre deux créations d'objet car si le formulaire est enlevé de la collection des composants, il n'est pas détruit, et il n'est donc pas possible de récréer un nouveau formulaire du même nom;
    • Dans les options d'Excel, il faut avoir coché "Accès approuvé au modèle d'objet du projet VBA" vans Options>Centre de gestion de la confidentialité>Paramètres des macros.



    On pourrait améliorer la classe en développant son "constructeur", c'est-à-dire la méthode Init. Elle pourrait recevoir un tableau de x lignes, chaque ligne précisant le type de contrôle à construire, son nom et le code associé, par exemple. Cela permettrait alors de créer "à la volée" plusieurs userforms.

    Cela dit, on est en train de créer du code qui crée du code, et cela me semble tout de même assez fragile... D'autant plus qu'il faut que la case de sécurité soit cochée chez l'utilisateur, et que cela me semble plus complexe (et parfois bloqué par l'IT) que d'importer les modules...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  11. #11
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 379
    Points : 12 075
    Points
    12 075
    Billets dans le blog
    8
    Par défaut re
    re

    @Patricktoulon :
    mais ca implique que tout tes fichier récepteurs de la classe auront le même userform


    C'est le but...
    moi je suis aussi un internaute et je l'accepterais pas entre nous


    tu connais la race de pomme glannioshias... non?

    c'est normal personne n'en veut on en trouve donc pas sur les marchés a bon entendeur
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  12. #12
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    Bonjour,

    @Pierre Fauconnier : Merci.
    Pour pallier aux limites que tu pointes, il suffit de ne pas nommer la form en supprimant la ligne de code : oForm.Name = "PersoForm"
    Ainsi, plus de souci, on peut créer x formulaires sans enregistrer entre temps.
    En ce qui concerne la présentation de l'userform ainsi créé, il est nécessaire de conserver toujours la même.
    En effet, le but est de créer un "objet personnel" (par exemple : une calculatrice, un calendrier,...) transposable facilement.

    Toutefois, comme tu le dis, j'aurais souhaité éviter de "créer du code qui crée du code" et surtout d'avoir à cocher la case "Accès approuvé au modèle d'objet du projet VBA".
    Ces deux contraintes m'amènent à réfléchir sur ce projet.
    Il vaut certainement mieux avoir deux modules à importer plutôt que cette méthode qui, comme tu le soulignes, n'est pas toujours réalisable (parfois bloqué par l'IT).

    Précision : pour utiliser le code de Pierre Fauconnier, la référence : Microsoft Forms 2.0 Object Library doit être cochée.

    @PatrickToulon : Je ne comprends pas, du tout, ou tu veux en venir avec : c'est normal personne n'en veut
    Si je trouve sur le net, un objet tel que décrit ici (un calendrier, une calculatrice...) qui ne nécessite que l'import d'un module de classe et deux lignes de code pour être actif, à titre perso, je prends...
    On aurait pu choisir de créer un .xla, comme proposé par Pierre Fauconnier dès le départ.
    Mais, un xla nécessite d'être intégré sur chaque pc ou serait installé le classeur utilisant notre objet.
    Il en est de même pour un .ocx.
    La méthode proposée ici aurait permis d'avoir l'objet directement intégré au classeur.
    => solutionne la portabilité (selon les versions d'excel) d'un objet (l'exemple du calendrier (contrôle Calendar vs DtPicker) est assez parlant)
    => solutionne la transportabilité

    En fin de compte, cet exercice m'aide à un peu mieux appréhender la création d'objet grâce aux modules de classe et si vous le voulez bien, je reviendrais ultérieurement avec d'autres difficultés.
    Notamment l'étape prochaine est de proposer des méthodes à cette classe.
    Entre autres, une méthode Valeur, permettrait le retour, dans le module standard, de la valeur correspondante au bouton cliqué (par son caption ou sa propriété tag par exemple).
    Je vais toutefois essayer de trouver cela par moi-même.

    Merci encore à tous et à tantôt.
    Cordialement,
    Franck

  13. #13
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 942
    Points
    55 942
    Billets dans le blog
    131
    Par défaut
    Citation Envoyé par pijaku Voir le message
    Pour pallier aux limites que tu pointes, il suffit de ne pas nommer la form en supprimant la ligne de code : oForm.Name = "PersoForm"
    Oui, ce n'est pas un problème, car le userform pourrait être rendu public au sein de la classe, de manière à le manipuler via la classe, comme une propriété "objet" de la classe.

    Citation Envoyé par pijaku Voir le message
    Précision : pour utiliser le code de Pierre Fauconnier, la référence : Microsoft Forms 2.0 Object Library doit être cochée.
    J'avais pensé que je devais le préciser, puis j'ai oublié. Mais c'est une limite supplémentaire, qui pourrait s'avérer bloquante également. Il faut noter que l'ajout d'un userform à un projet VBA coche automatiquement cette référence.

    Citation Envoyé par pijaku Voir le message
    En fin de compte, cet exercice m'aide à un peu mieux appréhender la création d'objet grâce aux modules de classe et si vous le voulez bien, je reviendrais ultérieurement avec d'autres difficultés.
    Notamment l'étape prochaine est de proposer des méthodes à cette classe.
    Si cela t'intéresse (je ne connais pas ton niveau à ce sujet), tu peux lire mon tuto sur les classes perso en VBA (http://fauconnier.developpez.com/art...neral/classes/)

    Citation Envoyé par pijaku Voir le message
    Entre autres, une méthode Valeur, permettrait le retour, dans le module standard, de la valeur correspondante au bouton cliqué (par son caption ou sa propriété tag par exemple).
    Je vais toutefois essayer de trouver cela par moi-même.
    Evidemment, dans ce cas, il faudrait ne pas détruire l'objet (en tout cas pas de suite), mais juste le rendre invisible (.hide). Dès lors, on pourrait utiliser ces propriétés publiques avant de détruire l'objet. Comme tu l'avais envisagé, on pourrait d'ailleurs détruire le userform créé dans le destructeur de l'objet.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  14. #14
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    Merci de ces prcisions.
    Pourrais-tu, stp, préciser :
    Le userform pourrait être rendu public au sein de la classe, de manière à le manipuler via la classe, comme une propriété "objet" de la classe.
    En fait, en Private cela fonctionne bien, d'où ma demande de complément d'info...

    En ce qui concerne ton tutoriel, oui je l'ai lu. Ainsi que les deux autres "Made in DVP" (Michel Blavin & Emmanuel Tissot) :
    http://excel.developpez.com/faq/?pag...ntroductionPOO

    Je penses toutefois qu'une relecture s'impose car j'ai du mal à déterminer la meilleure méthode pour retourner la valeur choisie lors d'un clic sur un des boutons en sachant que je souhaite vraiment privilégier la facilité pour l'utilisateur. Celui-ci ne devant pas, selon le but de ce sujet, saisir trop de code, il n'aurait qu'à initialiser la form et retourner la valeur.
    Du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Sub test()
    Dim myForm As New UsfPerso
      myForm.Init 5
      Debug.Print myForm.Valeur
    End Sub
    Je vais donc, de ce pas, relire tous ces tutos...

    EDIT : Je n'ai pas eu à trop chercher. Une simple relecture de ton tutoriel au chapitre des propriétés (http://fauconnier.developpez.com/art...asses/#LIV-C-6) m'a donné la solution.
    Idem pour la déclaration Publique de l'Userform...

    Voici donc ton code, légèrement modifié, pour obtenir, en retour, le Caption du bouton cliqué :
    Module d'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Option Explicit
     
    Public myForm As New UsfPerso
     
    Sub test()
      myForm.Init 5
      Debug.Print myForm.Valeur
    End Sub
    Module de la Classe UsfPerso :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    Option Explicit
     
    Private oForm
    Private oValeur As String
     
    Private Sub Class_Initialize()
      Set oForm = ThisWorkbook.VBProject.VBComponents.Add(3)
    End Sub
     
    Public Sub Init(CountOfButtons As Integer)
      Dim Counter As Integer
      Dim LineCounter As Long
      Dim CodeButton As String
      Dim CodeTemp As String
      Dim oButton As MSForms.CommandButton
     
      ' Initialisation
      CodeButton = "Private sub [button]_Click()" & vbCrLf & _
        "myForm.Valeur = [button].Caption" & vbCrLf & _
        "Unload Me" & vbCrLf & _
        "End Sub"
     
      ' Création des boutons
      For Counter = 1 To CountOfButtons
        Set oButton = oForm.Designer.Controls.Add("forms.Commandbutton.1")
        With oButton
          .Name = "Button_" & Counter
          .Top = 6 + (Counter - 1) * 18
          .Left = 6
          .Caption = Counter
          .Width = 100
        End With
     
        ' Création du code du bouton
        CodeTemp = Replace(CodeButton, "[button]", oButton.Name)
        With oForm.CodeModule
          LineCounter = .CountOfLines
          .InsertLines LineCounter + 1, CodeTemp
        End With
      Next
      VBA.UserForms.Add(oForm.Name).Show
    End Sub
     
    Property Get Valeur() As String
        ' Propriété en lecture
        Valeur = oValeur
    End Property
     
    Property Let Valeur(Valeur As String)
        ' Propriété en écriture
        oValeur = Valeur
    End Property
     
     
    Private Sub Class_Terminate()
      ThisWorkbook.VBProject.VBComponents.Remove oForm
    End Sub
    Cordialement,
    Franck

  15. #15
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 942
    Points
    55 942
    Billets dans le blog
    131
    Par défaut
    Je viens de faire quelques tests, et ça marche pas mal du tout pour récupérer la valeur saisie dans un textbox (par exemple)

    Le but est de déterminer sur quel bouton on a cliqué (Validate ou Cancel) du formulaire créé dynamiquement. Si on a cliqué sur Validate, alors, on récupère la valeur du textbox.

    Tout se passe comme si on avait un userform créé manuellement avec le code suivant. Après avoir cliqué sur un des deux boutons, le client de ce userform teste la valeur de Clickedbutton (variable publique modifiée par le code des deux boutons.). Si on a cliqué sur Validate, on peut récupérer la valeur du textbox au sein d'une propriété (variable "publique" pour faire simple) de la classe appelante. Le code ci-dessous sera créé par la classe appelante.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Option Explicit
     
    Public ClickedButton As String
     
    Private Sub btnValidate_Click()
    ClickedButton = "Validate"
    Me.Hide
    End Sub
     
    Private Sub btnCancel_Click()
    ClickedButton = "Cancel"
    Me.Hide
    End Sub
    Le code du module standard qui gère la création de l'objet de la classe perso est le suivant. Il passe un texte qui sera le texte par défaut du textbox du formulaire créé et récupère la valeur de la variable "publique" de l'objet pour l'afficher dans un message. Cela illustre bien que l'on peut récupérer les valeurs saisies au sein du userform créé dynamiquement (ou des cases à cocher ou autres...)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Sub Test()
      Dim myForm As New CustomForm
      myForm.Init "Pierre"
      MsgBox myForm.TextValue
    End Sub
    Voici le code commenté de la classe CustomForm, adapté par rapport à la version précédente...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    Option Explicit
     
    Public TextValue As String
     
    Public Sub Init(Optional DefaultText As String)
      Dim Counter As Integer
      Dim LineCounter As Long
      Dim OControl As MSForms.Control
      Dim oForm
      Dim ufr As Object
     
      ' Création du formulaire
      Set oForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ComponentType.vbext_ct_MSForm)
     
      ' Création de l'étiquette
      Set OControl = oForm.Designer.Controls.Add("Forms.Label.1")
      With OControl
        .Name = "labText1"
        .Top = 6
        .Left = 6
        .Width = 50
        .Height = 18
        .Caption = "Saisie:"
      End With
     
      ' Création du textbox
      Set OControl = oForm.Designer.Controls.Add("Forms.Textbox.1")
      With OControl
        .Name = "tboText1"
        .Top = 6
        .Left = 56
        .Width = 200
        .Height = 18
        .Value = DefaultText
      End With
     
      ' Création du bouton Validate
      Set OControl = oForm.Designer.Controls.Add("Forms.Commandbutton.1")
      With OControl
        .Name = "btnValidate"
        .Top = 30
        .Left = 6
        .Width = 256
        .Height = 18
        .Caption = "Valider"
      End With
     
      'Création du bouton Cancel
      Set OControl = oForm.Designer.Controls.Add("Forms.Commandbutton.1")
      With OControl
        .Name = "btnCancel"
        .Top = 54
        .Left = 6
        .Width = 256
        .Height = 18
        .Caption = "Annuler"
      End With
     
      ' Création du code du module du formulaire
      With oForm.CodeModule
        LineCounter = .CountOfLines
        .InsertLines LineCounter + 1, "public ClickedButton as string" & vbCrLf & vbCrLf & _
        "private sub btnValidate_Click()" & vbCrLf & _
        "clickedbutton = ""Validate""" & vbCrLf & _
        "me.hide" & vbCrLf & _
        "end sub" & vbCrLf & vbCrLf & _
        "private sub btnCancel_Click()" & vbCrLf & _
        "clickedbutton = ""Cancel""" & vbCrLf & _
        "me.hide" & vbCrLf & _
        "end sub"
      End With
     
      ' On crée un objet qui récupère le formulaire créé. C'est un userform, on peut
      ' peut donc manipuler ces méthodes (Show, Hide, ...) et manipuler les valeurs
      ' de ses contrôles (notamment tboText1.value)
      Set ufr = VBA.UserForms.Add(oForm.Name)
      ufr.Show
      ' Test du bouton cliqué via la variable "publique" ClickedButton du formulaire
      ' Si c'est Validate, on récupère la valeur du textbox que l'on transfère à
      ' la variable TextValue de l'objet "CustomForm".
      If ufr.ClickedButton = "Validate" Then
        TextValue = ufr.tboText1.Value
      End If
      Unload ufr
      ThisWorkbook.VBProject.VBComponents.Remove oForm
    End Sub
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  16. #16
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    Je teste également de mon côté les deux différentes classes développées ici.
    La tienne (CustomForm) et la mienne (UsfPerso).

    Cela m'amène plusieurs questionnements, notamment :
    1- la fermeture de l'userform par la croix provoque dans ton cas une erreur d'automation.
    Exactement comme si "l'objet" avait "disparu". Je ne comprends pas bien ce "phénomène".

    2- Mon VBA semble ne pas accepter la constante vbext_ComponentType.vbext_ct_MSForm
    Y a t'il une raison à cela? Une référence manquante?
    Cette question est subsidiaire car cela fonctionne avec la valeur de cette constante (3), mais cela me turlupine...

    J'aime beaucoup ton idée de se servir de l'userform et d'en créer le code directement plutôt que de coder chacun de ses contrôles.
    C'est super pratique pour créer le code de la Classe à partir d'un exemple d'UserForm déjà codé "en dur".

    Ma dernière question de cette matinée concernera l'approche que tu as.
    Pourquoi ne pas utiliser de propriétés de la classe pour le retour d'une valeur? (cf l'EDIT de mon post de 10h48)
    Pourquoi donc tout placer dans une procédure Init?
    Cordialement,
    Franck

  17. #17
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 942
    Points
    55 942
    Billets dans le blog
    131
    Par défaut
    Citation Envoyé par pijaku Voir le message
    J
    1- la fermeture de l'userform par la croix provoque dans ton cas une erreur d'automation.
    Chez moi aussi. J'ai essayé de contourner cela en mettant la propriété Cancel du bouton btnCancel à true, mais cela n'a rien résolu. Je n'ai pas de solution pour l'instant.

    Citation Envoyé par pijaku Voir le message
    2- Mon VBA semble ne pas accepter la constante vbext_ComponentType.vbext_ct_MSForm
    J'ai eu le même problème au début(je n'avais mis que vtext_ct...). J'ai alors saisi la ligne complète et le problème a été résolu. Il me semble que pour y arriver, j'avais saisi vbext_ puis CTRL+ESPACE, et il m'a alors donné les éléments souhaités.


    Citation Envoyé par pijaku Voir le message
    J'aime beaucoup ton idée de se servir de l'userform et d'en créer le code directement plutôt que de coder chacun de ses contrôles.
    C'est super pratique pour créer le code de la Classe à partir d'un exemple d'UserForm déjà codé "en dur".
    C'est effectivement plus simple, et cela évite les erreurs. Il faut juste penser à doubler les quotes et à mettre les retours à la ligne (si l'on veut voir du code propre dans le userform, car normalement, l'objet étant détruit en fin de Init, il n'est normalement jamais visible)...

    Citation Envoyé par pijaku Voir le message
    Ma dernière question de cette matinée concernera l'approche que tu as.
    Pourquoi ne pas utiliser de propriétés de la classe pour le retour d'une valeur? (cf l'EDIT de mon post de 10h48)
    Pourquoi donc tout placer dans une procédure Init?
    En fait, je n'aime pas que la modification d'une propriété active du code. Le "setter" d'une propriété devrait normalement consister uniquement en un transfert de la valeur reçue vers une variable d'instance, et c'est une méthode qui devrait activer le processus. Dès lors, j'ai pris l'habitude de passer mes valeurs au constructeur de la classe (ici, la méthode Init) de façon à pouvoir démarrer le traitement en étant sûr d'avoir toutes les valeurs nécessaires. Dans le cas où on passerait la valeur à la propriété, il faudrait alors après lancer l'INIT. Cela permettrait de lancer l'INIT alors que l'on n'a pas passé la valeur à la propriété... Ok, on pourrait tester à l'INIT que l'on a tout ce qu'il faut, mais ça fait un peu du code poubelle, surtout pour le client de la classe. Ici, on reste dans l'optique d'une ligne côté appelant, à charge pour l'appelant de passer les valeurs nécessaires. Tout cela est un peu "inutile" dans ce cas-ci, mais je procède en suivant ce qui pour moi fait partie des "good practices"

    Et pour terminer les comparaisons entre ta méthode et la mienne, j'ai l'habitude de ne pas repasser les valeurs directement au clic du bouton. Cela permet d'approcher au plus près une programmation de type "trois-tiers" (ou trois couches) dans laquelle le userform (ou la classe appelante, dans ce cas-ci) ne sert qu'au niveau de la couche d'interface. La couche "Business" (ici la méthode du module standard) peut ainsi charger le userform, lui passer les valeurs éventuelles, et à la fermeture du userform (chaque bouton ayant me.hide dans sa proc sur click), la couche business récupère alors les valeurs des contrôles (éventuellement d'un object complexe passé au userform), puis décharge celui-ci.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  18. #18
    Membre émérite
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 814
    Points : 2 949
    Points
    2 949
    Billets dans le blog
    10
    Par défaut
    J'ai essayé de contourner cela en mettant la propriété Cancel du bouton btnCancel à true, mais cela n'a rien résolu.
    Le problème de sortie de l'userform par la croix peut être résolu en empêchant cette fermeture.
    Pour cela, il suffit d'ajouter ce code au code de l'userform :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        "Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)" & vbCrLf & _
        "Cancel = True" & vbCrLf & _
        "end sub"
    j'avais saisi vbext_ puis CTRL+ESPACE, et il m'a alors donné les éléments souhaités.
    Mon VBA me donne comme valeur de constante : vbext_ct_MSForm
    J'en conclus que chaque version d'excel aurait des noms de constante différentes?? (2010 pour ma part).
    Cela voudrait dire qu'il vaut mieux utiliser la valeur (3) plutôt que le nom complet de la constante.
    D'autre part, se doit d'être cochée la référence Microsoft Visual Basic For Applications Extensibility 5.3

    Il faut juste penser à doubler les quotes et à mettre les retours à la ligne
    Bien entendu.

    En fait, je n'aime pas que la modification d'une propriété active du code.
    Je vais relire ce passage (plusieurs fois sans doute) pour une meilleure compréhension.
    N'étant pas de la partie, mais plutôt un amateur, ce langage demande de ma part une réflexion plus poussée.

    J'ajouterai toutefois que, ta manière de procéder permet également à l'utilisateur de se choisir lui-même le nom de la variable dans la partie appelante.
    En effet, de mon côté, le nom de cette variable doit être inscrit dans le code de chaque bouton.
    De plus, il y a obligation, de mon côté de déclarer cette variable en public.

    Je vais relire et poursuivre.
    Merci encore
    Cordialement,
    Franck

  19. #19
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Sub test()
    Dim Usf As New Classe1
    Usf.NewUsf "toto", 200, 100
    Usf.NewBouton "Bouton1", "Bouton 1", 100, 30, 20, 5
    Usf.Show
    End Sub
    Code Classe1 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    Private Usf As Object
    Private Nom As String
    Private Dico As Object
    Public WithEvents Bouton As MSForms.CommandButton
    Private Sub Class_Initialize()
     Set Dico = CreateObject("Scripting.dictionary")
    End Sub
    Public Sub NewUsf(Caption As String, Width As Double, Height As Double)
    Set Usf = ThisWorkbook.VBProject.VBComponents.Add(3)
    Nom = Usf.Name
      VBA.UserForms.Add (Nom)
     Set Usf = UserForms(UserForms.Count - 1)
    With Usf
        .Caption = Caption
        .Width = Width
        .Height = Height
      End With
    End Sub
    Public Sub Show()
    Usf.Show
    End Sub
    Sub NewBouton(Name As String, Caption As String, Width As Double, Height As Double, Left As Double, Top As Double)
    If Dico.EXISTS(Name) = True Then Exit Sub
    Dim cls As New Classe1
     Set Obj = Usf.Controls.Add("forms.CommandButton.1")
        With Obj
            .Name = Name
            .Caption = Caption
            .Width = Width
            .Height = Height
            .Left = Left
            .Top = Top
        End With
       Set cls.Bouton = Obj
       Dico.Add Name, Obj
       Set Obj = Nothing
    End Sub
    Private Sub Class_Terminate()
    If Nom <> "" Then
     Set VBComp = ThisWorkbook.VBProject.VBComponents(Nom)
        ThisWorkbook.VBProject.VBComponents.Remove VBComp
    End If
    End Sub

  20. #20
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 942
    Points
    55 942
    Billets dans le blog
    131
    Par défaut
    J'avais essayé l'ajout du Cancel sur le bouton (cfr mon précédent message) mais cela est inopérant chez moi...

    Il me semble que la constante générique porte le même nom dans nos versions... Effectivement, il faut la librairie pour pouvoir utiliser la constante générique plutôt que sa valeur.

    Pour le reste, ce sont des pratiques qui, respectées, me permet de coder "le plus proprement possible"... A chacun son style...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. [XL-2003] Clic droit de la souris sur un userform piloté par un module de classe
    Par mormic dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 07/11/2014, 09h58
  2. Réponses: 6
    Dernier message: 02/12/2007, 10h30
  3. Réponses: 8
    Dernier message: 22/02/2006, 15h09
  4. [JSP][Tomcat] COmment choisir la place des fichiers .class?
    Par mathieu dans le forum Tomcat et TomEE
    Réponses: 16
    Dernier message: 03/03/2004, 09h24
  5. Réponses: 14
    Dernier message: 15/01/2004, 01h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo