TL;DR — Un
ListBoxaffiche une liste et retient ce que l'utilisateur a choisi. Remplissez-le en un coup avecListBox1.List = Range("A2:A50").Value. Lisez un choix unique avec.ListIndex(la ligne en base 0, ou-1pour rien) et.Value(le texte choisi). Le piège : dès que.MultiSelectest actif,.Valuepasse àNullet cesse de vous renseigner — vous devez parcourir.Selected(i)pour récolter chaque choix.
' ListBox a selection unique : lire l'unique choix
Private Sub cmdOK_Click()
If ListBox1.ListIndex = -1 Then
MsgBox "Please pick a name first."
Exit Sub
End If
MsgBox "You picked " & ListBox1.Value ' .Value = le texte selectionne
End Sub
Un ListBox est un contrôle sur un UserForm, et la première chose à bien saisir
est l'idée unique qui sous-tend chaque contrôle : un contrôle est un objet vivant que vous lisez à
travers ses propriétés, jamais la valeur elle-même. Les éléments vivent dans .List ; le choix de
l'utilisateur vit dans une propriété distincte — .ListIndex ou .Selected — jamais dans la boîte
prise comme un tout. Presque chaque question « mon ListBox ne renvoie rien » lit la mauvaise propriété.
Ce que vous allez apprendre
- Le modèle mental qui relie
ListBox,ComboBoxetCheckBox - Deux façons de remplir un
ListBox—.List = Range.Valueen un coup, ou.AddItemdans une boucle - Comment lire une sélection unique avec
.ListIndexet.Value, et ce que signifie-1 - Le piège numéro un :
.Valuepasse àNullsousMultiSelect, si bien que vous devez parcourir.Selected(i) - Comment vider une liste, afficher plusieurs colonnes et la lier à une feuille avec
.RowSource - Quand un
ListBoxest le bon contrôle et quand unComboBoxconvient mieux
Le modèle mental : la boîte contient la liste, une propriété contient le choix
Voyez un ListBox comme une fenêtre sur une liste d'éléments. Deux choses différentes vivent à deux
endroits différents :
ListBox1.List ' les ELEMENTS - ce qui est affiche dans la boite
ListBox1.ListIndex ' le CHOIX - quelle ligne est selectionnee (base 0, -1 = aucune)
ListBox1.Value ' le TEXTE du choix - n'a de sens qu'en selection unique
ListBox1.Selected(i) ' True/False pour la ligne i - seule lecture fiable sous MultiSelect
Cette séparation, c'est tout le contrôle. Quand vous affectez .List, vous chargez les éléments. Quand
l'utilisateur clique sur une ligne, VBA ne modifie pas .List — il modifie .ListIndex et bascule
.Selected. Ainsi « qu'a choisi l'utilisateur ? » ne trouve jamais sa réponse en regardant la liste ; on
y répond en lisant les propriétés de sélection. Fixez cela et le reste n'est que détail.
Remplir un ListBox : un coup vaut mieux qu'une boucle
Vous verrez deux façons de remplir une liste. Celle vers laquelle tendre d'abord affecte une colonne entière d'un coup :
Private Sub UserForm_Initialize()
' Remplir depuis une colonne de la feuille en une seule affectation - rapide et simple
ListBox1.List = Sheet1.Range("A2:A50").Value
End Sub
.List accepte un tableau 2D, et Range.Value est un tableau 2D (voyez VBA Range),
si bien qu'une seule ligne charge cinquante lignes. N'utilisez .AddItem que lorsque les éléments sont
calculés un à un et que vous n'avez aucun tableau sous la main :
Dim i As Long
For i = 1 To 5
ListBox1.AddItem "Quarter " & i ' ajouter des elements construits a la volee
Next i
.AddItem dans une grosse boucle est le chemin lent — chaque appel est un aller-retour distinct vers le
contrôle. Si les données sont déjà dans une plage ou un tableau, affectez .List une seule fois. Pour
vider la boîte avant de la remplir à nouveau, appelez ListBox1.Clear.
Lire une sélection unique : ListIndex et Value
Pour un ListBox ordinaire à sélection unique, deux propriétés répondent à tout. .ListIndex est le
numéro de ligne (base 0) de la sélection — et il vaut -1 quand rien n'est sélectionné, la garde que
vous devriez toujours vérifier en premier. .Value est le texte de la ligne sélectionnée :
If ListBox1.ListIndex = -1 Then
MsgBox "Nothing selected." ' -1 est le signal 'aucun choix pour l'instant'
Else
MsgBox "Row " & ListBox1.ListIndex & ": " & ListBox1.Value
End If
Vérifier .ListIndex = -1 avant de lire .Value, c'est toute la différence entre un formulaire qui guide
l'utilisateur et un formulaire qui agit sur une sélection vide. C'est la même discipline que garder un
résultat de Find avant de l'utiliser.
Le piège numéro un : MultiSelect rend .Value inutile
Voici l'erreur qui fait tourner les gens en rond. Un ListBox possède une propriété MultiSelect.
Laissez-la à sa valeur par défaut (fmMultiSelectSingle) et .Value fonctionne. Passez-la à
fmMultiSelectMulti ou fmMultiSelectExtended pour que l'utilisateur puisse cocher plusieurs lignes — et
.Value passe à Null. Elle ne reflète plus du tout la sélection, car « la valeur » n'a aucun sens
quand trois lignes sont choisies.
Sous MultiSelect, la seule lecture fiable est de parcourir chaque ligne et de tester .Selected(i) :
Dim i As Long, chosen As String
For i = 0 To ListBox1.ListCount - 1 ' les lignes vont de 0 a ListCount - 1
If ListBox1.Selected(i) Then
chosen = chosen & ListBox1.List(i) & vbCrLf
End If
Next i
MsgBox "You chose:" & vbCrLf & chosen
Deux détails font ou défont cette boucle. Elle va de 0 à .ListCount - 1, parce que les lignes sont en
base 0 tout comme les bornes de tableau — une erreur d'indice ici perd
silencieusement la dernière ligne. Et elle lit le texte de l'élément avec .List(i), non .Value, car
.Value est Null dans ce mode. Si vous avez bâti un formulaire, activé la multi-sélection plus tard, et
que votre code a cessé de voir les sélections, voilà pourquoi.
Plusieurs colonnes, et la liaison à une feuille
Deux propriétés couvrent les cas courants « il me faut plus qu'une simple liste ». .ColumnCount et
.List (un tableau 2D) permettent à un ListBox d'afficher plusieurs colonnes — un identifiant et un nom
côte à côte — tandis que .BoundColumn décide quelle colonne .Value renvoie. Et .RowSource lie la
boîte directement à une plage de feuille, de sorte qu'elle suit les cellules sans aucun code de
remplissage :
ListBox1.ColumnCount = 2
ListBox1.RowSource = "Sheet1!A2:B50" ' deux colonnes, liees en direct a la feuille
ListBox1.BoundColumn = 1 ' .Value renvoie la colonne 1 (l'ID)
.RowSource est pratique mais couple le formulaire à une disposition de feuille précise ; affecter
.List depuis un tableau garde le formulaire indépendant de l'endroit où vivent les données. Pour un
formulaire de saisie qui survit à un seul classeur, préférez l'affectation par tableau.
ListBox ou ComboBox ? Choisissez selon le ressenti du choix
Un ListBox et un ComboBox se lisent presque à l'identique, alors choisissez
sur le comportement, non la syntaxe. Tendez vers un ListBox quand les options doivent être visibles
d'un coup d'œil ou quand l'utilisateur peut en choisir plus d'une — la multi-sélection est un tour
propre au ListBox. Tendez vers un ComboBox quand la place est comptée, que la réponse est une valeur
unique, et qu'une liste déroulante repliée sur une seule ligne fait plus net. Si vous vous surprenez à
vouloir une case à cocher par ligne, c'est probablement un ListBox multi-sélection qu'il vous faut.
Comment ExcelMaster vous aide
Les deux erreurs de cette page coûtent du temps réel : lire .Value sur un ListBox multi-sélection (et
récolter Null), et agir sur une sélection sans d'abord vérifier .ListIndex = -1. Les deux sont faciles
à écrire et discrètes à échouer.
ExcelMaster vous laisse décrire le
formulaire en mots simples — « une liste de clients que l'utilisateur peut multi-sélectionner, puis écrire
les choisis dans une feuille » — et il câble le UserForm, remplit le ListBox depuis vos données, et
lit la sélection de la bonne façon (en parcourant .Selected(i) quand la multi-sélection est active, en
gardant .ListIndex sinon). Vous gardez le classeur et le code.
Questions fréquentes
Comment remplir un ListBox depuis une plage en VBA ?
Affectez la valeur de la plage à .List en une seule instruction :
ListBox1.List = Sheet1.Range("A2:A50").Value. Comme Range.Value est un tableau 2D et que .List en
accepte un, cela charge toute la colonne d'un coup. N'utilisez .AddItem que pour des éléments que vous
construisez un à un dans une boucle, et appelez .Clear d'abord si vous remplissez à nouveau une boîte
qui a déjà des lignes.
Comment obtenir l'élément sélectionné d'un ListBox en VBA ?
Pour un ListBox à sélection unique, lisez .Value pour le texte ou .ListIndex pour le numéro de ligne
(base 0) ; .ListIndex vaut -1 quand rien n'est sélectionné, alors vérifiez cela d'abord. Pour un
ListBox multi-sélection, .Value est Null — parcourez For i = 0 To ListBox1.ListCount - 1 et
collectez chaque ligne où .Selected(i) vaut True.
Pourquoi mon ListBox .Value est-il vide ou Null ?
Parce que MultiSelect est activé. Quand .MultiSelect vaut fmMultiSelectMulti ou
fmMultiSelectExtended, la propriété .Value est toujours Null — elle ne peut pas représenter
plusieurs lignes sélectionnées. Lisez plutôt la sélection en parcourant .Selected(i) de 0 à
.ListCount - 1, et lisez chaque élément avec .List(i).
Comment vider tous les éléments d'un ListBox ?
Appelez ListBox1.Clear. Cela retire chaque ligne. Si la boîte est liée avec .RowSource, mettez d'abord
.RowSource = "", car une liste liée se reconstruit depuis la plage. Pour n'effacer que la sélection
courante sans retirer les éléments, mettez .ListIndex = -1 (sélection unique) ou parcourez
.Selected(i) = False (multi-sélection).
Quelle est la différence entre un ListBox et un ComboBox ?
Un ListBox affiche plusieurs lignes à la fois et peut autoriser plusieurs sélections ; un
ComboBox se replie sur une seule ligne, affiche une liste déroulante et
n'autorise qu'un seul choix (et, en option, la saisie libre). Utilisez un ListBox quand les options
doivent être visibles ou multi-choix, un ComboBox quand la place est comptée et qu'une seule réponse
suffit.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — vérifié le 25/09/2026.
Guides associés : VBA ComboBox · VBA CheckBox · VBA UserForm · VBA Range · VBA For Loop
