UserForm / Liaisons TextBox/Label/ListBox
Bonjour,
Je me permets de poster ici car je n'ai pas trouvé de solution sur internet.
Merci pour le temps que vous me consacrez.
J'utilise un UserForm. Mon problème est le suivant, j'ai :
- Une TextBox
- Un ListBox
- Un Label
qui sont liés par vba.
Les liaisons sont comme suit :
Liaisons principales
TextBox_Change -> Aide à la sélection dans la liste (La liste est beaucoup plus grande dans le programme complet)
ListBox_Change -> Copie les éléments sélectionnés dans le label
Il y a d'autres liaisons pour valider les 2 exigences suivant ce que l'utilisateur fait
J'aimerai que lorsque je choisisse un champ, TextBox.Value="" et ListBox.List = Liste complète avec les éléments présents dans le label sélectionnés. (Sans supprimer des liaisons).
Par exemple : Lancr la macro / taper m dans la TextBox / sélectionner Mathématiques
(C'est réalisé par la combinaison des touches espace et delete dans la Textbox par l'utilisateur mais j'aimerai que ce soit automatisé.)
Le problème est que ListBox_Change s'appelle de façon récursive. Avec l'utilisation d'un booléen en variable globale, ce serait sensé marcher mais la ligne
Me.ListBox1.List = vde TextBox_Change ne s'éxécute pas correctement (pas du tout en fait mais sans faire d'erreur) ce qui bloque tout le code qui suit. Pour tester, enlever la lignes b=false de
Private Sub ListBox1_Change()
If b Then
b = False
Me.TextBox1.Value = ""
b = True
UserForm_ActualiseL
UserForm_ActualiseReverseL
End If
End Subet éxécutez pas à pas.
J'ai pensé à utiliser une autre méthode : ListBox1_Click() mais elle ne marche apparemment pas pour les listes à choix multiples...
Auriez vous une solution à me proposer SVP.
Bonjour,
Le problème est que ListBox_Change s'appelle de façon récursive
Alors, utilises l'événement Click() de la ListBox plutôt que Change()
Bonjour
J'ai pensé à utiliser une autre méthode : ListBox1_Click() mais elle ne marche apparemment pas pour les listes à choix multiples...
Bonjour,
Testes si le TextBox est vide ou pas :
Private Sub TextBox1_Change()
If b Then
Dim Inc As Long, s As String
If TextBox1.Text = "" Then Exit Sub '<--- ICI tester si vide ou pas !
' Initialiser l'incrément
Inc = 0
s = Me.TextBox1.Value
Me.ListBox1.List = v 'Ligne qui fonctionne mais qui n'affecte pas l'affichage quand on enleve b=false
'(ListBox.Selected(x) renvoie donc une erreur (basé sur l'affichage)
'quand x dépasse l'indice le plus élévé affiché (fonction UserForm_ActualiseL)
' Pour chaque ligne
If Not s = "" Then
Do While Inc <= Me.ListBox1.ListCount - 1
' S'il n'existe pas de correspondance
If Not UCase(Me.ListBox1.List(Inc)) Like "*" & UCase(s) & "*" Then
' Supprimer la ligne de la combobox
Me.ListBox1.RemoveItem (Inc)
Else '''''''''''''''
' Sinon incrémenter ' Partie '
Inc = Inc + 1 ' Suggestions '
End If ' ListBox1 '
Loop '''''''''''''''
'Coche les cases en fonction du label1
UserForm_ActualiseReverseL
End If
End If
End SubBonjour,
Le fait de dupliquer le problème avec un if Textbox est vide et un else ne changera rien puisqu'il faudra tout de même modifier la liste et c'est sur ce point que ça bloque. La ligne
Me.ListBox1.List = vSurtout qu'il y a le if textbox est non vide dans le code que tu as copié.
Le problème est en gros que j'aimerai changer la liste de Listbox à l'intérieur de la méthode ListBox_Change ce qui n'est apparemment pas possible. Je ne peux pas utiliser ListBox_Click ya aucune solution du coup ?
Je rappelle que le but est que quand on sélectionne une ligne, la TextBox change de valeur et devient vide, la liste réapparaisse en entier en gardant cochée chaque ligne précédemment cochée. (label)
Bonjour,
Mets tout ton code actuel en commentaire et colles le code ci-dessous dans le module de la Form puis testes pour voir si le résultat correspond à tes attentes. Les commentaires sont dans le code mais si tu ne comprends pas quelque chose, reviens (ou si c'est moi qui est mal compris ta demande !) :
Dim Plage As Range
Dim Tbl() 'utilisation d'un tableau à deux dimensions (la 1 des Booléens et la 2 des chaines)
Dim Suspendre As Boolean
Private Sub UserForm_Initialize()
Dim I As Integer
Set Plage = Range("A1:A11")
'quand on veux supprimer, par la suite, des éléments dans une ListBox, il est préférable de la charger avec AddItem
For I = 1 To Plage.Count: ListBox1.AddItem Plage(I, 1).Value: Next I
ReDim Tbl(1 To 2, 1 To ListBox1.ListCount)
For I = 1 To UBound(Tbl, 2)
Tbl(1, I) = False: Tbl(2, I) = Plage(I, 1).Value
Next I
End Sub
Private Sub ListBox1_Change()
Dim I As Integer
Dim J As Integer
'si l'appel vient de l'événement "Change()" du TextBox saute au mot fin
If Suspendre = True Then GoTo Fin
With ListBox1
'si la liste est complète, mémorise l'état de chaque élément (coché ou non coché)
If .ListCount = UBound(Tbl, 2) Then
Tbl(1, .ListIndex + 1) = .Selected(.ListIndex)
Else
'dans le cas contraire (suppression dans la liste), effectue une recherche pour mémoriser l'état correspondant
For I = 0 To ListBox1.ListCount - 1: For J = 1 To UBound(Tbl, 2)
If Tbl(2, J) = ListBox1.List(I) Then Tbl(1, J) = ListBox1.Selected(I): Exit For
Next J, I
End If
End With
'saut ici
Fin:
'rempli le Label de toutes manières
RemplirLabel
End Sub
Private Sub TextBox1_Change()
Dim I As Integer
Dim J As Integer
ListBox1.Clear
If TextBox1.Text <> "" Then
For I = 1 To Plage.Count
If UCase(Plage(I, 1)) Like "*" & UCase(TextBox1.Text) & "*" Then ListBox1.AddItem Plage(I, 1)
Next I
Else
For I = 1 To Plage.Count: ListBox1.AddItem Plage(I, 1).Value: Next I
End If
'évite d'exécuter la procédure événementielle "Change()" de la ListBox...
Suspendre = True
'puis coche les éléments
For I = 0 To ListBox1.ListCount - 1: For J = 1 To UBound(Tbl, 2)
If Tbl(2, J) = ListBox1.List(I) And Tbl(1, J) = True Then ListBox1.Selected(I) = True
Next J, I
Suspendre = False
End Sub
Sub RemplirLabel()
Dim I As Integer
Dim J As Integer
'vide tout d'abords...
Label1.Caption = ""
'puis concatène
For I = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(I) = True Then Label1.Caption = Label1.Caption & ListBox1.List(I) & " - "
Next I
'si vide (tout à été décoché), fin !
If Label1.Caption = "" Then Exit Sub
'supprime le dernier tiret avec les deux espaces
Label1.Caption = Left(Label1.Caption, Len(Label1.Caption) - 3)
End SubBonjour,
Merci pour ta réponse.
Merci pour les améliorations que tu as apportées.
Ce n'est pas ce que je cherche mais l'utilisation du tableau Tbl en variable globale est une très bonne idée.
Je vais travailler là dessus et si j'arrive à avoir ce que je cherche, je le posterai.
Ce que je cherche c'est que lorsque l'on sélectionne un item dans la liste après avoir réduit la liste (en ayant écrit 1 caractère dans la text box par exemple), c'est que ça supprime le contenu de la text box et que la liste redevienne la plage A1:A11 avec les items précédemment sélectionnés (présents dans le label) sélectionnés.
Un problème qui n'était pas sur le classeur initial (je ne sais pas si tu pensais que c'était ça le problème) c'est que lorsqu'on sélectionne un item, puis réduit la liste et enfin resélectionne un item, le premier item sélectionné disparaît du label.
Théo
Bonjour,
Ce que je cherche c'est que lorsque l'on sélectionne un item dans la liste après avoir réduit la liste (en ayant écrit 1 caractère dans la text box par exemple), c'est que ça supprime le contenu de la text box et que la liste redevienne la plage A1:A11 avec les items précédemment sélectionnés (présents dans le label) sélectionnés.
Dans ce cas, il y a récursivité dans les événements "Change()" des deux objets et pour gérer ça, le code va devenir une usine à gaz alors que la suppression manuelle du caractère saisi dans le TextBox permet de faire ce que tu demandes (avec le code que je t'ai donné) à savoir afficher toute la liste en gardant les éléments sélectionnés !
D'accord,
C'est ça que je voulais savoir : si c'était possible à faire automatiquement.
J'en conclus donc que ce n'est pas possible.
Merci.
Théo
J'en conclus donc que ce n'est pas possible.
Non, c'est possible mais avec des variables interrupteur qui empêche les procédures "Change()" de se produire mais ça va alourdir et compliquer le code maintenant, si tu le veux vraiment, je peux me pencher dessus sachant toutes fois que je suis en congé ce soir et donc, moins devant le PC pour les 15 jours qui viennent !