TL;DR —
Application.EnableEvents = Falseは、マクロの書き込みがWorksheet_ChangeやWorkbook_Openなどのイベントハンドラーを引き起こすのを止めます。その主な役目は、Worksheet_Changeハンドラーがセルに書き込み、それがWorksheet_Changeをまた発火させ…と 永遠に続くループを断ち切ることです。これは速度ではなく、正しさのスイッチです。そして、もっとも エラーハンドラーを必要とするスイッチでもあります。なぜならEnableEventsはアプリケーション 単位で、自動では戻らないからです — 切ったままクラッシュすると、Excel のあらゆるイベントが 再起動まで死んだままになります。
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub
Application.EnableEvents = False ' 下の書き込みでこのハンドラーを再発火させないように
On Error GoTo CleanExit
Target.Offset(0, 1).Value = Now ' 書き込み - さもないと Worksheet_Change をまた引き起こす
CleanExit:
Application.EnableEvents = True ' エラーのあとでも戻す。さもないとイベントがアプリ全体で死ぬ
End Sub
このクラスターの他の 2 つのスイッチは速度の話です — ScreenUpdating
は再描画を止め、Calculation は再計算を止めます。EnableEvents は
違います。それは正しさの話です。自分の書き込みが、ブックを見張るイベントハンドラーの中で跳ね
返るのを止めるのです。本記事は 1 つの考えを軸にしています — EnableEvents は、自分の変更が「変更に
反応するコード」を引き起こさないように切り替えるスイッチである。速度のためではなく、制御のために
切り替える — そしてクラッシュがアプリケーション全体でこれを切ったまま残すので、戻すことは任意では
ない。
この記事で学べること
- 考え方の軸 — セルへの書き込みがイベントハンドラーを発火させ、それがさらにセルを書きうる
- 典型的なバグ —
Worksheet_Changeハンドラーが自分自身を無限ループに引き込む - 最も大事なルール —
EnableEventsはアプリ単位で、自動では戻らない - 「ボタンが動かなくなった」のほぼすべてが、置き去りにされた
EnableEvents = Falseである理由 CleanExitによる復元、そしてそれが速度スイッチよりここで重要な理由- Worksheet_Change と Intersect との組み合わせ方
考え方の軸:書き込みはイベントを発火させうる
Excel のブックはイベントハンドラー — 何かが起きたときに自動で走るプロシージャ — を持てます。
Worksheet_Change はセルが変わると走り、Workbook_Open はファイルが開くと走り、
Worksheet_SelectionChange は選択が動くと走ります。これらが、ブックがユーザーに反応する仕組みです。
落とし穴は、あなたのマクロの動作も「何かが起きた」に数えられることです。コードがセルへ書き込め
ば、それは変更なので、Excel は Worksheet_Change を発火させます — その編集をしたのがユーザーでは
なくあなたのマクロだったとしても。ふつう、自分の自動書き込みで、人間に応えるために書かれたハンド
ラーを起こしたくはありません。
Application.EnableEvents = False は、その発火をオフにします。False の間も変更は起きますが、Excel
はそれに応えてどのイベントハンドラーも走らせません。True に戻せばイベントが再開します。
典型的なバグ:自分自身を引き起こすハンドラー
このスイッチが防ぐために存在する失敗は、自分自身を引き起こす Worksheet_Change です。B 列が編集
されるたびに時刻を刻むハンドラーを考えてみましょう — C 列へ書き込むことによって。
' 壊れている - 無限再帰:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub
Target.Offset(0, 1).Value = Now ' C への書き込み自体が変更…
End Sub ' …それが Worksheet_Change をまた発火 -> また -> クラッシュ
C への書き込みは変更で、それが Worksheet_Change を発火させ、それがまた C へ書き込み、それが
また発火させます。実際にはスタックオーバーフロー(error 28)になるか、Excel がループにはまり込み
ます。直し方は、書き込みがハンドラーに再突入しないよう包むことです。
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub
Application.EnableEvents = False ' 下の書き込みはこれを再発火させない
On Error GoTo CleanExit
Target.Offset(0, 1).Value = Now
CleanExit:
Application.EnableEvents = True
End Sub
Intersect のガードと EnableEvents のガードは兄弟です — シートに何かを
書き戻す Worksheet_Change ハンドラーは両方を必要とします。一方は
引き金のスコープを絞るため、もう一方は再帰を止めるためです。
最も大事なルール:自動では戻らない
ここが、EnableEvents が「慎重に扱わねばならないスイッチ」という評判を得るところです。マクロが
終わると Excel が時に戻す ScreenUpdating と違い、EnableEvents は
決して自分では戻りません。しかも、これはブック単位ではなく**Application** のプロパティです —
つまり開いているすべてのブックに一度に効きます。
この 2 つの事実を合わせると、VBA で最も厄介な残留状態が生まれます。マクロが EnableEvents = False
を設定し、それを戻す前にエラーになると、イベントはいまやあらゆる場所で — そのブックでも、開いて
いる他のすべてのブックでも — オフになり、ユーザーがExcel を閉じて開き直すまで、オフのまま残り
ます。エラーメッセージも、見た目の合図もありません。ブックはただ静かに反応をやめます。
「ボタンが動かなくなった」
その残留状態には、決まり文句の訴えがあります。「マクロのボタンが/ドロップダウンが/自動書式が
動かなくなった、しかも何も変えていない」。十中八九、以前のどれかのマクロが EnableEvents = False
を効かせたままクラッシュし、いまや Worksheet_Change、Workbook_Open、そして他のあらゆるハンド
ラーが静かに無効になっています。
一行の救済策は、イミディエイトウィンドウ(またはどのマクロからでも)でこれを走らせることです。
Application.EnableEvents = True
けれど本当の直しは上流にあります。それを戻すエラーハンドラーなしに、決して EnableEvents = False
を設定しないこと。損害がアプリケーション全体に及び、しかも目に見えないので、速度スイッチでは単に
良い習慣にすぎない CleanExit の規律が、ここでは本当に必須になります。
Sub BulkImport()
Application.EnableEvents = False
On Error GoTo CleanExit
' ... さもないと行ごとに Worksheet_Change を引き起こす書き込み ...
CleanExit:
Application.EnableEvents = True ' 譲れない
End Sub
いつ使い、いつ使わないか
コードが、イベントハンドラーに見張られたセルへ書き込むとき、あるいは行ごとのイベントが何百回も
発火してほしくない一括処理の間に、EnableEvents = False に手を伸ばしましょう。一般的な速度の小技
として手を伸ばしてはいけません — シートに関係するイベントハンドラーがなければ、イベントを無効に
しても何も変わらず、何の得もなく復元のリスクだけを背負い込みます。これは的を絞った正しさの道具です。
書き込みが跳ね返るであろうまさにその場所で使い、それ以外では手を触れないでください。
ExcelMaster の活用
EnableEvents は見かけによらず危険です。アプリケーション全体に効き、決して戻らず、切ったまま
クラッシュすると、再起動まで Excel のあらゆるイベントを静かに殺します。安全に使うということは、
イベントハンドラーの中で Intersect のガードと組にし、一括書き込みを行ごとのイベントが発火しない
よう包み、そして毎回欠かさず CleanExit ハンドラーの中で戻すことを意味します。
ExcelMaster は、その安全な
パターンを丸ごと組み立てます。「B 列が変わったら C 列に時刻を刻んで」と頼めば、Intersect のガード、
書き込みを囲む EnableEvents = False の切り替え、そして CleanExit の復元とともに
Worksheet_Change ハンドラーを書きます — ハンドラーが自分自身をループすることも、そのセッションの
残りずっとイベントを置き去りにすることもありません。最初のエラーで静かに壊れるものではなく、正しく
反応するブックの自動化が手に入ります。
よくある質問
VBA の Application.EnableEvents = False は何をしますか?
あなたのコードが行う変更に応えて、Excel がイベントハンドラーを走らせるのを止めます。False の間も、
セルへの書き込みのような動作は起きますが、それらは Worksheet_Change、Workbook_SheetChange、
その他のイベントプロシージャを引き起こしません。True に戻せば、イベントが再び発火するように
なります。
Worksheet_Change イベントが自分自身を引き起こすのを止めるには?
ハンドラーがどのセルへ書き込む前にも Application.EnableEvents = False を設定し、そのあと True に
戻します。これがないと、ハンドラー自身の書き込みが変更となって Worksheet_Change をまた発火させ、
Excel がスタックオーバーフローエラーを発生させるまでループします。Intersect のガードと組み合わせて、
気にかけるセルに対してだけハンドラーが走るようにしましょう。
Excel のイベントがすべて動かなくなったのはなぜですか?
どれかのマクロが Application.EnableEvents = False を設定して戻さなかったからです — たいていは戻す
行の手前でエラーになりました。EnableEvents はアプリケーション単位で、自動では戻らないので、
Application.EnableEvents = True に設定するか Excel を再起動するまで、開いているすべてのブックで
イベントが無効のまま残ります。
EnableEvents はマクロが終わると自動でリセットされますか?
いいえ。Excel が自分で戻すことのある ScreenUpdating と違い、EnableEvents は、あなたが戻すか
Excel を閉じるまで — マクロをまたいでも、マクロが終わったあとでも — 残したそのままです。だからこそ、
何らかの自動リセットに頼るのではなく、エラーハンドラーの中で戻さなければなりません。
EnableEvents は ScreenUpdating のような速度の最適化ですか?
そうではありません。ScreenUpdating と Calculation は速度の話ですが、EnableEvents は正しさの
話です — 自分の書き込みが、ブックを見張るハンドラーを引き起こすのを止めます。一括書き込みの間に
イベントコードが何百回も走るのを避けられはしますが、その第一の目的は、生の速度ではなく、ループや
望まない反応を防ぐことです。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-17。
関連ガイド: VBA ScreenUpdating · VBA Calculation · VBA Worksheet_Change · VBA Intersect · VBA On Error
