【Excel VBA】代表的なイベント処理について

Excel

何かの操作が行われたときに、その操作を「キッカケ」にして処理を実行する仕組みのことを、プログラミング用語で「イベント処理」と言います。
例えば、「ボタンをクリックしたら、画面を切り替える」とか、「キーボードのキーを押したら、ある処理を始める」といったような感じです。
ExcelのVBAでは、イベントの発生時に実行される処理を、「イベントプロシージャ」といいます。
VBAで扱えるイベントは数多くありますので、ここでは代表的なものを4つ、ご紹介いたします。

イベントプロシージャの記述方法

イベントプロシージャの説明の前に、Visual Basic Editorでのイベントの記述方法をご説明いたします。

① まず、Visual Basic Editor左上の「プロジェクト」の部分で、イベントを記述したいシートまたはブックをダブルクリックします。

② 次に、表示されたコードウインドウで、(General)の部分をWorksheet(ブックの場合はWorkbook)に変更して下さい。

③ デフォルトで「Worksheet_SelectionChange」というイベントプロシージャ(ブックの場合はWorkbook_Open)が表示されます。
この状態で、コードウインドウ右上のプルダウンメニューを選択すると、記述可能なイベントが選択できるようになります。ここから、使いたいイベントを選択して下さい。
デフォルトで表示された「Worksheet_SelectionChange」プロシージャは、使わなければ消しても良いですし、そのまま放置しても良いですし、どちらでも構いません。

ここから、具体的なイベントの説明に入ります。

Workbook_Open(ブックを開いた直後)

ブックを開いた直後に実行されるイベントプロシージャです。

ブックを開いた直後に、ファイル選択ダイアログボックスを開きたい場合、こんな感じになります。

Private Sub Workbook_Open()
    'ブックを開いた直後に実行したい処理をここに記述する
    Sheets("Sheet1").Range("A1") = Application.GetOpenFilename
End Sub

Workbook_Openプロシージャを実行させない方法(マクロを無効にする)

当プロシージャは、ブックを開いた直後に実行されるため、ブックを開くと有無を言わさず実行されます。
しかし、デバッグを行いたい場合など、プロシージャを実行したくない場合は、以下の方法でブックを開くと、プロシージャを実行せずにブックを開くことが出来ます。
※Workbook_Openプロシージャに限らず、ブック内の全てのマクロが無効になります。

  • Excelを起動する。
  • メニューの「開く」を選択。
  • 「参照」を選択して、「ファイルを開く」ダイアログで、開きたいファイルを選択する。この時点ではまだファイルを開かないこと。
  • Shiftを押しながら「開く」をクリックする。

これで、マクロを無効にしてブックを開くことができます。

Worksheet_Change(どこかのセルの値が変更されたとき)

セルの値が変更された時に実行されるイベントプロシージャです。
当プロシージャでは、変更されたセル(Target)が、Rangeオブジェクトとして引数で渡されます。

例1:変更されたセルの値(Target.Value)をメッセージボックスで表示する。

※変更前の値を取得することは出来ません。

Private Sub Worksheet_Change(ByVal Target As Range)
    MsgBox "変更後のセルの値は " & Target.Value
End Sub

例2:変更されたセルのアドレス(Target.Address)をメッセージボックスで表示する。

Private Sub Worksheet_Change(ByVal Target As Range)
    MsgBox "変更されたセルは " & Target.Address
End Sub

※「$」が邪魔な場合は、Replace関数で除去して下さい。

注意点:イベントを一時的に無効にする必要がある場合(Application.EnableEventsの使用)

当イベントプロシージャ内で、シート内のセルの値を更新する場合は、以下の命令により、イベントの発生を止める必要があります。

Application.EnableEvents = False

これが無いと、セルの更新時に再びWorksheet_Changeイベントが発生してしまい、無限ループに陥ります。
但し、この命令は全てのイベントを止めるのと、マクロ終了後もイベントが発生しないままになります。
そのため、必ず以下の命令を実行して、イベントが発生する状態に戻す必要があります。

