Avec 2 ComboBox, afficher la sélection dans ListBox
Bonjour à tous,
Je viens vers vous pour des problèmes sur le formulaire TousLesDevis, onglet Devis de mon fichier ci-joint en fin de message.
A grand peine, j'ai réussi à faire que la première ComboBox fonctionne, et encore, la sélection ne s'opère pas pour un cas isolé.
et je je n'arrive pas à faire le code pour la seconde (ComboBoxStatut) sans tout désorganiser/bloquer.
La première combobox ( ComboBoxNomPrenom) sélectionne bien les noms et affiche les devis contenus dans la ListBoxTousLesDevis, mais ne le fait pas si la personne n'a qu'un seul devis.
Le codage provient d'un exemple trouvé sur ce forum que j'ai adapté comme j'ai pu. voir le sujet
J'ai du mettre en commentaire la ligne 139 de mon formulaire TousLesDevis sinon j'avais un blocage.
' If Not CTRL.Name = "ComboBoxNomPrenom" Then CTRL.Value = R.Cells(LI, CByte(CTRL.Tag)).ValueJ'ai bien vu un message de ThauThème auquel je n'ai rien compris à propos des Tag et des colonnes. voir le message dans le même sujet
Voici le projet que je souhaiterais obtenir dans ce formulaire
Merci d'avance de votre aide
Private Sub ComboBoxStatut_Change()
'**************************
' sélectionne les devis existants selon leur statut, 2ème colonne,
'**************************
' // Les statuts peuvent avoir 2 valeurs : Ouvert, Verrouillé. onglet Liste F12 et F13
' // Affiche/masque les devis existants dans la ListBoxTousLesDevis selon leur statut, 2ème colonne,
' // La combo box peut faire afficher 3 valeurs de tri : Ouvert, Verrouillé, Tous (les Verrouillés ET les Ouverts). onglet Liste H12, H13 et H14
' // Si le Devis est Verrouillé, la ligne dans la ListBoxTousLesDevis sera rouge code couleur &H000000FF&
End SubPour ouvrir le formulaire, il faut cliquer sur "Voir tous les devis" :)
Il me semble avoir vu qu'il était préférable de sélectionner le tableau struturé lui-même plutôt que l'onglet.
J'ai essayé avec "Range " mais je n'y suis pas parvenu.
si quelqu'un peut m'indiquer le bon codage, svp . Merci d'avance.
Set R = Sheets("Devis") 'définit l'onglet R (Devis)
' Set R = Range("TableauDevis") ' définit le Tableau structuré TableauDevisTrois remarques :
1) Paramétrez votre éditeur avec l'obligation de déclarer toutes vos variables
2) De mémoire, vous ne pouvez pas mettre un tableau dans un Dictionnary. Il faut créer 2 dicos : D1 pour les Noms et Prénoms et D2 pour les statuts.
3) Il y a une erreur de syntaxe sur la ligne
TV = R.Range("B7:F" & R.Cells(Application.Rows.Count, 2).End(xlUp).Row)Remplacez-la par :
TV = R.Range("B7:F" & R.Range("B" & Rows.Count).End(xlUp).Row)Si vous tenez aux dicos, essayez ceci :
Private Sub UserForm_Initialize() 'à l'initialisation de l'USerform
Dim D1 As Object 'déclare la variable D1 (Dictionnaire)
Dim D2 As Object 'déclare la variable D2 (Dictionnaire)
Dim I As Integer 'déclare la variable I (Incrément)
' Me.ListBoxTousLesDevis.ColumnCount = 6 'définit le nombre de colonnes de la ListBoxTousLesDevis
' Me.ListBoxTousLesDevis.ColumnWidths = "0" 'masque la première colonne de la ListBoxTousLesDevis (N° de ligne, largueur 35
' Me.ListBoxTousLesDevis.ColumnWidths = "35;150;80;150;160;30" ' 35 pt;150 pt;80 pt;150 pt;160 pt;30 pt
Set R = Sheets("Devis") 'définit l'onglet R (Devis)
' Set R = Range("tableauDevis") ' définit le Tableau structuré TableauDevis
Set L = Sheets("Listes") 'définit l'onglet L (Listes)
Set D1 = CreateObject("Scripting.Dictionary") 'définit le dictionnaire D1
Set D2 = CreateObject("Scripting.Dictionary") 'définit le dictionnaire D2
'TV = R.Range("B7:F" & R.Cells(Application.Rows.Count, 2).End(xlUp).Row) 'définit la tableau des valeurs TV (les 5 premières colonnes en partant de la ligne 7...)
TV = R.Range("B7:F" & R.Range("B" & Rows.Count).End(xlUp).Row)
For I = 1 To UBound(TV, 1) ' boucle sur toutes les lignes I du tableau des valeurs TV
' alimente le dictionnaire D avec Nom/espace/Prenom de chaque ligne I
' D(TV(I, 2) & " " & TV(I, 3)) = TV(I, 2) & " " & TV(I, 3) ' cas du fichier ModifierSupprimer.xlm
D1(TV(I, 1)) = TV(I, 1)
D2(TV(I, 2)) = TV(I, 2)
Next I ' ligne suivante de la boucle
Me.ComboBoxNomPrenom.List = D1.Keys 'alimente la ComboBoxNomPrenom avec la liste du dictionnaire D sans doublon
Me.ComboBoxStatut.List = D2.Keys 'alimente la ComboBoxNomPrenom avec la liste du dictionnaire D sans doublon
' Me.ComboBoxStatut.List = L.Range("H12:H" & L.Cells(Application.Rows.Count, 6).End(xlUp).Row).Value 'alimente la ComboBoxStatut( 6 = colonne H dans l'onglet Listes)
LI = R.Cells(Application.Rows.Count, 2).End(xlUp).Row + 1 'définit la ligne LI (première ligne vide de la colonne B : NomPrenom)
' Me.CB_CompleterDevis.Visible = True 'affiche le bouton "Compléter ce devis"
' Me.CB_supprimer.Visible = False 'masque le bouton "Supprimer"
End SubJ'ai laissé toutes vos remarques, ne sachant pas ce que vous voulez faire ensuite.
un essai
Bonjour à tous
Oups! Pas mis la bonne version et j'ai effacé la bonne
Re,
Et voilà la bonne version.
Une version "à ma sauce" sans dictionary. Le code est commenté. j'ai remplacé la combobox du choix des statuts par 3 contrôles option.
Tout est basé sur la procédure ListeDevisClient qui se charge d'actualiser la listbox des devis en fonction du client sélectionné et du statut coché.
Sub ListeDevisClient() ' Actualise la liste des devis pour le client choisi et le statut choisi
Dim client As String, statut As String, der As Long, t, i As Long, j As Long, ok As Boolean
ListBoxTousLesDevis.Clear ' on vide la liste des devis
If ComboBoxNomPrenom.ListIndex = -1 Then Exit Sub ' aucun client choisi -> on quitte
client = ComboBoxNomPrenom.List(ComboBoxNomPrenom.ListIndex) ' nom du client sélectionné
If Opt1 = True Then statut = "Ouvert" Else If Opt2 = True Then statut = "Verrouillé" ' valeur du statut à chercher
der = Sheets("Devis").Cells(Rows.Count, "b").End(xlUp).Row ' dernière ligne de la colonne B
t = Sheets("devis").Columns("a:f").Resize(der) ' tableau source étendu (à partir de la ligne 1 de la feuille "Devis"
' Filtrage des devis sources
For i = 7 To UBound(t) ' boucle sur le tableau t (à partir de la ligne 7 -> 1ère ligne des devis)
If t(i, 2) = client Then ' si c'est un devis du client recherché
If InStr(t(i, 3), statut) > 0 Then ' si le devis a le bon statut
' on ajoute une ligne dans la liste avec le N° de ligne de devis au sein de la feuille de calcul "Devis"
ListBoxTousLesDevis.AddItem i
' on complète par les autres éléments de la ligne
k = ListBoxTousLesDevis.ListCount - 1 ' index de la ligne ajoutée
For j = 2 To 6: ListBoxTousLesDevis.List(k, j - 1) = t(i, j): Next ' ajout des autres éléments de la ligne k
End If
End If
Next i
End Sub
Private Sub ComboBoxNomPrenom_Change()
' on passe au statut "Tous" si ce n'est le cas (ça déclenchera Opt3_Click() et donc l'actualisation)
' si le statut est déjà à true alors on appellera directement l'actualisation de la liste (via ListeDevisClient() )
If Opt3 = False Then Opt3 = True Else ListeDevisClient
End Sub
Private Sub Opt1_Click() ' clique sur Opt1 ("Ouvert")
ListeDevisClient ' actualisation de la liste
End Sub
Private Sub Opt2_Click() ' clique sur Opt2 ("Verrouillé")
ListeDevisClient ' actualisation de la liste
End Sub
Private Sub Opt3_Click() ' clique sur Opt3 ("Tous")
ListeDevisClient ' actualisation de la liste
End SubBonjour,
J'ai vu qu'Optimix a corrigé ton problème de sélection.
Une autre proposition.
Je n'ai pas modifié le visuel mais on pourrait mettre une liste pour les statuts et la mise à jour de la liste des devis dynamiquement sur la valeur cliquée dans cette liste. Il n'y a que 3 statuts.
Les nomsprénoms sont classés alphabétiquement.
La liste des devis se met à jour automatiquement selon le chois des combobox.
Le format du n° des lignes est avec les séparateurs de milliers.
Le format des montants est avec les séparateurs de milliers et en 2 décimales.
Je t'ai dégagé les erreurs de saisie quand l'utilisateur mets des " " devant et/ou derrière les nomsprénoms et/ou le statut (pas de modification de tes données. Uniquement dans le code de traitement du formulaire).
Pas de distinction de casse dans les nomsprenoms et les statuts.
Teste et dis nous.
Alors tout d'abord un grand merci à tous de m'avoir proposé ces solutions.
La version proposée par @mafraise a une esthétique et une ergonomie plus pertinente que ce que je soumettais, grâce aux boutons Option et un joli encadré. (je vais ouvrir le formulaire pour voir comment tu as fais ça.
Je vais donc tenter une modification pour pouvoir afficher les devis selon leur statut sans avoir de NomPrenom de sélectionné.
La Version de Bart (@BsAlv) fonctionne bien aussi.
Bien vu le message quand aucun devis n'est trouvé avec le statut sélectionné. Merci
@Optimix Comme je le disais dans mon post, j'ai repris un code existant pour un autre projet qui ne m'appartient pas. Je ne tiens pas
particulièrement au dictionnaire. Je vais m’imprégner du code proposé pour d'autres formulaires, si besoin.
J'ai bien noté les observation quant aux erreurs de ligne mentionnées. Merci
La version d' @Alex buggue dès qu'on choisi un nom. Dommage.
Ça ne doit pas être grand chose, mais je n'ai pas réussi à trouver la ligne fautive. Le codage est... impressionnant.
Je vais également tenter de reprendre les lignes qui permettent les formatages des prix.
version d'Alex.
Pardon
Il te suffit d'ajouter
Dim Index_2_tablo_affichage as long
Tout en haut avec les autres dim pour déclarer cette variable
Je vais donc tenter une modification pour pouvoir afficher les devis selon leur statut sans avoir de NomPrenom de sélectionné.
Voici avec la correction.
Et pour me faire pardonner, puisque apparemment c'est la version de mafraise que tu préfères
esthétique et une ergonomie plus pertinente que ce que je soumettais, grâce aux boutons Option et un joli encadré
tout en regrettant la non prise en compte du format des nombres avec 2 décimales et le séparateur de milliers
Je vais également tenter de reprendre les lignes qui permettent les formatages des prix.
, voici sa version modifiée (sans vouloir t'offenser d'être intervenu mafraise). Je n'ai rien touché d'autre à ce fichier.
A toi quand même de relire et surtout comprendre les codes et méthodologies proposés.
Bonjour à tous,
me revoici après ce long week-end.
J'ai tant bien que mal réussi à intégrer les OptionButton à la place de la seconde ComboBox des statuts.
J'ai tenté de le faire depuis le fichier de Bart (BsAlv) car il correspondait mieux à la méthode de tri.
C'est à dire, tout afficher dès l'ouverture du formulaire, puis affiner selon que l'on veuille sélectionner sur le statut ou le nom du client.
Je suis parvenu à faire afficher tous les devis, mais impossible de faire le tri.
Je suis parvenu à mettre des couleurs sur les OptionButtton, sans peine. Mais bon, c'est peu de chose.
J'ai aussi tenté d'appliquer le formatage des nombres, sans résultat, je n'arrive pas à récupérer la variable des lignes de la ListBox.
J'ai tout essayé, sans succès.
Du coup, j'ai mis les lignes en commentaire.
Merci d'avance de votre aide.
Bonjour papicx
Pour mon fun
- Private Sub UserForm_Initialize()
- Private Sub cmdTous_Click()
- Private Sub Opt1_Click()
- Private Sub Opt2_Click()
- Private Sub Opt3_Click()
- Sub RemplirListeDevis()
- Sub FormaterNombre()
J'ai ajouté un petit commandBouton "*" pour afficher les devis de tous les clients
La suppression des doublons nomprenom n'utilise plus une syntaxe spécifique aux dernières versions de Excel.
On formate uniquement les colonnes de nombres que l'on désire (pour le classeur joint, ce sont les colonnes 1 et 6). Dans FormaterNombre() , on indiquera dans la variable tNumcol les numéros de colonnes à formater (en commençant à 1) et dans la variable tFormat les formats à appliquer pour chaque colonne. Les nombres seront alignés à droite. Pour cela, il faut obligatoirement que la police de la ListBoxTousLesDevis soit une police à espacement fixe (ceci est réalisé à l'initialisation du UserForm).
J'ai modifié la couleur de l'option "Tous" pour qu'elle soit plus visible à mes yeux (goût personnel, c'est de la cosmétique maison
edit 19/12/2025 10h42 : version v2a
..
Re papicx
papicx à dit :
je n'arrive pas à récupérer la variable des lignes de la ListBox
Considérons une Listbox à N lignes et M colonnes.
Listbox.List va être un tableau (array) avec N lignes et M colonnes contenant les données de la liste.
Mais si dans la vie courante, on parle des lignes de 1 à N et des lignes de 1 à M, il en va autrement pour cette propriété .List.
En effet, les index des lignes de .List commencent toujours à 0 (et se terminent à N-1) et les index des colonnes de .List commencent toujours à 0 (et se terminent à M-1).
Donc si vous cherchez la variable de la ligne i et de la colonne j, c'est .List(i-1, j-1). i-1 est l'index de la i ème ligne et j-1 est l'index de la j ème colonne.
Exemple : On veut afficher tous les numéros de ligne de la Listbox (ceux en colonne 1). On écrira :
For i = 0 to maListe.Listcount-1 ' les index commencent à 0 et se terminent donc au (nombre de lignes -1)
msgbox maListe.List(i,0) ' la colonne numéro 1 a pour index 0 (1-1)
next iMême pour des utilisateurs chevronnés, l'étourderie et la précipitation peuvent encore aboutir à faire la confusion...
...
Bonjour mafraise,
Un grand MERCI pour cette proposition qui est un peu plus compréhensible pour l'ultra novice que je suis.
J'ai ajouté qq corrections pour la cosmétique.
mis en commentaires des lignes de cosmétique des boutons qui semblent inutiles.
Merci pour la couleur de "Tous"
Tu expliques que les nombres sont alignés à droite. ce qui serait une bonne chose.
Comme tu peux le voir sur la capture, grâce aux titres des colonnes affichés, columnHeads mis à "True" ça ne semble pas être le cas.
Je dois partir faire des commissions, je reviens cet am.
Re
papicx a dit:
Tu expliques que les nombres sont alignés à droite. ce qui serait une bonne chose.
Comme tu peux le voir sur la capture, grâce aux titres des colonnes affichés, columnHeads mis à "True" ça ne semble pas être le cas.
Il faut savoir que les contrôles ListBox n'ont pas été conçus pour adapter individuellement l'alignement de leurs colonnes. En général, on use de pis-aller qui font plus ou moins bien le travail.
Dans notre cas, j'ai passé la listbox des devis en police à espacement fixe et pour chacune des colonnes 1 et 6, j'ai formaté leurs nombres de telle sorte qu'au sein de la même colonne, ces nombre aient tous le même nombre de caractères et que les caractères de remplissage (des espaces) soient à gauche et le nombre formaté à droite. Ce qui est sûr, c'est que les textes représentant ces nombres ont tous le même nombre de caractères.
On a donc à gauche de chaque nombre des caractères de remplissage (des espaces en nombre variables) suivi du nombre formaté. Le nombre d'espaces + le nombre de caractères du nombre formaté est constant au sein d'une colonne. Ceci permet d'aligner les nombres les un en dessous des autres avec superposition de la virgule nonobstant le fait que la colonne n'est pas explicitement alignée à droite (mais les nombres le sont).
C'est ce qui m'a fait employer l'expression "aligné à droite" un peu abusivement.
On pourrait sans doute faire mieux à grand renfort de lignes de code et en faisant appel à des API du système Windows. Mais il ne faut pas oublier le but premier du projet qui est la gestion des devis et non pas une esthétique parfaite qui ne contribue absolument en rien au but ultime du projet. Quand l'esthétique est acceptable, il vaut mieux se consacrer à la réalisation du projet que de perdre de l'énergie pour de la cosmétique inutile et resté 'scotché" dans des détails qui ne contribuent en rien au succès du projet (et c'est du vécu). C'est mon opinion et je la partage (c'est le minimum syndical)
Bon, vous trouvez en pièce jointe la dernière version avec un alignement "pseudo à droite" (je le confesse - mea culpa
nota : quant à "columnHeads", je crois bien que je ne l'ai jamais utilisé
Bonjour mafraise,
Ceci permet d'aligner les nombres les un en dessous des autres avec superposition de la virgule nonobstant le fait que la colonne n'est pas explicitement alignée à droite (mais les nombres le sont).
Oui, ça je l'ai vu et l'essentiel est que les nombres le sont.
Quand l'esthétique est acceptable, il vaut mieux se consacrer à la réalisation du projet que de perdre de l'énergie pour de la cosmétique inutile et resté 'scotché" dans des détails qui ne contribuent en rien au succès du projet (et c'est du vécu).
Oui, bien sûr. On est d'accord sur ce point.
nota : quant à "columnHeads", je crois bien que je ne l'ai jamais utilisé. C'est une propriété qui ne m'a jamais inspiré...
En fait, je m'en sers juste pour voir concrètement les largeurs des colonnes et centrer à peu près les titres. Ensuite, je la remets sur False.
Merci beaucoup de ton aide.
Je mets ci-dessous une capture d'écran pour les lecteurs du sujet, qu'ils puissent voir de quoi on parle.
Re,
papicx à dit :
En fait, je m'en sers juste pour voir concrètement les largeurs des colonnes et centrer à peu près les titres. Ensuite, je la remets sur False.
C'est une astuce que je vais adopter
bonjour papicx, salut mafraise,
je n'ai pas lu tout ce que vous avez écrit ici, mais une mise à jour du tri avec ces bouton "option"
Merci Bart,
Vos 2 propositions sont exactement ce que je demandais, et même plus. Seule les approches par le code sont bien différentes.
Néanmoins, j'ai déjà choisi la version de mafraise.
J'y ai ajouté le message d'information quand il n'y a pas de devis au statut recherché pour un client.
J'aurai encore besoin de tes compétences pour un autre formulaire où les images seront à intégrer au formulaire.
J'espère que c'est bon ainsi. En tout cas, ça fonctionne.
Sub RemplirListeDevis()
Dim NomPrenom$, filtre$, tsDevis As ListObject, auxCombo As New MSForms.Control
Dim t, i&, j&, n&
NomPrenom = Me.ComboBoxNomPrenom ' le nomprenom sélectionné
If Opt1.Value = True Then ' si'option 1 est choisie le filtre est "Ouvert"
filtre = "Ouvert"
ElseIf Opt2.Value = True Then ' si'option 2 est choisie le filtre est "Verrouillé"
filtre = "Verrouillé"
Else ' sinon le filtre est "*"
filtre = "*"
End If
ListBoxTousLesDevis.Clear ' on vide la liste
t = Range("tableauDevis") ' lecture du tableau des devis
For i = 1 To UBound(t) ' boucle sur le tableau des devis
' si le nomprenom du devis est celui qui est sélectionné et si son staut est le bon
If (t(i, 1) = NomPrenom Or NomPrenom = "") And t(i, 2) Like filtre & "*" Then
ListBoxTousLesDevis.AddItem Range("tableauDevis").Row + i - 1 ' alors on ajoute le N° de ligne (feuille de calcul) du devis
n = ListBoxTousLesDevis.ListCount - 1 ' n est la ligne de la listbox du devis qu'on vient d'ajouter
For j = 1 To 5: ListBoxTousLesDevis.List(n, j) = t(i, j): Next j ' on complète les colonnes suivantes
End If
Next i
FormaterNombre ' la liste est remplie, on formate les totaux des devis
If j = 0 Then ' si aucun match
MsgBox "Aucun devis ne correspond à cette sélection.", vbExclamation: Me.ListBoxTousLesDevis.Clear
End If
End SubMerci bien.