Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Apprendre Working With Form Controls | Interaction Utilisateur
VBA Excel Pour l'Automatisation des Entreprises

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.

Figure 5.5

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

  1. 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.
  2. Ajouter deux CheckBoxes indépendantes (chkWelcomeEmail, chkNewsletter) et vérifier lors des tests que cocher l'une n'affecte jamais l'autre.
  3. 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).
  4. 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".
Astuce
expand arrow

1. Remplacement de cboStatus par un Frame d’OptionButtons

  • Supprimer d'abord cboStatus et 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é .Value de chaque OptionButton avec If...ElseIf — il n’existe pas de propriété unique indiquant "lequel du groupe est coché".
  • Puisque cboStatus.Value n’existe plus, cmdSave_Click a besoin d’une variable status construite à partir des OptionButtons, à écrire dans newRow à 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 à .AddItem dans UserForm_Initialize.
  • ListIndex = -1 signifie 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.
Solution
expand arrow
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 chkWelcomeEmail et chkNewsletter indé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.Value est toujours utilisé pour l’enregistrement réel (newRow.Range(1, 5)), tandis que lstCities existe 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.
Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 5. Chapitre 4

Demandez à l'IA

expand

Demandez à l'IA

ChatGPT

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.

Figure 5.5

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

  1. 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.
  2. Ajouter deux CheckBoxes indépendantes (chkWelcomeEmail, chkNewsletter) et vérifier lors des tests que cocher l'une n'affecte jamais l'autre.
  3. 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).
  4. 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".
Astuce
expand arrow

1. Remplacement de cboStatus par un Frame d’OptionButtons

  • Supprimer d'abord cboStatus et 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é .Value de chaque OptionButton avec If...ElseIf — il n’existe pas de propriété unique indiquant "lequel du groupe est coché".
  • Puisque cboStatus.Value n’existe plus, cmdSave_Click a besoin d’une variable status construite à partir des OptionButtons, à écrire dans newRow à 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 à .AddItem dans UserForm_Initialize.
  • ListIndex = -1 signifie 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.
Solution
expand arrow
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 chkWelcomeEmail et chkNewsletter indé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.Value est toujours utilisé pour l’enregistrement réel (newRow.Range(1, 5)), tandis que lstCities existe 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.
Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 5. Chapitre 4
some-alt