ComboBox en cascade

Bonjour,

J'aimerais faire une combobox en cascade dans un formulaire à partir de données d'une autre feuille. Est-ce possible?
J'ai un bouton "valider" à la fin du formulaire? Par conséquent, est-ce que je dois taper le code pour faire la combobox en cascade dans l'espace dédié au bouton valider?
Je donnerai plus d'information dès que je recevrais une réponse.
Merci d'avance

17 réponses

  1. Contributeur
    Voilà un exemple adapter à ta feuille et tes combobox, il te suffit de changer les données:

    http://www.cjoint.com/data3/3Cxsmrp1UDh.htm
    1. Bonjour

      On t'as déjà demandé plusieurs fois de poster un exemple de ton fichier, tant qu'on ne l'aura pas on ne pourra pas t'aider plus !

      Cdlmnt
      1. Ca ne fonctionne toujours pas. Mais tant pis. Merci beaucoup pour votre aide.
        1. Contributeur
          As-tu sur ton UserForm une comboBox nommée ComboBoxIngrédientAchat?

          Attention aux accents.

          Regarde l'exemple que je t'ai envoyé sur c-joint. En respectant les données dans les colonnes, tu arriveras à faire ce que tu veux. Il suffit de suivre, il y a très peu de code. Analyse bien cet exemple.

          Avec ce code tu ajoutes un item seulement, je ne pense pas que ce soit ce que tu veux!
          1. J'ai remplacé le code par:

            Private Sub ComboBoxFournisseur_Change()

            '*** A CHAQUE CHANGEMENT DE CHOIX DANS COMBOBOX1
            '*** ETABLIT LA LISTE DES ITEMS DE LA COMBOBOX2
            ' fournisseur choisi

            Dim f
            Dim i As Integer
            Dim NoAction As Boolean

            f = ComboBoxFournisseur.Value
            NoAction = True
            ComboBoxIngrédientAchat.Clear

            Dim Ligne As Long
            'derniere ligne rempli en colonne Ide BASE
            Ligne = Sheets("Fournisseurs").Columns(10).Find("*", , , , xlByColumns, xlPrevious).Row
            'Boucle sur les lignes de BASE
            For i = 4 To Ligne
            ' si fournisseur choisi on ajoute l'ingredient de cette ligne à combobox2
            If Sheets("Fournisseurs").Range("J" & i) = f Then
            ComboBoxIngrédientAchat.AddItem Sheets("Fournisseurs").Range("K" & i)
            End If
            Next i

            ComboBoxIngrédientAchat.ListIndex = 0
            SendKeys "^(F4)"
            NoAction = False

            End Sub

            Mais il y a maintenant un problème au niveau de ComboBoxIngrédientAchat.Clear. Je reçois un message "erreur non répertoriée".
            1. Contributeur
              Il faudrait quand même connaître les bases. La déclaration des variables.
              NoAction = True
              Quand une variable renvoie True ou False, c'est une variable Booleenne, il faut donc la déclarer en tant que tel. Et non pas la déclarer avec un nom fantaisiste:
              Dim NoAction As Action

              Un petit rappel:

              https://silkyroad.developpez.com/VBA/LesVariables/
              1. Trop cool ça marche! Vous êtes un génie!
                Par contre, la 2ème partie du code ne fonctionne pas. J'ai essayé avec votre code, ça ne fonctionnait pas. Du coup, je l'ai modifié comme ceci :

                Private Sub ComboBoxFournisseur_Change()

                '*** A CHAQUE CHANGEMENT DE CHOIX DANS COMBOBOX1
                '*** ETABLIT LA LISTE DES ITEMS DE LA COMBOBOX2
                ' fournisseur choisi

                Dim f
                Dim i As Integer
                Dim NoAction As Action

                f = ComboBoxFournisseur.Value
                NoAction = True
                ComboBoxIngrédientAchat.Clear

                Dim Ligne As Long
                'derniere ligne rempli en colonne Ide BASE
                Ligne = Sheets("Fournisseurs").Columns(10).Find("*", , , , xlByColumns, xlPrevious).Row
                'Boucle sur les lignes de BASE
                For i = 4 To Ligne
                ' si fournisseur choisi on ajoute l'ingredient de cette ligne à combobox2
                If Sheets("Fournisseurs").Range("J" & i) = f Then
                ComboBoxIngrédientAchat.AddItem Sheets("Fournisseurs").Range("K" & i)
                End If
                Next i

                ComboBoxIngrédientAchat.ListIndex = 0
                SendKeys "^(F4)"
                NoAction = False

                End Sub

                mais il y a un problème au niveau de "NoAction=True)
                1. Contributeur
                  Pour supprimer les 2 items:

                  Option Explicit
                  Private Sub deleteitem(monnom As String)
                  Dim i As Integer
                  Dim nom As String
                   For i = 0 To ComboBoxFournisseur.ListCount - 1
                    nom = ComboBoxFournisseur.List(i)
                  If nom = monnom Then
                   ComboBoxFournisseur.removeitem (i)
                  Exit Sub
                  End If
                      Next i
                  End Sub
                  Private Sub UserForm_Initialize()
                  Dim j As Integer
                   Dim Ligne As Long
                     'derniere ligne rempli en colonne I de Fournisseurs
                  Ligne = Sheets("Fournisseurs").Columns(9).Find("*", , , , xlByColumns, xlPrevious).Row
                   'Boucle sur les lignes de Fournisseurs
                  For j = 2 To Ligne 'on commence en ligne 2 car titre en I1
                   ComboBoxFournisseur = Sheets("Fournisseurs").Range("I" & j)
                   '...et filtre les doublons
                   If ComboBoxFournisseur.ListIndex = -1 Then ComboBoxFournisseur.AddItem Sheets("Fournisseurs").Range("I" & j)
                   Next j
                   ComboBoxFournisseur.ListIndex = 0
                   deleteitem ("Fournisseur inexistant")
                  deleteitem ("Nom et Prénom")
                  End Sub
                  

                  1. Avec votre code, ça affiche : "erreur d'exécution '70':accès refusé"...
                    1. Non c'est bon! merci beaucoup, ça marche pour la première partie ! je vais tester la deuxième partie du code. Seulement, pour la première partie, j'aimerai rajouter une condition : ne pas prendre la case lorsqu'il y a marqué "Nom et Prénom"(titre de la colonne), mais aussi lorsqu'il y a marqué "Fournisseur inexistant". Est-il possible de rajouter du code pour ça ? Merci d'avance !!
                  2. Contributeur
                    Tu n'as pas bien recopier l'exemple de via 55. Ce n'est quand même pas trop compliqué!

                    Private Sub UserForm_Initialize()
                    Dim j As Integer
                     Dim Ligne As Long
                       'derniere ligne rempli en colonne I de Fournisseurs
                    Ligne = Sheets("Fournisseurs").Columns(9).Find("*", , , , xlByColumns, xlPrevious).Row
                     'Boucle sur les lignes de Fournisseurs
                    For j = 2 To Ligne 'on commence en ligne 2 car titre en I1
                     ComboBoxFournisseur = Sheets("Fournisseurs").Range("I" & j)
                     '...et filtre les doublons
                     If ComboBoxFournisseur.ListIndex = -1 Then ComboBoxFournisseur.AddItem Sheets("Fournisseurs").Range("I" & j)
                     Next j
                     ComboBoxFournisseur.ListIndex = 0
                    End Sub
                    


                    On attend la suite!
                    1. Bonjour,

                      Merci pour votre dévouement.
                      J'ai essayé la première partie du code que vous avez posté en l'adaptant à mes données, ce qui donne :

                      Private Sub UserForm_Initialize()

                      '*** A INITIALISATION DE UF
                      '**** ETABLIT LA LISTE DES ITEMS DE COMBOBOX1
                      Dim j As Integer
                      Dim Ligne As Long
                      Dim ComboBoxFournisseur As Object
                      Ligne = Sheets("Fournisseurs").Columns(9).Find("J4:J" & Range("J10000").End(xlUp).Row)
                      'Récupère les données de la colonne Ide BASE
                      For j = 1 To Ligne 'on commence en ligne 1 car titre en J3
                      ComboBoxFournisseur = Sheets("Fournisseurs").Range("I" & j)
                      '...et filtre les doublons
                      If ComboBoxFournisseur.ListIndex = -1 Then ComboBoxFournisseur.AddItem Sheets("Fournisseurs").Range("I" & j)
                      Next j

                      End Sub

                      MAIS il y a un problème : lorsque j'exécute, un message d'erreur s'affiche : "Erreur d'exécution '91': Variable objet ou variable de bloc With non définie". Je n'arrive pas à trouver ce qu'il manque dans le code, pouvez-vous m'aider ?
                      1. Bonsoir à tous

                        @Melissa
                        Ce serait plus simple si au lieu de morceaux de codes tu envoyais un fichier complet comme demandé
                        Ceci dit il te faut 2 macros :
                        - l'une qui à l'initialisation de l'Userform alimente le 1er combo avec les fournisseurs à partir de la colonne I de ta feuille de donnée (que j'ai nommée BASE dans la macro)
                        Private Sub UserForm_Initialize()
                        '*** A INITIALISATION DE UF
                        '**** ETABLIT LA LISTE DES ITEMS DE COMBOBOX1
                            Dim j As Integer
                            Dim Ligne As Long
                            'derniere ligne rempli en colonne I de BASE
                        Ligne = Sheets("BASE").Columns(9).Find("*", , , , xlByColumns, xlPrevious).Row
                            'Récupère les données de la colonne Ide BASE
                            For j = 2 To Ligne 'on commence en ligne 2 car titre
                                ComboBox1 = Sheets("BASE").Range("I" & j)
                                '...et filtre les doublons
                                If ComboBox1.ListIndex = -1 Then ComboBox1.AddItem Sheets("BASE").Range("I" & j)
                            Next j
                        End Sub
                        

                        - l'autre qui à chaque modification de choix dans le Combobox 1 alimente le 2eme combo avec les ingrédients pris en colonne J si correspondance de fournisseur en colonne I . J'ai adaptée celle de Le Pivert (que je salue au passage) dans ce sens :
                        Private Sub ComboBox1_Change()
                        '*** A CHAQUE CHANGEMENT DE CHOIX DANS COMBOBOX1
                        '*** ETABLIT LA LISTE DES ITEMS DE LA COMBOBOX2
                        ' fournisseur choisi
                        f = ComboBox1.Value
                            NoAction = True
                            ComboBox2.Clear
                            Dim Ligne As Long
                            'derniere ligne rempli en colonne Ide BASE
                        Ligne = Sheets("BASE").Columns(9).Find("*", , , , xlByColumns, xlPrevious).Row
                         'Boucle sur les lignes de BASE
                            For i = 2 To Ligne
                            ' si fournisseur choisi on ajoute l'ingredient de cette ligne à combobox2
                            If Sheets("BASE").Range("I" & i) = f Then
                                ComboBox2.AddItem Sheets("BASE").Range("J" & i)
                                End If
                            Next i
                            
                            ComboBox2.ListIndex = 0
                            SendKeys "^(F4)"
                            NoAction = False
                          
                        End Sub


                        Dans l'editeur VBA Clic droit sur l'Userform dans l'arborescence et Code pour afficher la page où coller les macros (en les adaptant si nécessaire)

                        Cdlmnt
                        1. Merci pour votre réponse mais je ne parviens toujours pas à coder. De plus, il faudrait d'abord que quand je choisisse mon fournisseur, il ne soit pas proposé plusieurs fois. En effet, vu que dans mon tableau, les fournisseurs apparaissent plusieurs fois, c'est le cas aussi dans la combobox.
                          Que faire?
                          J'ai chercher plusieurs astuces sur internet : elles partent toutes de Private Sub Userform_Initialize(). Sauf qu'il n'apparaît nulle part dans mon code et quand je le tape il détecte une erreur de validation des données.
                          1. Voici mon code actuel :
                            Private Sub CmdValider_Click()

                            Dim ctrl As Control, ctrlerr As Control
                            Dim erreur As Boolean

                            For Each ctrl In frmAchats.Controls
                            erreur = False
                            If TypeOf ctrl Is MSForms.TextBox Then
                            If ctrl.Text = "" Then
                            erreur = True
                            Set ctrlerr = ctrl
                            Exit For
                            End If
                            End If
                            Next ctrl

                            If erreur = True Then
                            MsgBox "Vous n'avez pas rempli toutes les zones"
                            ctrlerr.SetFocus
                            Set ctrlerr = Nothing
                            Else

                            If txtDateAchat.Value <> "" Then
                            If Not IsDate(txtDateAchat.Value) Then
                            MsgBox "Date incorrecte.", vbCritical + vbOKOnly, "Erreur"
                            txtDateAchat.Value = ""
                            txtDateAchat.SetFocus
                            frmAchats.Hide
                            frmAchats.Show

                            Else
                            txtDateAchat.Value = Format(txtDateAchat.Value, "dd/mm/yyyy")
                            End If
                            End If

                            With frmAchats

                            Dim nblig As Integer
                            Dim nbcol As Integer
                            nbcol = 1
                            nblig = 9
                            Do Until IsEmpty(Cells(nblig, nbcol))
                            nblig = nblig + 1
                            Loop

                            Dim dernière_ligne As Integer
                            dernière_ligne = Range("A1").End(xlDown).Row
                            Dim TabAchats()
                            ReDim TabAchats(dernière_ligne + 1, 0)

                            feuille.Range("Achats!A" & nblig).Value = .txtDateAchat.Value
                            feuille.Range("Achats!B" & nblig).Value = .ComboBoxIngrédientAchat.Value
                            feuille.Range("Achats!D" & nblig).Value = .txtQuantité.Value
                            feuille.Range("Achats!E" & nblig).Value = .ComboBoxFournisseur.Value
                            feuille.Range("Achats!H" & nblig).Value = .txtCoûtTransport.Value

                            End With
                            frmAchats.Hide
                            End If

                            End Sub
                        2. Contributeur
                          Bonjour,

                          Voici un exemple:

                          http://www.cjoint.com/data3/3CvossSb0GZ.htm
                          1. Ok. Donc j'ai créé un formulaire pour faire l'inventaire d'achats d'ingrédients sur une année. Dans ce formulaire, on peut rentrer :
                            -la date d'achat
                            -le fournisseur (son numéro)
                            -l'ingrédient
                            -la quantité
                            -le coût du transport
                            Le fournisseur(numéro) et l'ingrédient sont en combobox.
                            Il y a un bouton "valider" et un bouton "quitter" la fin.

                            Sur une autre feuille, j'ai dans un tableau :
                            -en colonne I le numéro du fournisseur
                            -en colonne J son ingrédient
                            Comme un fournisseur peut vendre plusieurs ingrédients, il y a plusieurs fois le même numéro de fournisseur en I.
                            Aussi, comme un ingrédient peut avoir plusieurs fournisseurs, le même ingrédient peut être répété plusieurs fois en J mais avec des num de fournisseurs en I différents.

                            Par conséquent, lors d'un achat, j'aimerais pouvoir d'abord choisir le fournisseur dans la 1ère combobox. Puis, dans la 2è combobox, j'aimerais que s'affichent SEULEMENT les ingrédients que ce fournisseur livre.

                            Jusqu'à présent, je taper la majorité du code dans :Private Sub CmdValider_Click(). J'avais juste une petite partie à part pour le bouton "quitter". J'ai lu plusieurs tutos sur internet à propos des combobox en cascade, mais je n'arrive pas à les adapter à mon cas.

                            Pouvez-vous m'aider s'il vous plait? J'espère que vous avez pu comprendre même si je sais que mes explications ne sont pas très claires.