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 :

Module de classe ou macro commune à plusieurs TextBox


Sujet :

Macros et VBA Excel

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    839
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 839
    Par défaut Module de classe ou macro commune à plusieurs TextBox
    Bonjour à tous,

    Dans un UserForm qui contient 4 contrôlesTextBox1, 2, 3 et 4.

    Dont voici le code pour le premier :
    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
    Private Sub TextBox1_Change()
      colRecherche = 1
      clé = "*" & Me.TextBox1 & "*"
      Dim Tbl()
      For i = 1 To UBound(TblBD)
        If TblBD(i, colRecherche) Like clé Then
            n = n + 1
            ReDim Preserve Tbl(1 To UBound(TblBD, 2), 1 To n)
            For k = 1 To UBound(TblBD, 2): Tbl(k, n) = TblBD(i, k): Next k
         End If
      Next i
      If n > 0 Then
         Me.ListBox1.Column = Tbl
       Else
         Me.ListBox1.List = TblBD
       End If
    End Sub
    Les 3 autres sont identiques seul le nom du TextBox change.

    Quelle est la meilleure solution : créer un module classe ou si possible créer une macro commune au 4 TextBox.

    Je fais appel à vos connaissances et compétences pour apporter une réponse à mes questions.

    Merci d'avance.

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    839
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 839
    Par défaut
    Re bonjour,

    Après avoir parcouru sur différents forums pas mal d'exemples traitant :
    - des modules de classe
    - ou des arguments à passer dans un module pour une procédure appelante dans un UserForm

    Je n'arrive pas à créer une procédure pour éviter les répétitions.

    Une petite piste pour me mettre le pied à l'étrier ou pour m'aiguiller svp

  3. #3
    Expert confirmé
    Homme Profil pro
    Electrotechnicien
    Inscrit en
    Juillet 2016
    Messages
    3 241
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Electrotechnicien

    Informations forums :
    Inscription : Juillet 2016
    Messages : 3 241
    Par défaut
    Bonjour,

    Le VBA est un langage orienté objet, donc à chaque TextBox son code. Je ne vois pas où est le problème de répéter 4 fois un bout de code si court puisque c'est conçu pour cela.

    Quant aux classes, je ne peux pas vous répondre vu que je maîtrise pas.

    Cdlt

  4. #4
    Rédacteur/Modérateur


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

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

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Salut.

    POO ou pas (le VBA est bien plus procédural qu'orienté objet), il n'est jamais bon de répéter du code => lors d'une modif de la procédure, il faut reporter la modif dans chaque procédure qui répète les lignes. C'est pour cela, justement, que la création de classes personnalisées a été rendue possible. Ca permet de capitaliser le code au sein d'une appli, voire même de le transporter d'appli en appli en insérant le module de classe dans les projets qui en ont besoin. Mais le procédural pur permet cela aussi, notamment grâce aux arguments de procédure, et c'est pour cela que j'insiste tant, sur le forum, sur la découpe du processus en petites procédures qui ne font qu'une chose.

    Au passage, pour des raisons d'architecture et, là encore, d'économie de code, le code évènementiel ne devrait pas être applicatif. Il devrait se contenter d'appeler la (les) procédures applicatives. J'explique cela dans deux billets, ici et ici. C'est d'ailleurs l'architecture que j'explique dans le premier billet cité ("A quoi sert un code évènementiel?") que je te propose comme première solution.

    Ta quête d'une économie de code est donc pertinente. Avec si peu de contrôles à gérer, tu peux te baser sur ce qui suit, qui dirige l'évènement change de chaque textbox vers une procédure commune qui reçoit le textbox en argument. Tu as alors une seule procédure exécutive, et une seule ligne de code dans chaque textbox. Et pour cette architecture, tu n'as pas besoin de classe perso. Le gain est immédiat et évident, puisque tu ne répliques plus le code applicatif. Si tu dois le modifier, tu n'as qu'un seul endroit où aller. Qui plus est, tu peux tester bien plus facilement ce petit bout de code isolé que lorsqu'il est noyé dans des lignes avec lesquelles il n'a pas de lien.

    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
    Private Sub TextBox1_Change()
      Textboxchange TextBox1
    End Sub
     
    Private Sub TextBox4_Change()
      Textboxchange TextBox4
    End Sub
     
    Private Sub TextBox5_Change()
      Textboxchange TextBox5
    End Sub
     
    Private Sub TextBox6_Change()
      Textboxchange TextBox6
    End Sub
     
    Private Sub Textboxchange(tbo As MSForms.TextBox)
      MsgBox "vous modifiez le " & tbo.Name
    End Sub

    Tu peux aussi monter une classe perso. Je donne la façon de procéder ici, même si c'est peut-être un peu lourd pour 4 textbox, quoique...*

    1. Crée un module de classe dans ton projet. Dans mon exemple, je l'ai nommé ManagedTbo. Dans ce module, tu places le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Option Explicit
     
    Private WithEvents mTbo As MSForms.TextBox
     
    Sub Init(Item As MSForms.TextBox)
      Set mTbo = Item
    End Sub
     
    Private Sub mTbo_Change()
      MsgBox "Vous modifiez " & mTbo.Name
    End Sub
    Ce code déclare une variable privée de la classe en mentionnant que l'on va utiliser ses évènements, et permettra de transférer le textbox reçu en arguments à la variable privée dont on gère ici un évènement. Les évènements du contrôle (en fait le mtbo) sont gérés par code et tu peux gérer, grâce à WithEvents, les évènements du textbox. Dans la liste déroulante de gauche de la page de code du module, tu retrouveras l'objet mTbo et lorsque tu l'auras choisi, tu retrouveras à droite ses évènements que tu pourras gérer, notamment par le code mTbo_Change, exactement comme ceux que tu gères dans le userform. Mais la différence est qu'ici, tu as créé une procédure unique pour gérer l'évènement change de tous les textbox que tu gèreras de cette façon.
    Nom : 2020-08-30_194838.png
Affichages : 1357
Taille : 57,9 Ko

    La procédure Init se charge simplement de transférer à la variable privée le contrôle Textbox reçu en argument.


    2. A l'initialisation du userform, on décide des textbox à gérer, on crée le ManagedTextBox qui est la "surcouche" qui reçoit le textbox pour l'ajouter à une collection des ManagedTextbox, par exemple au travers d'une boucle. Le code du userform est alors réduit au minimum vital:
    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
    Option Explicit
     
    Dim mTbos As Collection
     
    Private Sub UserForm_Initialize()
      Dim c As MSForms.Control
      Dim tbo As ManagedTBO
     
      Set mTbos = New Collection
     
      For Each c In Me.Controls
        If TypeName(c) = "TextBox" Then
          Set tbo = New ManagedTBO
          tbo.Init c
          mTbos.Add tbo
        End If
      Next
    End Sub

    Tu peux avancer en pas-à-pas sur le Initialize du userform, en y plaçant un point d'arrêt (F9 lorsque tu as cliqué sur la ligne) et pratiquer de façon identique sur l'évènement de la classe perso. Tu as ainsi créé un seul code (règle d'or en programmation, selon moi) pour gérer tes textbox. Tu pourrais déporter l'exécution du TextboxChange de la classe dans une procédure standard, mais je n'en vois pas l'intérêt ici.

    Je développe également ce concept dans cette discussion, dont les échanges pourront éventuellement t'être profitables.

    * Si on souhaite la création d'un userform générique et/ou créant des contrôles dynamiques et/ou si l'on a beaucoup de contrôles qui vont utiliser le même code, alors la création d'une classe perso, éventuellement générique et donc déportant le traitement réel à une procédure d'un module standard se justifie tout à fait.
    "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 éclairé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    839
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 839
    Par défaut
    Bonjour M. FAUCONNIER, le forum,
    Bravo pour vos excellentes réponses.

    Dans ma quête d'une économie de code et éviter de répliquer le code applicatif vous avez parfaitement répondu à mes questions.

    Pour répéter un bout de code dans 4 Textbox ce n'est peut-être pas nécessaire, mais vos solutions sont très intéressantes pour gérer et modifier un nombre plus important de contrôles.

    Merci beaucoup pour votre aide qui me permet encore de progresser.

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    839
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 839
    Par défaut
    Bonjour le forum,

    Je suis en train de constituer dans un classeur des exemples de module de classe, de codes génériques, de procédures communes et fonctions, principalement avec des bouts de codes trouvés dans les discussions et le blog de Pierre FAUCONNIER.

    Et reviens sur cette discussion, car j'un petit souci avec les procédures suivantes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Function LastTableRow(Table As ListObject) As Long 
        LastTableRow = Table.ListRows.Count
    End Function
    Function LastAbsoluteTableRow(Table As ListObject) As Long 
        If Table.ListRows.Count > 0 Then LastAbsoluteTableRow = Table.DataBodyRange(Table.ListRows.Count, 1).Row
    End Function
    Si j'utilise l'une ou l'autre des fonctions dans une cellule de la feuille "=LastTableRow("Tableau1")" ou =LastAbsoluteTableRow("Feuil 1") elles renvoient "#VALEUR!"

    Je ne comprends pas pourquoi ?

    Une petite explication svp, merci d'avance.

  7. #7
    Rédacteur/Modérateur


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

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

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Salut.

    Les fonctions que tu utilises doivent recevoir en paramètre un ListObject. Dans l'interface Excel, cet objet est inconnu de sorte que tu ne sais forcément pas le passer en paramètres. Ce que tu peux passer, c'est la plage du tableau structuré. Tu dois donc adapter les fonctions pour qu'elles reçoivent une plage et en VBA, tu te serviras de ces plages pour pointer vers les Listobject correspondants.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Function LastTableRow1(rng As Range) As Long
        LastTableRow1 = rng.ListObject.ListRows.Count
    End Function
     
    Function LastAbsoluteTableRow1(rng As Range) As Long
        If rng.ListObject.ListRows.Count > 0 Then LastAbsoluteTableRow1 = rng.ListObject.DataBodyRange(rng.ListObject.ListRows.Count, 1).Row
    End Function

    Ces fonctions renverront une erreur #Valeur si la plage renseignée n'est pas en tout ou en partie dans un listobject

    Nom : 2020-11-17_110357.png
Affichages : 1260
Taille : 7,2 Ko
    "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...
    ---------------

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    839
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 839
    Par défaut
    Bonjour M. FAUCONNIER, le forum,

    C'est une réponse supersonique ultra nickel chrome.

    Merci bbbbbbbbbbbbbbbbbbbbbbbeaucoup.

  9. #9
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    1 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 1 150
    Par défaut
    Bonjour,
    Je m'intéresse au sujet de ce post qui remonte mais le vin ne se bonifie t il pas en vieillissant???....

    Serait-il possible d'intégrer un tel code dans un .xlam, en macro complémentaire, pour que tous les userform y répondent dans tous les classeurs????

  10. #10
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    1 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 1 150
    Par défaut
    J'arrive à gérer le userform du xlam depuis un fichier xlsm lambda mais le userform du xlam doit être préformaté et pourrait servir à modifier la valeur d'une cellule active du xlsm avec la valeur entrée dans le textbox du xlam, ce n'est pas très efficient....
    L'intérêt serait plus de gérer le userform d'un xlsm lambda depuis le xlam......

  11. #11
    Invité
    Invité(e)
    Par défaut
    Bonjour Kestion100

    Lorsque vous avez une question sur un sujet déjà existant, merci de créer un nouveau fil et d'y faire référence SVP

    Remonter un sujet de 2020... non mais sérieux

Discussions similaires

  1. [XL-2003] Comment avoir un calendrier commun à plusieurs TextBox
    Par MichaSarah dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 14/11/2017, 14h10
  2. [XL-2007] Groupe de Checkbox sur feuille et module de classe pour macro unique
    Par seb360 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 10/04/2012, 11h30
  3. Méthode commune à plusieurs classes
    Par rvzip64 dans le forum Langage
    Réponses: 15
    Dernier message: 08/12/2008, 14h42
  4. module de classe et textbox
    Par RemiT dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 20/12/2007, 10h06
  5. [C# 2.0 / VS 2005] Classes communes à plusieurs projets
    Par oodini dans le forum Visual Studio
    Réponses: 10
    Dernier message: 19/07/2006, 14h47

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