セルの値が変更された際にマクロを実行する方法を解説します。
Worksheet_Changeプロシージャを使用します。
基本構文
以下のコードをマクロを設定したいシートモジュールに記載します。
Private Sub Worksheet_Change(ByVal Target As Range, Cancel As Boolean) Application.EnabeleEvents = False ' ここに実行したい処理を記述 Application.EnabeleEvents = True End Sub
引数Targetには値が変更されたセルまたはセル範囲がSetされます。
構文的に必須という訳ではありませんが、このプロシージャを使う場合は、
かなりの確率でApplication.EnabeleEventsの切り替えが必要になります。
というのも、このプロシージャ内の処理でセルの値を変更した場合でも、
値の変更が検知され、このプロシージャが重ねて再帰呼出されます。
よって、場合によってはこのプロシージャがこのプロシージャを呼ぶ、
無限ループに陥ってしまう可能性がかなり高いです。
このプロシージャ内の処理に対してもイベントを発火させたい場合を除き、
Application.EnabeleEvents = False は基本記述して使うものと考えてください。
このプロシージャはプロシージャ名を変更することはできません。
第1行は変更せずすべてこのままのコードを記述してください。
このコードはシートモジュール上部の選択肢から呼び出すことが出来ます。


イベントプロシージャの構文はWEB検索で探したりする必要はなく、
使うときにこの選択肢から選べばよいことを覚えておきましょう。
サンプルコードと解説
特定のセル値が変更された際にマクロを実行する
A1セル、C3セルなど単独のセル値が変更された際にマクロを実行するには、
対象のシートモジュールに以下のコードを記載します。
Private Sub Worksheet_Change(ByVal Target As Range) Application.EnableEvents = False Select Case Target.Address(False, False) Case "A1" MsgBox "変更された値は" & Target.Value & "です。" Case "B2", "C3" MsgBox "変更されたセルは" & Target.Address(False, False) & "です。" End Select Application.EnableEvents = True End Sub
対象シートのすべてのセルを変更してもこのプロシージャが実行されますので、
上記のように「Target.Address」を使用して処理を分岐します。
この時、Target.AddressではなくTarget.Address(False, False)と書くことで、
分岐用のアドレスを「$A$1」ではなく「A1」で書けるようになります。
こちらの方が読みやすいため、基本はこの記述を使用しましょう。
複数のセルを一括で編集した場合にも処理を実行する
上記のようにA1,B2,C3を変更した場合に処理を実行したいとします。
例として「入力したセル値を半角に統一しなおす」処理を考えましょう。
この時、Deleteキーでクリアしたり、Ctrl+Vで一気に貼り付けるなどで、
A1~C3セルを含むセル範囲を一括で編集した場合の処理も考えないといけません。
例えばA1:D4の値を一気に変更した場合には、
TargetにRange("A1:D4")がSetされていることになります。
これを利用し、A1,B2,C3セルへの処理を以下のように記述します。
Private Sub Worksheet_Change(ByVal Target As Range) If Intersect(Target, Me.UsedRange) Is Nothing Then Exit Sub Application.EnableEvents = False ' 対象セルの値が入力されたら半角に統一する Dim 変更セル As Range For Each 変更セル In Intersect(Target, Me.UsedRange) Select Case 変更セル.Address(False, False) Case "A1", "B2", "C3" 変更セル.Value = StrConv(変更セル.Value, vbNarrow) End Select Next Application.EnableEvents = True End Sub
このようにTarget内のセルをForEachステートメントでループすることで、
値の変更があったセルをすべてループすることが可能です。
本来なら「For Each 変更セル In Target」で済ませたいところなのですが、
この書き方だと列全体をクリアした際に104万セルに処理が走ってしまいます。
それを防ぐ目的で、セル範囲の交差範囲を取得するIntersectメソッドを利用し、
そのシートの使用範囲(UsedRange)との共通部分だけをループしてください。
セル値変更処理をセル範囲に一括設定する
特定のセル範囲(例:A1:C3)内のセルにまとめて処理を設定したい場合は、
対象のシートモジュールに以下のコードを記載します。
Private Sub Worksheet_Change(ByVal Target As Range) ' 実行対象範囲とTargetの交差範囲を取得 Dim 実行対象範囲 As Range Set 実行対象範囲 = Intersect(Target, Range("A1:C3")) If 実行対象範囲 Is Nothing Then Exit Sub Application.EnableEvents = False ' 対象セルの値が入力されたら半角に統一する Dim 変更セル As Range For Each 変更セル In 実行対象範囲 変更セル.Value = StrConv(変更セル.Value, vbNarrow) Next Application.EnableEvents = True End Sub
先ほどのIntersectメソッドをUsedRangeではなくマクロ設定範囲にすることで、
マクロを実行したいセルのみにForEachステートメントを回すことが出来ます。
セル範囲に一括でマクロを設定したい場合は、こちらのコードを活用して下さい。
データ内のセル値が変更された際にマクロを実行する
例えばこのような表データ内のセルの変更時にマクロを設定する場合を考えます。

