Combobox en cascade avec saisie intuitive semie automatique
Bonjour à tous !
Je suis tout nouveau dans le monde du VBA, et je m'arrache les cheveux sur un petit problème
Mes connaissances en VBA sont encore très faible, mais j'ai réussi à bien avancer tout de même ^^
J'ai dans un classeur, plusieurs onglets contenant dans chacun d'eux une base de donnée relatifs aux prix d'entreprises différentes avec :
en A : Une catégorie de travaux
en B : La désignation des travaux
en C : Prix pour une zone 1
en D : Prix pour une zone 2
etc ...
Mon But pour l'instant est d'avoir une liste déroulante pour choisir l'entreprise (ça c'est fait)
Un liste déroulante pour choisir la région (C'est fait)
Un comboBox qui contient toutes les grandes catégories des travaux (la colone A des bases de données sans doublon) , relatif à l'entreprise choisit (C'est fait ! )
Pour ça j'ai créé une fonction matricielle pour créé une colonne "Catégorie sans doublon", maintenant je vois que c'est possible de le faire directement dans la ComboBox, je le ferais plus tard car cela fonctionne très bien pour le moment.
Avec saisie semi automatique et recherches des lettres nimporte où, pas juste en début de phrase.
Et la où je bloque :
Un ComboBox2 qui va, en fonction de l'entrerise choisi, et de la catégorie de travaux choisis, faire la liste des désignation des travaux possibles (Colone B lorsque colone A = Combobox1)
J'y suis presque arrivé, mais il y a un problème dès que j’essaie de mettre la saisie semie automatique !
Voici la code de la page au complet : (je suis VRAIMENT débutant, de quelques jours ^^, toutes remarques sera bien prise
Dim a()
Dim b()
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Range("Tableau7[Categorie]"), Target) Is Nothing And Target.Count = 1 Then
If Cells(Target.Row, Target.Column - 2).Value = "Ent1" Then
a = Application.Transpose(Sheets("Ent1").Range("Tableau16"))
ElseIf Cells(Target.Row, Target.Column - 2).Value = "Ent2" Then
a = Application.Transpose(Sheets("Ent2").Range("N1FMB"))
ElseIf Cells(Target.Row, Target.Column - 2).Value = "Ent3" Then
a = Application.Transpose(Sheets("Ent3").Range("Tableau5"))
ElseIf Cells(Target.Row, Target.Column - 2).Value = "Ent4" Then
a = Application.Transpose(Sheets("Ent4").Range("Tableau6"))
Else
Exit Sub
End If
Me.ComboBox1.List = a
Me.ComboBox1.Height = Target.Height + 3
Me.ComboBox1.Width = Target.Width
Me.ComboBox1.Top = Target.Top
Me.ComboBox1.Left = Target.Left
Me.ComboBox1 = Target
Me.ComboBox1.Visible = True
Me.ComboBox1.Activate
'Me.ComboBox1.DropDown ' ouverture automatique au clic dans la cellule
Else
Me.ComboBox1.Visible = False
End If
If Not Intersect(Range("Tableau7[Designation]"), Target) Is Nothing And Target.Count = 1 Then
ComboBox2.Clear
Dim FL1 As Range, NoCol As Integer
Dim NoLig As Long, Var As Variant, Var2 As Variant
Set FL1 = Sheets("Ent1").Range("Tableau11")
NoCol = 1 'lecture de la colonne 1
iii = 0
jjj = 0
For NoLig = 1 To Split(FL1.Address, "$")(4)
Var = FL1.Cells(NoLig, NoCol)
Var2 = FL1.Cells(NoLig, NoCol + 1)
If Cells(Target.Row, Target.Column - 1) = Var Then
ComboBox2.AddItem Var2
End If
Next
Set FL1 = Nothing
Me.ComboBox2.Height = Target.Height + 3
Me.ComboBox2.Width = Target.Width
Me.ComboBox2.Top = Target.Top
Me.ComboBox2.Left = Target.Left
Me.ComboBox2 = Target
Me.ComboBox2.Visible = True
Me.ComboBox2.Activate
'Me.ComboBox1.DropDown ' ouverture automatique au clic dans la cellule
Else
Me.ComboBox2.Visible = False
End If
End Sub
Private Sub ComboBox1_Change()
If Me.ComboBox1 <> "" And IsError(Application.Match(Me.ComboBox1, a, 0)) Then
Set d1 = CreateObject("Scripting.Dictionary")
tmp = "*" & UCase(Me.ComboBox1) & "*"
For Each c In a
If UCase(c) Like tmp Then d1(c) = ""
Next c
Me.ComboBox1.List = d1.keys
Me.ComboBox1.DropDown
End If
ActiveCell.Value = Me.ComboBox1
End Sub
Private Sub ComboBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Me.ComboBox1.List = a
Me.ComboBox1.Activate
Me.ComboBox1.DropDown
End Sub
Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then ActiveCell.Offset(1).Select
End Sub
Private Sub ComboBox2_Change()
If Me.ComboBox2 <> "" And IsError(Application.Match(Me.ComboBox2, Me.ComboBox2.List, 0)) Then
Set d1 = CreateObject("Scripting.Dictionary")
tmp = "*" & UCase(Me.ComboBox1) & "*"
For Each c In Me.ComboBox2.List
If UCase(c) Like tmp Then d1(c) = ""
Next c
Me.ComboBox2.List = d1.keys
Me.ComboBox2.DropDown
End If
ActiveCell.Value = Me.ComboBox2
End Sub
Private Sub ComboBox2_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Me.ComboBox2.Activate
Me.ComboBox2.DropDown
End Sub
Private Sub ComboBox2_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then ActiveCell.Offset(1).Select
End SubVoila Voila, je triture ça depuis un moment, mais j'ai toujours un bug avec
Private Sub ComboBox2_Change()
Je pense que c'est
Me.ComboBox2.List qui pose problème dans tout le Sub, mais je ne sais pas pourquoi.
Me.ComboBox2.List = d1.keys > autorisation denied
Soit j'arrive à afficher la bonne liste combobox2, mais la saisie auto ne fonctionne pas.
Soit j'arrive à la faire fonctionner, mais dès que je choisi un élément de la liste, ça plante
Je ,e pourrai répondre que ce soir
A+ !
Et merci !
Bonjour,
Exemple avec 3 niveaux intuitifs
Boisgontier
Merci pour ta réponse rapide !
En effet, dans le tableur en exemple, j'y arrive ^^
Mais le soucis est qu'il faut nommer chaque xsous-zones" ! Ma BD est bien trop grande pour cela :-/
D'où le fait que j'utilise une boucle For avec AddItem pour remplir ma combobox2, ce qui résous une partie du problème.
Mais du coup, je n'arrive pas à faire, comme dans ton exemple :
Choix2 = transpose.application (Range(xxx).Value)
Puisqu'il n'y a pas de range definit.
Je pense que le problème vient de la, mais je bloque :-/
Il ne faut pas utiliser AddItem qui est lent mais .List ou .Column
J'ai un pgm de recherche intuitif sur 36.000 communes.
http://boisgontierjacques.free.fr/fichiers/Formulaire/CommunesCP.zip
Boisgontier
Merci ,
J'ai modifié pas mal mon code, je n'utilise plus les .addItem ni les fonctions matricielles d'ailleurs pour supprimer les doublons
Il me reste un dernier (j’espère) bug lorsque j'utilise Application.Transpose, et que certaines cellules contiennent plus de 256 caractères.
D'ailleurs, j'ai eu un mal de chien à identifier le problème
Je vois que le sujet a été abordé à divers endroit sur internet, mais je n'arrive à faire fonctionner aucunes des solutions pour le moment, je continu de chercher ^^
Mais si quelqu'un a la solution, je suis preneur
Bonjour,
Si c'est Transpose qui est le problème,il suffit de ne pas l'utiliser.
Boisgontier
Bonjour Merwis, Bonjour Jacques Boisgontier,
A toutes fins utiles, une proposition qui compile certainement plusieurs codes prélevés à droite et à gauche, il doit y avoir un zeste puissant de JacquesBoigintier, du Quicksort, du Scripting.Dictionary, et du ListObjects (tableaux) ... donc rapide (charge le tableau d'un seul coup), supprime les doublons avec dico, et trie la liste
La présentation est un userform mais je pense avoir aussi travaillé directement sur la feuille excel comme JacquesBoigontier le propose.
L'autre version ... ce ne sont pas des combobox ici mais des listes de validation.
Const nbZones = 8
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim data() As Variant
Dim choix() As Variant
Dim dico As Object
Dim i&, iData&, iZone&, plus&
If Target.Count <> 1 Then Exit Sub
plus = Target.Row - 1
If plus = 0 Then Exit Sub
ReDim choix(1 To nbZones)
For i = 1 To nbZones
choix(i) = Range("zone" & i).Offset(plus, 0).Value
If Not Intersect(Range("zone" & i).Offset(plus, 0), Target) Is Nothing Then
data = [TabData].Value
Set dico = CreateObject("Scripting.Dictionary")
For iData = 1 To UBound(data)
flag = True
If i > 1 Then
For iZone = 1 To i - 1
If choix(iZone) <> CStr(data(iData, iZone)) Then flag = False
Next
End If
If flag Then dico(CStr(data(iData, i))) = ""
Next iData
If dico.Count > 0 Then
Target.Validation.Delete
Target.Validation.Add xlValidateList, Formula1:=Join(dico.keys, ",")
End If
Exit For
End If
Next i
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count <> 1 Then Exit Sub
plus = Target.Row - 1
If plus = 0 Then Exit Sub
For i = 1 To nbZones
If Not Intersect(Range("zone" & i).Offset(plus, 0), Target) Is Nothing Then
If i < nbZones Then
Application.EnableEvents = False
For iZone = i + 1 To nbZones
With Range("zone" & iZone).Offset(plus, 0)
.Value = ""
.Validation.Delete
End With
Next
Application.EnableEvents = True
End If
Exit For
End If
Next
End SubC'est complètement paramétré.
Le tableau de base doit s'appeler TabData
Une constante en début de macro définit le nombre de colonnes, ici 8
Les en-têtes de colonnes de la page dans laquelle s'affichent les listes déroulantes doivent s'appeler zone1, zone2 etc ...
Voir l'exemple ci-après
Et bonjour ^^
J'ai réglé le soucis avec le .transpose, enfin, je l'ai simplement esquivé en réduisant le nombre de caractères à moins de 255 par cellule
J'ai maintenant un beau "Erreur d’exécution 70 : Permission refusée"
avec une erreur sur Me.ComboBox2.List = d2.keys
Et cette fois je sèche complétement, le code semble correcte par rapport à tout ce que vous m'avez envoyé.
De plus, l'erreur se produit sur Me.ComboBox2.List = d2.keys mais pas sur Me.ComboBox1.List = d1.keys ... Bizarre
J'ai essayé de changer le nom des variables, au cas ou ... mais je ne vois pas :/
De plus, lorsque j'efface Me.ComboBox2.List = d2.keys (pour tester), on voit que la ComboBox2 se remplit bien avec les bons éléments (mais plus de recherche intuitive du coup)
Dim a()
Dim b()
Dim AddN1 As Range
Dim AddN2 As Range
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Range("Tableau7[Categorie]"), Target) Is Nothing And Target.Count = 1 Then
If Cells(Target.Row, Target.Column - 2).Value = "ent1" Then
Set AddN1 = Sheets("ent1").Range("Tableau11[N1]")
ElseIf Cells(Target.Row, Target.Column - 2).Value = "ent2" Then
Set AddN1 = Sheets("ent2").Range("Tableau1[N1]")
ElseIf Cells(Target.Row, Target.Column - 2).Value = "ent3" Then
Set AddN1 = Sheets("ent3").Range("Tableau3[N1]")
ElseIf Cells(Target.Row, Target.Column - 2).Value = "ent4" Then
Set AddN1 = Sheets("Ent4").Range("Tableau4[N1]")
Else
Exit Sub
End If
Set MonDico = CreateObject("Scripting.Dictionary")
On Error Resume Next
For Each C In AddN1
If C <> "" Then
MonDico.Add C.Value, C.Value
End If
Next C
Tablo = Application.Transpose(MonDico.items)
a = Tablo
Me.ComboBox1.List = a
Me.ComboBox1.Height = Target.Height + 3
Me.ComboBox1.Width = Target.Width
Me.ComboBox1.Top = Target.Top
Me.ComboBox1.Left = Target.Left
Me.ComboBox1 = Target
Me.ComboBox1.Visible = True
Me.ComboBox1.Activate
'Me.ComboBox1.DropDown ' ouverture automatique au clic dans la cellule
Else
Me.ComboBox1.Visible = False
End If
If Not Intersect(Range("Tableau7[Designation]"), Target) Is Nothing And Target.Count = 1 Then
If Cells(Target.Row, Target.Column - 3).Value = "ent1" Then
Set AddN1 = Sheets("ent1").Range("Tableau11[N1]")
ElseIf Cells(Target.Row, Target.Column - 3).Value = "ent2" Then
Set AddN1 = Sheets("Fent2").Range("Tableau1[N1]")
ElseIf Cells(Target.Row, Target.Column - 3).Value = "ent3" Then
Set AddN1 = Sheets("ent3").Range("Tableau3[N1]")
ElseIf Cells(Target.Row, Target.Column - 3).Value = "ent4" Then
Set AddN1 = Sheets("ent4").Range("Tableau4[N1]")
Else
Exit Sub
End If
Set MonDico2 = CreateObject("Scripting.Dictionary")
For Each C In AddN1
If C.Value = Target.Offset(O, -1).Value Then
MonDico2.Add C.Offset(0, 1).Value, C.Offset(0, 1).Value
End If
Next C
Tablo = Application.Transpose(MonDico2.items)
b = Tablo
Me.ComboBox2.List = b
Me.ComboBox2.Height = Target.Height + 3
Me.ComboBox2.Width = Target.Width
Me.ComboBox2.Top = Target.Top
Me.ComboBox2.Left = Target.Left
Me.ComboBox2 = Target
Me.ComboBox2.Visible = True
Me.ComboBox2.Activate
Else
Me.ComboBox2.Visible = False
End If
End SubPrivate Sub ComboBox1_Change()
If Me.ComboBox1 <> "" And IsError(Application.Match(Me.ComboBox1, a, 0)) Then
Set d1 = CreateObject("Scripting.Dictionary")
tmp = "*" & UCase(Me.ComboBox1) & "*"
For Each C In a
If UCase(C) Like tmp Then d1(C) = ""
Next C
Me.ComboBox1.List = d1.keys
Me.ComboBox1.DropDown
End If
ActiveCell.Value = Me.ComboBox1
End Sub
Private Sub ComboBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Me.ComboBox1.List = a
Me.ComboBox1.Activate
Me.ComboBox1.DropDown
End Sub
Private Sub ComboBox2_Change()
If Me.ComboBox2 <> "" Then
Set d2 = CreateObject("Scripting.Dictionary")
cle = "*" & UCase(Me.ComboBox2) & "*"
For Each C In b
If UCase(C) Like cle Then d2(C.Value) = ""
Next C
Me.ComboBox2.List = d2.keys
Me.ComboBox2.DropDown
End If
ActiveCell.Value = Me.ComboBox2
End Sub
Private Sub ComboBox2_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Me.ComboBox2.List = b
Me.ComboBox2.Activate
Me.ComboBox2.DropDown
End SubBonjour,
Quelqu'un aurrait une idée de ce qui pourrait causer "Erreur d’exécution 70 : Permission refusée" ?
Même juste une piste, je tourne en rond
Je peux poster le fichier Excel en question si besoin
MonDico.Add C.Value, C.ValueEssaie plutôt :
MonDico(C.Value)=""sinon prend le code que je t'ai proposé...