TL;DR — Chaque contrôle d'un UserForm vit à un seul endroit : la collection
Controlsdu formulaire. Atteignez-la avecMe.Controls, parcourez-la avecFor Each, et adressez n'importe quel contrôle par son nom sous forme de chaîne —Me.Controls("txtName"). C'est cette collection qui garde court un formulaire de vingt champs : une boucle au lieu de vingt lignes nommées. Filtrez les contrôles que vous visez avecTypeNameouTypeOf, car la collection contient aussi des étiquettes, des cadres et des boutons.
Private Sub cmdClear_Click()
Dim ctl As MSForms.Control
' Vider chaque zone de texte du formulaire en une seule boucle:
For Each ctl In Me.Controls
If TypeOf ctl Is MSForms.TextBox Then ctl.Value = ""
Next ctl
End Sub
Vous atteignez un contrôle en tapant son nom : txtName.Value, lstItems.Clear. Cela fonctionne quand
vous connaissez le contrôle au moment d'écrire le code. La collection Controls sert au cas où vous ne le
connaissez pas — vous voulez chaque zone de texte, ou un contrôle dont le nom a été construit à
l'exécution. C'est le pivot de la famille des contrôles UserForm, et les trois guides ici la complètent.
La collection Controls est la façon d'adresser les contrôles en masse ; une TextBox
renvoie toujours une String, si bien qu'un nombre saisi reste du texte tant que vous ne le convertissez
pas ; et un Frame est le conteneur qui donne à un ensemble de boutons radio son
propre groupe. Maîtrisez la collection, la chaîne et le conteneur, et les contrôles individuels —
ListBox, ComboBox, CheckBox —
se lisent tous de la même façon : un contrôle est un objet que vous atteignez via le formulaire et auquel
vous parlez à travers ses propriétés.
Ce que vous allez apprendre
- Ce qu'est
Me.Controls, et pourquoi un formulaire est une collection plutôt qu'un écran - Parcourir chaque contrôle avec
For Eachet agir sur ceux que vous visez - Filtrer par type avec
TypeNameetTypeOfpour ignorer les étiquettes et les cadres - Atteindre un contrôle par son nom sous forme de chaîne, pour des formulaires construits depuis des données
- Ajouter des contrôles à un formulaire pendant qu'il tourne
- Le choix de jugement : quand une boucle vaut mieux que vingt références nommées
Le modèle mental : un formulaire est une collection d'objets contrôles
Un UserForm ressemble à un écran, mais pour votre code, c'est une collection. Me.Controls est cette
collection — chaque zone de texte, étiquette, bouton, cadre et liste déroulante que vous avez déposés sur
le formulaire, tenus comme des objets que vous pouvez compter et parcourir. Me.Controls.Count vous dit
combien il y en a ; Me.Controls(0) est le premier (la collection est indexée à partir de zéro). Me
désigne le formulaire dans lequel le code s'exécute, donc dans le module propre d'un UserForm,
Me.Controls et Controls signifient la même chose.
MsgBox "This form has " & Me.Controls.Count & " controls"
Une fois que vous voyez le formulaire comme une collection, les parties répétitives du code de formulaire
disparaissent. Vous arrêtez d'écrire txt1, txt2, txt3 et vous commencez à écrire une boucle.
Parcourir chaque contrôle avec For Each
For Each parcourt la collection. La variable de contrôle est typée MSForms.Control — le type
générique que partage chaque contrôle :
Dim ctl As MSForms.Control
For Each ctl In Me.Controls
Debug.Print ctl.Name
Next ctl
C'est le schéma derrière « vider le formulaire », « recueillir chaque valeur », « tout désactiver pendant
que je travaille ». Mais la collection contient tous les contrôles — y compris ceux que vous ne visiez
pas — si bien qu'une boucle brute qui écrit ctl.Value plante sur la première étiquette, parce qu'une
étiquette n'a pas de Value. C'est le problème suivant.
Filtrer par type avec TypeName et TypeOf
Tous les contrôles n'ont pas la propriété que vous voulez. Un Label n'a pas de .Value ; un
CommandButton n'a pas de .Text. Touchez le mauvais et vous obtenez une erreur d'exécution 438,
« Object doesn't support this property or method ». Filtrez donc d'abord. TypeName(ctl) renvoie le
type sous forme de chaîne ; TypeOf ctl Is le teste directement :
For Each ctl In Me.Controls
If TypeOf ctl Is MSForms.TextBox Then
ctl.Value = "" ' sans risque : seules les zones de texte atteignent cette ligne
End If
Next ctl
Utilisez TypeOf ... Is dans un If — c'est le test idiomatique. Utilisez TypeName(ctl) quand vous
voulez le nom du type dans un message ou un Select Case portant sur plusieurs types. La règle : n'appelez
jamais une propriété à l'intérieur d'un For Each sur Controls sans avoir d'abord prouvé que le contrôle
est d'un type qui la possède.
Atteindre un contrôle par son nom
C'est là que la collection porte ses fruits. Vous pouvez l'indexer par une chaîne de nom, et cette chaîne peut être construite à l'exécution :
Dim i As Long
For i = 1 To 5
Me.Controls("txtDay" & i).Value = "" ' txtDay1 ... txtDay5
Next i
Un formulaire avec des champs nommés de txtDay1 à txtDay5 a besoin d'une boucle, pas de cinq lignes.
C'est ainsi que fonctionnent les formulaires pilotés par les données : les noms suivent une convention, et
le code les construit. Le piège fait écho à celui d'Application.Run et CallByName dans la famille de
la réflexion — le nom est une chaîne, donc le compilateur ne peut pas le vérifier. Une faute de frappe
comme "txtDya1" ne provoque pas de soulignement rouge ; c'est une erreur d'exécution quand la ligne
s'exécute. Construisez le nom à partir d'un schéma connu, et protégez-le avec
On Error si une partie provient de données.
Ajouter des contrôles à un formulaire pendant qu'il tourne
La collection n'est pas figée. Controls.Add crée un contrôle pendant que le formulaire est ouvert, ce
qui permet de construire un formulaire dont la taille dépend des données — une ligne de champs par
enregistrement :
Dim box As MSForms.TextBox
Set box = Me.Controls.Add("Forms.TextBox.1", "txtDynamic", True)
box.Top = 10: box.Left = 10: box.Width = 120
Le premier argument est la classe du contrôle, le second son nom, le troisième s'il est visible. Les
contrôles ajoutés dynamiquement n'ont aucun événement de code associé, à moins de les câbler avec une
classe WithEvents — une technique réelle, mais à réserver aux cas où une disposition fixe ne peut
vraiment pas faire le travail.
Le choix de jugement : quand une boucle vaut mieux que vingt références nommées
La collection Controls est puissante, ce qui la rend facile à surutiliser. La règle honnête : si vous
avez une poignée de contrôles que vous connaissez par leur nom, txtName.Value est plus clair que
Me.Controls("txtName").Value, et le compilateur le vérifie. La boucle mérite sa place quand les contrôles
sont nombreux et uniformes — vingt champs de jour, une grille de saisies, chaque zone de texte du
formulaire — ou quand le nom est réellement décidé par les données. Une boucle sur trois contrôles, c'est
de la frime ; une boucle sur vingt est la seule façon sensée de l'écrire. Choisissez la collection quand
elle supprime une vraie répétition, pas pour prouver que vous en êtes capable.
Comment ExcelMaster vous aide
Les échecs ici sont discrets et tardifs : un For Each qui plante sur l'unique étiquette que vous avez
oubliée, un nom de contrôle construit depuis des données qui ne correspond plus, une propriété appelée sur
le mauvais type. Tous se manifestent par la même erreur 438 ou un « introuvable », à l'exécution, sur un
formulaire qui semblait terminé.
ExcelMaster vous laisse décrire le
comportement du formulaire — « vider chaque zone de texte », « lire toutes les saisies dans une ligne »,
« construire cinq champs de jour à partir d'une liste » — et il écrit la boucle Controls avec le filtre
de type et le garde-fou de nom déjà en place. Vous gardez le formulaire et le code, et vous évitez la
chasse aux erreurs à l'exécution.
Questions fréquentes
Qu'est-ce que la collection Controls en VBA ?
C'est la collection de tous les contrôles d'un UserForm, atteinte via Me.Controls. Chaque élément est un
objet contrôle — une zone de texte, une étiquette, un bouton, un cadre ou une liste déroulante. Vous
pouvez les compter avec .Count, les parcourir avec For Each, et en atteindre un par index ou par son
nom sous forme de chaîne. C'est la façon standard d'agir sur de nombreux contrôles à la fois au lieu de
les nommer un par un.
Comment parcourir tous les contrôles d'un UserForm ?
Déclarez une variable As MSForms.Control et utilisez For Each ctl In Me.Controls. À l'intérieur de la
boucle, testez le type avec TypeOf ctl Is MSForms.TextBox avant de toucher une propriété, car la
collection contient aussi des étiquettes et des boutons qui n'ont pas cette propriété et déclencheraient
l'erreur 438.
Comment référencer un contrôle par un nom stocké dans une chaîne ?
Indexez la collection avec la chaîne : Me.Controls("txtName"). Le nom peut être construit à l'exécution,
comme Me.Controls("txtDay" & i). Comme le nom est une chaîne, une faute de frappe n'est pas détectée
avant que la ligne ne s'exécute — elle déclenche une erreur « introuvable » — construisez donc le nom à
partir d'un schéma connu et protégez-le.
Pourquoi ma boucle For Each sur Controls déclenche-t-elle l'erreur 438 ?
Parce que vous avez appelé une propriété que le contrôle courant n'a pas — le plus souvent .Value ou
.Text sur un Label, un Frame ou un CommandButton. La collection Controls contient tous les
types, filtrez donc avec TypeOf ctl Is MSForms.TextBox (ou le type visé) avant de lire ou d'écrire cette
propriété.
Puis-je ajouter des contrôles à un formulaire pendant qu'il tourne ?
Oui. Me.Controls.Add("Forms.TextBox.1", "txtNew", True) en crée un à l'exécution, ce qui permet de
construire un formulaire dimensionné aux données. Réglez ensuite son Top, son Left et son Width. Les
contrôles ajoutés dynamiquement n'ont aucun gestionnaire d'événement à moins de les connecter avec une
classe WithEvents.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — vérifié le 28/09/2026.
Guides associés : VBA TextBox · VBA Frame · VBA UserForm · VBA ListBox · VBA ComboBox · VBA CheckBox · VBA On Error