例えば「価格または個数が変更された際に売り上げを更新する」場合は、
対象のシートモジュールに以下のコードを記載します。
Private Sub Worksheet_Change(ByVal Target As Range) Dim 実行対象範囲 As Range Set 実行対象範囲 = Intersect(Target, Me.UsedRange) If 実行対象範囲 Is Nothing Then Exit Sub Application.EnableEvents = False ' 対象セルの値が入力されたら半角に統一する Dim 変更セル As Range For Each 変更セル In 実行対象範囲 Dim R As Long: R = 変更セル.Row Dim C As Long: C = 変更セル.Column ' データ内のセルを対象 If R >= 4 Then ' 各列ごとの処理 Select Case C ' 価格または個数の変更時 Case 3, 4 Cells(R, 5) = Cells(R, 3) * Cells(R, 4) End Select End If Next Application.EnableEvents = True End Sub
セル値が変更されたセルの「.Row/.Column」を利用して分岐することで、
データ内のセルが変更された際の処理を整理して記述することが出来ます。
Target.Row、Target.Columnは何度も書くことが多いため、
上記サンプルのようにRやCなど変数に入れてしまいましょう。
処理を全シート分まとめて書きたい場合 - Workbook_SheetChange
今回の処理をひとつのプロシージャにまとめて書きたい場合は、
ThisworkbookモジュールのWorkbook_SheetChangeイベント
を使用することも可能です。
以下のコードをThisWorkbookに記載することで、
「複数シートのA1:C3セル」に一括でマクロを設定することが可能です。
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) ' Sheet1,2,3のChangeイベントをまとめて記載 Select Case Sh.Name Case "Sheet1", "Sheet2", "Sheet3" ' 実行対象範囲とTargetの交差範囲を取得 Dim 実行対象範囲 As Range Set 実行対象範囲 = Intersect(Target, Sh.Range("A1:C3")) If 実行対象範囲 Is Nothing Then Exit Sub Application.EnableEvents = False ' 対象セルの値が入力されたら半角に統一する Dim 変更セル As Range For Each 変更セル In 実行対象範囲 変更セル.Value = StrConv(変更セル.Value, vbNarrow) Next Application.EnableEvents = True End Select End Sub
引数「Sh」で選択セルが変更されたシートも受け取れるため、
サンプルのようにシート名をSelect Case で分岐することで、
ブック内の全シートのイベントをここにまとめて書くことが可能です。
- 同じ処理であれば1回書くだけで済む
- 全シートの処理の違いが一目瞭然になる
などのメリットがありますが、代わりにシートモジュールを見るだけではそのシートのイベントを一覧できなくなるデメリットもあります。
状況に応じて使い分けてください。