Working With Form Controls
Glissez pour afficher le menu
TextBoxes et ComboBoxes couvrent la plupart des saisies de données, mais certains autres contrôles expriment certains types de choix de manière plus naturelle — et lire correctement leurs valeurs comporte quelques pièges importants à connaître avant de s’y fier.
CheckBoxes
La propriété Value d’une CheckBox est un simple booléen — True lorsqu’elle est cochée, False sinon :
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent here."
End If
Chaque CheckBox sur un formulaire est totalement indépendante des autres — cocher chkWelcomeEmail n’a aucun effet sur chkNewsletter, ce qui est exactement le comportement souhaité lorsque les choix ne sont pas mutuellement exclusifs.
OptionButtons
Les OptionButtons fonctionnent à l’inverse : dans un même groupe, en sélectionner un décoche automatiquement tous les autres — exactement ce dont les choix de Statut de la capture d’écran ont besoin, puisqu’un client ne peut pas être à la fois Actif et Inactif. Pour savoir lequel est sélectionné, il faut vérifier la valeur de chacun individuellement :
Dim status As String
If optActive.Value = True Then
status = "Active"
ElseIf optInactive.Value = True Then
status = "Inactive"
ElseIf optProspect.Value = True Then
status = "Prospect"
End If
L’exclusivité mutuelle est automatique et entièrement gérée par VBA — il n’est jamais nécessaire d’écrire du code pour décocher les deux autres lorsqu’un est sélectionné. Le regroupement est important : les OptionButtons ne s’excluent mutuellement qu’à l’intérieur du même conteneur (le formulaire lui-même, ou un contrôle Frame placé dessus), donc deux groupes distincts d’OptionButtons sur le même formulaire — par exemple, Statut et Priorité — doivent être placés dans deux Frames différentes, sinon VBA les traiterait tous comme un seul groupe mutuellement exclusif.
ListBoxes
Une ListBox affiche plusieurs choix en même temps sans avoir besoin d’être déroulée, comme la liste City dans la Figure 5.5. Elle se remplit de la même manière qu’une ComboBox, avec .AddItem, et la sélection se lit via .Value ou .ListIndex :
Private Sub UserForm_Initialize()
lstCities.AddItem "Chicago"
lstCities.AddItem "Boston"
lstCities.AddItem "Austin"
End Sub
Private Sub cmdAssign_Click()
If lstCities.ListIndex = -1 Then
MsgBox "Please select a city first."
Exit Sub
End If
MsgBox "Assigning to: " & lstCities.Value
End Sub
ListIndex correspond à la position de l’élément sélectionné, en commençant à 0 pour le premier élément — et, point crucial, il vaut -1 lorsqu’aucun élément n’a encore été sélectionné, ce qui permet à cmdAssign_Click de détecter un utilisateur qui clique sur le bouton sans avoir choisi de ville. .Value donne directement le texte sélectionné, ce qui est généralement plus utile que la position numérique fournie par .ListIndex.
Multi-Page Forms
Un contrôle MultiPage (les onglets Détails / Préférences en haut de la Figure 5.5) regroupe des contrôles liés sur des pages séparées d’un même formulaire physique — utile lorsqu’un formulaire comporte trop de champs pour tenir confortablement sur un seul écran. Chaque page est adressée par sa position, et seuls les contrôles de la page actuellement visible sont pertinents pour l’utilisateur, même si tous existent et peuvent être lus par le code, quelle que soit la page affichée :
Private Sub MultiPage1_Change()
If MultiPage1.Value = 1 Then
MsgBox "Now viewing Preferences"
End If
End Sub
MultiPage1.Value suit le même comptage à partir de 0 que ListIndex — la première page est 0, la seconde (Préférences, dans la Figure 5.5) est 1 — et l’événement Change se déclenche automatiquement chaque fois que l’utilisateur clique sur un autre onglet.
Tâche
- Ajouter un Frame contenant trois OptionButtons (optActive, optInactive, optProspect) à frmAddCustomer, en remplaçant l'ancien ComboBox cboStatus, et écrire le bloc If...ElseIf montré ci-dessus pour lire la sélection.
- Ajouter deux CheckBoxes indépendantes (chkWelcomeEmail, chkNewsletter) et vérifier lors des tests que cocher l'une n'affecte jamais l'autre.
- Ajouter une ListBox (lstCities) remplie dans UserForm_Initialize, et écrire un contrôle qui affiche une erreur si l'utilisateur essaie de continuer sans rien sélectionner (ListIndex = -1).
- Défi : regrouper les champs Company Name, Contact et Email sur une page MultiPage nommée "Details", et les CheckBoxes et OptionButtons sur une seconde page nommée "Preferences".
1. Remplacement de cboStatus par un Frame d’OptionButtons
- Supprimer d'abord
cboStatuset son Label du formulaire — vous le remplacez, vous ne l’ajoutez pas en plus. - Glisser un contrôle Frame sur le formulaire, puis glisser les trois OptionButtons à l’intérieur des limites du Frame — ce regroupement les rend mutuellement exclusifs en tant que groupe.
- Renommer chaque OptionButton individuellement dans la fenêtre Propriétés ; le Frame peut garder une Caption simple comme "Status" mais n’a pas besoin d’un nom adapté au code sauf si vous souhaitez le référencer directement.
- Lire la sélection signifie vérifier individuellement la propriété
.Valuede chaque OptionButton avecIf...ElseIf— il n’existe pas de propriété unique indiquant "lequel du groupe est coché". - Puisque
cboStatus.Valuen’existe plus,cmdSave_Clicka besoin d’une variablestatusconstruite à partir des OptionButtons, à écrire dansnewRowà la place.
2. Ajout de deux CheckBoxes indépendantes
- Elles sont placées directement sur le formulaire (pas dans le Frame) — des CheckBoxes hors d’un même conteneur ne s’affectent jamais mutuellement, peu importe le regroupement.
- Pour "confirmer lors des tests", il suffit d’en cocher une, puis l’autre, et de vérifier qu’aucune ne décoche la première.
3. Ajout et validation d’une ListBox
- La remplir de la même façon que
cboCity— appels répétés à.AddItemdansUserForm_Initialize. ListIndex = -1signifie qu’aucun élément n’a encore été sélectionné — c’est exactement la condition à vérifier avant d’autoriser l’enregistrement.- Ce contrôle appartient au même bloc de validation que les autres champs obligatoires, en ajoutant à la même chaîne
errors.
4. Défi MultiPage
- Glisser un contrôle MultiPage sur le formulaire — il comporte deux pages par défaut, ce qui correspond exactement à vos besoins.
- Renommer chaque page via un clic droit → Ordre des pages, ou en sélectionnant l’onglet de la page et en utilisant le champ Caption de la fenêtre Propriétés (Caption contrôle le texte visible de l’onglet ; il existe aussi un champ (Name) si vous souhaitez référencer une page par son nom dans le code).
- Déplacer des contrôles existants sur une page signifie les glisser physiquement sur la zone visible de cette page en mode Création — les références dans le code ne changent pas, car le nom d’un contrôle ne dépend pas de la page sur laquelle il se trouve.
Private Sub UserForm_Initialize()
cboCity.AddItem "Chicago"
cboCity.AddItem "Boston"
cboCity.AddItem "Austin"
cboCity.AddItem "Seattle"
cboCity.AddItem "Denver"
lstCities.AddItem "Chicago"
lstCities.AddItem "Boston"
lstCities.AddItem "Austin"
lstCities.AddItem "Seattle"
lstCities.AddItem "Denver"
End Sub
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdSave_Click()
Dim tbl As ListObject
Dim newRow As ListRow
Dim errors As String
Dim status As String
' --- Reset field colors ---
txtCompanyName.BackColor = vbWhite
txtContact.BackColor = vbWhite
txtEmail.BackColor = vbWhite
' --- Required field checks ---
If Trim(txtCompanyName.Value) = "" Then
errors = errors & "- Company Name is required" & vbNewLine
txtCompanyName.BackColor = RGB(255, 199, 206)
End If
If Trim(txtContact.Value) = "" Then
errors = errors & "- Contact is required" & vbNewLine
txtContact.BackColor = RGB(255, 199, 206)
End If
If Trim(txtEmail.Value) = "" Then
errors = errors & "- Email is required" & vbNewLine
txtEmail.BackColor = RGB(255, 199, 206)
End If
' --- Status via OptionButtons ---
If optActive.Value = True Then
status = "Active"
ElseIf optInactive.Value = True Then
status = "Inactive"
ElseIf optProspect.Value = True Then
status = "Prospect"
Else
errors = errors & "- Please select a Status" & vbNewLine
End If
' --- ListBox check ---
If lstCities.ListIndex = -1 Then
errors = errors & "- Please select a city from the list" & vbNewLine
End If
If errors <> "" Then
MsgBox "Please fix the following:" & vbNewLine & errors, vbExclamation
Exit Sub
End If
' --- All checks passed — safe to save now ---
Set tbl = ThisWorkbook.Worksheets("Customers").ListObjects("tblCustomers")
Set newRow = tbl.ListRows.Add
newRow.Range(1, 1).Value = "C0" & (tbl.ListRows.Count + 100)
newRow.Range(1, 2).Value = txtCompanyName.Value
newRow.Range(1, 3).Value = txtContact.Value
newRow.Range(1, 4).Value = txtEmail.Value
newRow.Range(1, 5).Value = cboCity.Value
newRow.Range(1, 6).Value = status
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent to " & txtEmail.Value & "."
End If
MsgBox txtCompanyName.Value & " was added successfully."
Unload Me
End Sub
Notes de test :
- Le point 2 (CheckBoxes) n’a pas de validation dédiée — il suffit de cliquer sur
chkWelcomeEmailetchkNewsletterindépendamment et de vérifier que chaque case s’active sans affecter l’autre. - Le point 4 (MultiPage) est uniquement un changement de mise en page — aucun changement de code n’est nécessaire au-delà de ce qui est déjà présent, car chaque contrôle conserve son nom quel que soit l’onglet où il est placé.
- Remarquez que
cboCity.Valueest toujours utilisé pour l’enregistrement réel (newRow.Range(1, 5)), tandis quelstCitiesexiste uniquement comme contrôle séparé, validé indépendamment selon la consigne — les deux ne sont pas liés sauf si vous choisissez de l’étendre vous-même.
Merci pour vos commentaires !
Demandez à l'IA
Demandez à l'IA
Posez n'importe quelle question ou essayez l'une des questions suggérées pour commencer notre discussion
Working With Form Controls
TextBoxes et ComboBoxes couvrent la plupart des saisies de données, mais certains autres contrôles expriment certains types de choix de manière plus naturelle — et lire correctement leurs valeurs comporte quelques pièges importants à connaître avant de s’y fier.
CheckBoxes
La propriété Value d’une CheckBox est un simple booléen — True lorsqu’elle est cochée, False sinon :
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent here."
End If
Chaque CheckBox sur un formulaire est totalement indépendante des autres — cocher chkWelcomeEmail n’a aucun effet sur chkNewsletter, ce qui est exactement le comportement souhaité lorsque les choix ne sont pas mutuellement exclusifs.
OptionButtons
Les OptionButtons fonctionnent à l’inverse : dans un même groupe, en sélectionner un décoche automatiquement tous les autres — exactement ce dont les choix de Statut de la capture d’écran ont besoin, puisqu’un client ne peut pas être à la fois Actif et Inactif. Pour savoir lequel est sélectionné, il faut vérifier la valeur de chacun individuellement :
Dim status As String
If optActive.Value = True Then
status = "Active"
ElseIf optInactive.Value = True Then
status = "Inactive"
ElseIf optProspect.Value = True Then
status = "Prospect"
End If
L’exclusivité mutuelle est automatique et entièrement gérée par VBA — il n’est jamais nécessaire d’écrire du code pour décocher les deux autres lorsqu’un est sélectionné. Le regroupement est important : les OptionButtons ne s’excluent mutuellement qu’à l’intérieur du même conteneur (le formulaire lui-même, ou un contrôle Frame placé dessus), donc deux groupes distincts d’OptionButtons sur le même formulaire — par exemple, Statut et Priorité — doivent être placés dans deux Frames différentes, sinon VBA les traiterait tous comme un seul groupe mutuellement exclusif.
ListBoxes
Une ListBox affiche plusieurs choix en même temps sans avoir besoin d’être déroulée, comme la liste City dans la Figure 5.5. Elle se remplit de la même manière qu’une ComboBox, avec .AddItem, et la sélection se lit via .Value ou .ListIndex :
Private Sub UserForm_Initialize()
lstCities.AddItem "Chicago"
lstCities.AddItem "Boston"
lstCities.AddItem "Austin"
End Sub
Private Sub cmdAssign_Click()
If lstCities.ListIndex = -1 Then
MsgBox "Please select a city first."
Exit Sub
End If
MsgBox "Assigning to: " & lstCities.Value
End Sub
ListIndex correspond à la position de l’élément sélectionné, en commençant à 0 pour le premier élément — et, point crucial, il vaut -1 lorsqu’aucun élément n’a encore été sélectionné, ce qui permet à cmdAssign_Click de détecter un utilisateur qui clique sur le bouton sans avoir choisi de ville. .Value donne directement le texte sélectionné, ce qui est généralement plus utile que la position numérique fournie par .ListIndex.
Multi-Page Forms
Un contrôle MultiPage (les onglets Détails / Préférences en haut de la Figure 5.5) regroupe des contrôles liés sur des pages séparées d’un même formulaire physique — utile lorsqu’un formulaire comporte trop de champs pour tenir confortablement sur un seul écran. Chaque page est adressée par sa position, et seuls les contrôles de la page actuellement visible sont pertinents pour l’utilisateur, même si tous existent et peuvent être lus par le code, quelle que soit la page affichée :
Private Sub MultiPage1_Change()
If MultiPage1.Value = 1 Then
MsgBox "Now viewing Preferences"
End If
End Sub
MultiPage1.Value suit le même comptage à partir de 0 que ListIndex — la première page est 0, la seconde (Préférences, dans la Figure 5.5) est 1 — et l’événement Change se déclenche automatiquement chaque fois que l’utilisateur clique sur un autre onglet.
Tâche
- Ajouter un Frame contenant trois OptionButtons (optActive, optInactive, optProspect) à frmAddCustomer, en remplaçant l'ancien ComboBox cboStatus, et écrire le bloc If...ElseIf montré ci-dessus pour lire la sélection.
- Ajouter deux CheckBoxes indépendantes (chkWelcomeEmail, chkNewsletter) et vérifier lors des tests que cocher l'une n'affecte jamais l'autre.
- Ajouter une ListBox (lstCities) remplie dans UserForm_Initialize, et écrire un contrôle qui affiche une erreur si l'utilisateur essaie de continuer sans rien sélectionner (ListIndex = -1).
- Défi : regrouper les champs Company Name, Contact et Email sur une page MultiPage nommée "Details", et les CheckBoxes et OptionButtons sur une seconde page nommée "Preferences".
1. Remplacement de cboStatus par un Frame d’OptionButtons
- Supprimer d'abord
cboStatuset son Label du formulaire — vous le remplacez, vous ne l’ajoutez pas en plus. - Glisser un contrôle Frame sur le formulaire, puis glisser les trois OptionButtons à l’intérieur des limites du Frame — ce regroupement les rend mutuellement exclusifs en tant que groupe.
- Renommer chaque OptionButton individuellement dans la fenêtre Propriétés ; le Frame peut garder une Caption simple comme "Status" mais n’a pas besoin d’un nom adapté au code sauf si vous souhaitez le référencer directement.
- Lire la sélection signifie vérifier individuellement la propriété
.Valuede chaque OptionButton avecIf...ElseIf— il n’existe pas de propriété unique indiquant "lequel du groupe est coché". - Puisque
cboStatus.Valuen’existe plus,cmdSave_Clicka besoin d’une variablestatusconstruite à partir des OptionButtons, à écrire dansnewRowà la place.
2. Ajout de deux CheckBoxes indépendantes
- Elles sont placées directement sur le formulaire (pas dans le Frame) — des CheckBoxes hors d’un même conteneur ne s’affectent jamais mutuellement, peu importe le regroupement.
- Pour "confirmer lors des tests", il suffit d’en cocher une, puis l’autre, et de vérifier qu’aucune ne décoche la première.
3. Ajout et validation d’une ListBox
- La remplir de la même façon que
cboCity— appels répétés à.AddItemdansUserForm_Initialize. ListIndex = -1signifie qu’aucun élément n’a encore été sélectionné — c’est exactement la condition à vérifier avant d’autoriser l’enregistrement.- Ce contrôle appartient au même bloc de validation que les autres champs obligatoires, en ajoutant à la même chaîne
errors.
4. Défi MultiPage
- Glisser un contrôle MultiPage sur le formulaire — il comporte deux pages par défaut, ce qui correspond exactement à vos besoins.
- Renommer chaque page via un clic droit → Ordre des pages, ou en sélectionnant l’onglet de la page et en utilisant le champ Caption de la fenêtre Propriétés (Caption contrôle le texte visible de l’onglet ; il existe aussi un champ (Name) si vous souhaitez référencer une page par son nom dans le code).
- Déplacer des contrôles existants sur une page signifie les glisser physiquement sur la zone visible de cette page en mode Création — les références dans le code ne changent pas, car le nom d’un contrôle ne dépend pas de la page sur laquelle il se trouve.
Private Sub UserForm_Initialize()
cboCity.AddItem "Chicago"
cboCity.AddItem "Boston"
cboCity.AddItem "Austin"
cboCity.AddItem "Seattle"
cboCity.AddItem "Denver"
lstCities.AddItem "Chicago"
lstCities.AddItem "Boston"
lstCities.AddItem "Austin"
lstCities.AddItem "Seattle"
lstCities.AddItem "Denver"
End Sub
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdSave_Click()
Dim tbl As ListObject
Dim newRow As ListRow
Dim errors As String
Dim status As String
' --- Reset field colors ---
txtCompanyName.BackColor = vbWhite
txtContact.BackColor = vbWhite
txtEmail.BackColor = vbWhite
' --- Required field checks ---
If Trim(txtCompanyName.Value) = "" Then
errors = errors & "- Company Name is required" & vbNewLine
txtCompanyName.BackColor = RGB(255, 199, 206)
End If
If Trim(txtContact.Value) = "" Then
errors = errors & "- Contact is required" & vbNewLine
txtContact.BackColor = RGB(255, 199, 206)
End If
If Trim(txtEmail.Value) = "" Then
errors = errors & "- Email is required" & vbNewLine
txtEmail.BackColor = RGB(255, 199, 206)
End If
' --- Status via OptionButtons ---
If optActive.Value = True Then
status = "Active"
ElseIf optInactive.Value = True Then
status = "Inactive"
ElseIf optProspect.Value = True Then
status = "Prospect"
Else
errors = errors & "- Please select a Status" & vbNewLine
End If
' --- ListBox check ---
If lstCities.ListIndex = -1 Then
errors = errors & "- Please select a city from the list" & vbNewLine
End If
If errors <> "" Then
MsgBox "Please fix the following:" & vbNewLine & errors, vbExclamation
Exit Sub
End If
' --- All checks passed — safe to save now ---
Set tbl = ThisWorkbook.Worksheets("Customers").ListObjects("tblCustomers")
Set newRow = tbl.ListRows.Add
newRow.Range(1, 1).Value = "C0" & (tbl.ListRows.Count + 100)
newRow.Range(1, 2).Value = txtCompanyName.Value
newRow.Range(1, 3).Value = txtContact.Value
newRow.Range(1, 4).Value = txtEmail.Value
newRow.Range(1, 5).Value = cboCity.Value
newRow.Range(1, 6).Value = status
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent to " & txtEmail.Value & "."
End If
MsgBox txtCompanyName.Value & " was added successfully."
Unload Me
End Sub
Notes de test :
- Le point 2 (CheckBoxes) n’a pas de validation dédiée — il suffit de cliquer sur
chkWelcomeEmailetchkNewsletterindépendamment et de vérifier que chaque case s’active sans affecter l’autre. - Le point 4 (MultiPage) est uniquement un changement de mise en page — aucun changement de code n’est nécessaire au-delà de ce qui est déjà présent, car chaque contrôle conserve son nom quel que soit l’onglet où il est placé.
- Remarquez que
cboCity.Valueest toujours utilisé pour l’enregistrement réel (newRow.Range(1, 5)), tandis quelstCitiesexiste uniquement comme contrôle séparé, validé indépendamment selon la consigne — les deux ne sont pas liés sauf si vous choisissez de l’étendre vous-même.
Merci pour vos commentaires !