TL;DR —
Worksheet_Changeest un événement qu'Excel déclenche chaque fois qu'un utilisateur (ou votre code) modifie une cellule de cette feuille. Excel vous remet la cellule modifiée sous forme deTarget, pour que vous puissiez réagir — horodater la ligne, valider la saisie, journaliser la modification. La seule chose à savoir : si votre gestionnaire écrit dans une cellule, cette écriture redéclencheWorksheet_Change— encore et encore — jusqu'à ce qu'Excel se fige. Le correctif tient en une seule paire de lignes,Application.EnableEvents = False … = True, autour de chaque écriture. Acquérez ce réflexe et tout le reste n'est que détail.
' Réside dans l'objet propre à la feuille (p. ex. Sheet1), PAS un Module ni ThisWorkbook.
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("B:B")) Is Nothing Then Exit Sub ' ne réagir qu'à la colonne B
On Error GoTo Done
Application.EnableEvents = False ' empêcher notre propre écriture de redéclencher cet événement
Target.Offset(0, 1).Value = Now ' inscrire l'heure à côté de la modification
Done:
Application.EnableEvents = True ' TOUJOURS réactiver les événements
End Sub
Réagir aux modifications, c'est le moment où VBA cesse d'être « des boutons qui
lancent des macros » pour commencer à sembler vivant : une cellule change et la
feuille répond d'elle-même. Worksheet_Change est l'événement qui alimente les
pistes d'audit, les horodatages automatiques, la validation en direct et les listes
déroulantes dépendantes. C'est aussi l'événement qui provoque les instants les plus
paniqués du genre « Excel s'est figé et j'ai perdu mon travail » — car le code
évident n'est qu'à un petit pas d'une boucle infinie.
Ce que vous allez apprendre
- Le modèle mental — un capteur de modification qui vous remet la cellule modifiée sous forme de
Target - Le piège de la boucle infinie — et le correctif
Application.EnableEventsqui définit le VBA événementiel - Pourquoi un plantage peut désactiver tous vos événements jusqu'au redémarrage d'Excel
- Comment cibler le gestionnaire avec
Intersectpour qu'il ne s'exécute pas à chaque modification - Pourquoi il ignore les recalculs de formules — et quand vous avez plutôt besoin de
Worksheet_Calculate
Le modèle mental : un capteur de modification, pas un bouton
Worksheet_Change est un capteur relié à la feuille. Vous ne l'appelez pas ; à
l'instant où le contenu d'une cellule change, c'est Excel qui vous appelle, en
passant la ou les cellules modifiées sous forme d'un Range nommé Target. Votre
travail consiste à lire Target et à décider quoi en faire.
Ce cadrage règle deux points. D'abord, Target est votre unique entrée — c'est là
où la modification a eu lieu, et cela peut être une cellule ou plusieurs (un
collage, un remplissage, une suppression sur toute une sélection arrivent tous sous
forme d'un Target multi-cellules). Ensuite, le gestionnaire réside dans l'objet de
code de la feuille concernée — Sheet1 dans l'Explorateur de projets, pas
ThisWorkbook ni un Module. La signature est figée :
Private Sub Worksheet_Change(ByVal Target As Range). (La version à l'échelle du
classeur, pour toutes les feuilles à la fois, est Workbook_SheetChange dans
ThisWorkbook.)
Le piège qui fige Excel : votre écriture redéclenche l'événement
Voici le bug que tout développeur VBA écrit exactement une fois. Vous voulez réagir à une modification en réécrivant quelque chose dans la feuille :
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Offset(0, 1).Value = Now ' écrire à côté de la modification... ce qui est LUI-MÊME une modification
End Sub
Écrire dans Target.Offset(0, 1) modifie une cellule — ce qui redéclenche
Worksheet_Change — dont l'écriture le redéclenche encore — à l'infini. Excel
s'appelle récursivement jusqu'à épuiser la pile et lever une erreur, ou simplement
paraître figé. L'événement de modification n'a aucune protection intégrée contre le
fait de réagir à sa propre réaction.
Le correctif est l'idiome le plus important du VBA événementiel : désactivez les événements autour de toute écriture, puis réactivez-les.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Target.Offset(0, 1).Value = Now
Application.EnableEvents = True
End Sub
Avec EnableEvents = False, votre écriture ne déclenche pas un nouveau
Worksheet_Change, donc pas de récursion. Ensuite vous le rétablissez. Gravez la
règle : dans tout événement qui écrit dans des cellules, encadrez l'écriture par
Application.EnableEvents = False … = True.
La règle qui cache la seconde moitié du piège : un plantage laisse les événements désactivés
Application.EnableEvents est un interrupteur unique, global à l'application, et
Excel ne le rétablit pas automatiquement. Cela crée un vilain second mode de
défaillance : si votre gestionnaire échoue après l'avoir mis à False mais
avant de l'avoir remis, les événements restent désactivés — pour toute la session
Excel, sur chaque feuille et chaque classeur.
Le symptôme déroute : « mes macros ont soudain cessé de fonctionner ». Votre
Worksheet_Change n'est pas cassé — les événements sont globalement supprimés parce
qu'une exécution antérieure est morte en plein gestionnaire. C'est pourquoi le motif
sûr réactive toujours les événements dans un gestionnaire d'erreurs :
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo CleanExit
Application.EnableEvents = False
Target.Offset(0, 1).Value = Now
' ... d'autres traitements susceptibles d'échouer ...
CleanExit:
Application.EnableEvents = True ' s'exécute que l'on ait réussi ou échoué
End Sub
C'est exactement la discipline de « la sortie unique qui nettoie toujours » de
VBA On Error, et elle est non négociable ici. (Si les
événements sont déjà bloqués à l'arrêt, exécutez une ligne dans la fenêtre
Exécution — Application.EnableEvents = True — ou redémarrez simplement Excel.)
La règle qui le maintient ciblé : cibler avec Intersect
Un Worksheet_Change nu se déclenche pour n'importe quelle cellule de la
feuille. Si seules vous intéressent les modifications dans une colonne ou un tableau,
vous devez le dire — sinon le gestionnaire s'exécute (et écrit peut-être) à chaque
modification sans rapport. L'outil, c'est Intersect, qui renvoie le chevauchement
entre Target et la plage qui vous intéresse, ou Nothing s'il n'y en a pas :
Private Sub Worksheet_Change(ByVal Target As Range)
' Ignorer les modifications hors de B2:B1000
If Intersect(Target, Range("B2:B1000")) Is Nothing Then Exit Sub
' ... ne réagir qu'à la partie qui compte ...
End Sub
Deux mises en garde connexes. Target peut compter plusieurs cellules — un
collage ou un remplissage de colonne vous remet une plage multi-cellules, si bien
qu'un code supposant que Target.Value est une valeur unique lèvera une erreur ou
se comportera mal ; parcourez Target en boucle, ou restreignez avec
If Target.Count > 1 Then Exit Sub quand vous voulez vraiment des modifications
unitaires. Et réagissez à l'intersection, pas à tout Target, lorsqu'un collage
déborde de votre plage surveillée sur des cellules extérieures.
La distinction qui piège tout le monde : il ignore les recalculs de formules
Worksheet_Change se déclenche sur un changement du contenu d'une cellule — une
valeur tapée, une valeur collée, une suppression, une écriture VBA. Il ne se
déclenche pas quand une cellule affiche simplement un nouveau nombre parce qu'une
formule a été recalculée. Si C1 vaut =A1+B1 et que A1 change, l'événement se
déclenche pour A1 (la cellule modifiée), pas pour C1 (celle qui a été
recalculée).
Quand vous devez réagir au changement d'un résultat, c'est un autre événement —
Worksheet_Calculate — qui se déclenche au recalcul mais ne vous donne aucun
Target (vous devez inspecter les cellules vous-même). Choisir le mauvais est une
défaillance silencieuse : votre gestionnaire ne s'exécute tout simplement jamais. La
règle : Change = quelqu'un a modifié la cellule ; Calculate = la sortie d'une
formule a bougé.
Worksheet_Change est une moitié du duo « réagir à l'utilisateur ». Son jumeau,
Worksheet_SelectionChange, se déclenche
quand le curseur se déplace plutôt que quand une valeur change — et tous deux
appartiennent à la même famille d'événements que
Workbook_Open, l'événement qui s'exécute à la première
ouverture du fichier.
Comment ExcelMaster aide
Une macro de réaction aux modifications est d'une minutie trompeuse : le bon objet,
Intersect pour la cibler, EnableEvents pour éviter la boucle, un gestionnaire
d'erreurs pour qu'un plantage ne tue pas tous les événements d'Excel. Oubliez la
paire EnableEvents et vous figez le fichier ; oubliez le gestionnaire d'erreurs et
vous cassez les événements en silence.
ExcelMaster
vous laisse énoncer le comportement à la place. Dites « quand quelqu'un modifie la
colonne B, mets l'heure actuelle dans la colonne C juste à côté », et il écrit un
Worksheet_Change dans le bon objet de feuille — ciblé avec Intersect, protégé par
EnableEvents, enveloppé pour qu'une erreur ne puisse pas laisser les événements
bloqués à l'arrêt. Vous gardez la feuille et le code ; vous vous épargnez le rituel
initial qui consiste à figer votre propre classeur pour apprendre la règle.
Questions fréquentes
Pourquoi mon Worksheet_Change provoque-t-il une boucle infinie ou un blocage ?
Parce que votre gestionnaire écrit dans une cellule, et que cette écriture est
elle-même un changement qui redéclenche Worksheet_Change — sans fin. Encadrez
chaque écriture par Application.EnableEvents = False avant et
Application.EnableEvents = True après, et réactivez toujours les événements dans un
gestionnaire d'erreurs pour qu'un plantage ne puisse pas les laisser désactivés.
Comment faire en sorte que Worksheet_Change ne s'exécute que pour une colonne précise ?
Utilisez Intersect en tête du gestionnaire :
If Intersect(Target, Range("B:B")) Is Nothing Then Exit Sub. Cela sort
immédiatement, sauf si la modification a touché la colonne B. Intersect renvoie le
chevauchement entre la plage modifiée et la plage qui vous intéresse, ou Nothing
quand il n'y a aucun chevauchement.
Worksheet_Change se déclenche-t-il quand une formule est recalculée ?
Non. Il se déclenche uniquement quand le contenu d'une cellule est modifié — tapé,
collé, supprimé ou écrit par VBA. Une cellule qui affiche une nouvelle valeur parce
qu'une formule a été recalculée ne le déclenche pas. Pour cela, utilisez l'événement
Worksheet_Calculate, qui se déclenche au recalcul mais ne vous donne pas de
Target.
Où placer le code Worksheet_Change ?
Dans le module de code de la feuille concernée — double-cliquez sur la feuille
(p. ex. Sheet1) sous « Microsoft Excel Objets » dans l'Explorateur de projets et
placez-y Private Sub Worksheet_Change(ByVal Target As Range). Cela ne fonctionne
pas depuis un Module standard. Pour toutes les feuilles à la fois, utilisez
Workbook_SheetChange dans ThisWorkbook.
Mes événements VBA ont cessé de fonctionner — comment corriger ça ?
Un gestionnaire antérieur a probablement défini Application.EnableEvents = False et
échoué avant de le rétablir, laissant les événements globalement désactivés. Tapez
Application.EnableEvents = True dans la fenêtre Exécution (Ctrl+G) et appuyez sur
Entrée, ou redémarrez Excel. Prévenez le problème en réactivant toujours les
événements dans un gestionnaire d'erreurs.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — dernière vérification le 02/08/2026.
Guides associés : VBA Worksheet_SelectionChange · VBA Workbook_Open · VBA On Error · VBA Range · VBA Boucle For