Application.EnableEvents = True

プロシージャの先頭で「Application.EnableEvents = False」を実行して、プロシージャ終了時に「Application.EnableEvents = True」を実行することを推奨します。

Application.EnableEventsの使用例

Private Sub Worksheet_Change(ByVal Target As Range)
    'イベントの発生を止める
    Application.EnableEvents = False

    '変更されたセルの値が数値の場合は、入力値を2倍にする
    If IsNumeric(Target.Value) = True Then
        Target.Value = Target.Value * 2
    End If

    'イベントが発生する状態に戻す
    Application.EnableEvents = True
End Sub

応用例1:イベントプロシージャを発生させるセルを限定したい場合

Worksheet_Changeイベントは、イベントプロシージャを記述したシート全体が対象となります。
「それでは困る。対象のセルを限定したい。」という場合は、以下のようにTarget.Addressでの判定文を記述すれば、イベントプロシージャを発生させるセルを限定できます。

以下のようにすれば、セル「B2」が変更された場合のみ、メッセージボックスが表示されます。

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Address = "$B$2" Then
        MsgBox "変更後のセルの値は " & Target.Value
    End If
End Sub

セルを範囲指定する場合(例えばセル「B1」~「D3」を指定したい場合)は、以下のようにTarget.Row(行番号)やTarget.Column(列番号)で判定すると良いです。

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Row >= 1 And Target.Row <= 3 And _
       Target.Column >= 2 And Target.Column <= 4 Then
        MsgBox "変更後のセルの値は " & Target.Value
    End If
End Sub

応用例2:複数のセルをまとめて処理対象にしたい場合(コピー&ペーストした場合など)

Worksheet_Changeイベントを記述したシートにてコピー&ペーストした場合など、複数のセルがまとめて変更された場合は、以下のようにFor Each文を使って、それぞれのセルを処理する必要があります。

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim objRange As Range
    For Each objRange In Target
        MsgBox "変更されたセルは  " & objRange.Address & vbCrLf & _
               "変更後のセルの値は " & objRange.Value
    Next
End Sub

For Each文を使わずに、引数のTargetをそのまま処理すると、以下のような結果になります。

  • Target.Address ➡ 「$C$1:$C$2」のようにセル範囲がまとめて返され、プログラムで扱いづらい形式になる。
  • Target.Value ➡ 「型が一致しません。」という実行時エラーになる。

Worksheet_SelectionChange(セルの選択範囲を変更したとき)

セルの選択範囲が変更された時に実行されるイベントプロシージャです。
矢印キーでセルの選択位置を動かした時など、セルの値を変更しなくても当イベントが発生します。
Worksheet_Changeと使い方が似ており、変更後に選択されたセル(Target)が、Rangeオブジェクトとして引数で渡されます。

例:変更後に選択されたセルのアドレス(Target.Address)をメッセージボックスで表示する。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    MsgBox "選択されたセルは  " & Target.Address
End Sub

イベントプロシージャを発生させるセルを限定する方法や、複数のセルをまとめて処理対象にする方法も、Worksheet_Changeと同様です。

Worksheet_BeforeDoubleClick(セルがダブルクリックされたとき)

セルがダブルクリックされた時に実行されるイベントプロシージャです。
当プロシージャでは、変更されたセル(Target)が、Rangeオブジェクトとして引数で渡されます。
また、第2引数のCancelにTrueを設定すると、ダブルクリック時の挙動(セルが編集中の状態)をキャンセルできます。
通常は、イベントプロシージャ終了時に、第2引数のCancelにTrueを設定することを推奨します。
理由は、セルが編集中のままだと、下図のようにカーソルが点滅中のままになり、思わぬ誤操作を起こすリスクがあるためです。

例:ダブルクリックされたセルのアドレス(Target.Address)をメッセージボックスで表示する。

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    MsgBox "ダブルクリックされたセルは " & Target.Address
    Cancel = True     'セルを編集中の状態にしたくない場合
End Sub

コメント

タイトルとURLをコピーしました