Developer

【ExcelVBA】イベントを利用する際の注意点
2022.01.13
Lv1

【ExcelVBA】イベントを利用する際の注意点

イベントを利用する際の注意点

イベントを利用すると、ユーザーがボタンやメニューを操作しなくても自動的に特定の処理を実行するようなマクロを作ることができます。
たとえば、ブックを開いたときに専用のメニューを表示したり、ブックを閉じる前にデータをバックアップして保存したり、家計簿のようなマクロでは入力された金額が妥当なものかチェックを行ったりということが可能になります。
この仕組みは特にマクロを作る人と使う人が異なる場合や、マクロを実行するタイミングが月に1回で間が空いてしまう場合などでは必須とも呼べる機能です。
このように非常に便利なイベントですが、間違った使い方をすると思わぬ不具合(バグ)になってしまうことがあります。作成者が意図していないタイミングでマクロが実行されてしまうことに起因します。

イベントループ

では、不具合の代表例の1つ「イベントループ」を見てみましょう。この不具合はその名の通りイベントの発生がループしてしまうことによって起こります。
VBAではマクロの処理結果からもイベントが発生すると特徴があります。
このために、イベントプロシージャ内の処理からその処理開始の切っ掛けとなっているイベントが発生してしまい、さらに同じイベントプロシージャが実行されてしまうということが起こる可能性があります。
これは合わせ鏡(鏡に映った鏡の中に、さらに鏡が映って…と無限に続いてしまうという現象)をしている状態と似ています。このイベントループが一度発生してしまうとマクロの処理が永遠に終わらない(無限ループともいいます)状態となってしまいます。

これから作るマクロは、セルの値が変わった時に発生するイベントを切っ掛けにして処理を実行するイベントプロシージャです。
処理内容としては、入力された値をプラス1するというシンプルなものです。しかし、セルの値を変更していますのでこのプロシージャ内から同じイベントが発生してイベントループが起こってしまいます。

Private Sub Worksheet_Change(ByVal Target As Range)
    Target.Value = Target.Value + 1
End Sub

Excelの画面にもどって、任意のセルに「1」と入力します。すると、「1」が入力されたというイベントが発生し、「Worksheet_Change」が実行されます。「Worksheet_Change」の中では入力されたセルの値をプラス1するという処理が記述されているのでセルの値が2になります。
セルの値が変更されたため、Excelは再度「セルの値が変更された」というイベントを発生させます。そして再度「Worksheet_Change」が実行されます。

イベントループを止めるには

イベントループはこのように処理が永遠に終わらない状態に陥ってしまうことを指します。他のプログラム言語ではこのような状態が続いているとアプリケーションが応答なしの状態やコンピュータがハングアップしたかのような状態になってしまいます。
Excelではイベントループを防ぐための仕組みがあらかじめ組み込まれており、一定の回数だけループが発生すると自動的に停止するようになっています。
上の画像ではセルの値が「48」となっていたのはこれが原因です。
しかし、みなさんのコンピュータで同じことをした場合、同じように「48」で止まるとは限りません。Excelのバージョンなど環境によって異なります。

VBAの中からイベントが発生してしまうことを抑止することも可能です。
「EnableEventsプロパティ」に「False」を設定すると、それ以降Excelのイベントは発生することがなくなります。

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    Target.Value = Target.Value + 1
    Application.EnableEvents = True
End Sub

注意点としては、「False」に設定した「EnableEvents」プロパティは必ず「True」に戻すことを忘れないようにすることです。戻さずにマクロが終了してしまうと、一切のイベントが発生しない状態が続いてしまいます。

まとめ

イベントプロシージャを使用するときにはイベントループに注意が必要。
Excelではイベントループが発生しても自動的に停止する仕組みが備わっている。
イベント発生を抑止するには、「EnableEvents」プロパティを使用する。

確認問題

次のプログラムにイベント発生を抑止するプログラムを追加してください。イベント発生を再開することをわすれないようにしましょう。

Private Sub Worksheet_Change(ByVal Target As Range)
    Target.Value = Target.Value + 1
End Sub
答え
[vb] Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Target.Value = Target.Value + 1
Application.EnableEvents = True
End Sub
[/vb]

次回は、「ブックのイベントについて」です。