値の変更時のイベントプロシージャで変更前の値を確認する

ワークシートの内容が変更されるとChangeイベントが発生します。このときに自動実行させるマクロはWorksheet_Change イベントプロシージャとして作成します。発動の時点で値は変更済みなので通常は変更前の値は確認できません。しかし、Worksheet_SelectionChangeイベントプロシージャと組み合わせることで、それを実現できます。

変更メッセージ

値を変えなくても「Change」
Changeイベントは、セルを編集状態にしてそのまま確定した場合も発生します。このため、値が変更された場合だけ処理を実行するには、変更前の値との比較が必要になります。

Worksheet_SelectionChange と Worksheet_Change の連携

Option Explicit
'============================
'宣言セクション
Dim VAL As Variant
'============================
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    
    On Error GoTo ENDUP
    If Intersect(Target, Range("変更管理")) Is Nothing Then Exit Sub
    If Target.Cells.Count <> 1 Then Exit Sub
    
    VAL = Target.Value

ENDUP:
End Sub
'============================
Private Sub Worksheet_Change(ByVal Target As Range)

    On Error Resume Next
    
    If Intersect(Target, Range("変更管理")) Is Nothing Then Exit Sub
    If Target.Cells.Count <> 1 Then Exit Sub
    
    If Target.Value <> VAL Then
        MsgBox Target.Address & " の値が変更されました" & vbCrLf & _
               "元の値 : " & VAL
    End If    
End Sub

ポイント解説

宣言セクションの変数で値の受け渡し

Worksheet_SelectionChangeは、ワークシートで選択操作をしたときに発動するプロシージャです。ここで変更前の値を取得し、宣言セクションのVAL変数に入れています。値の変更で発動したWorksheet_Changeでは、VAL変数の値と現在の値を比較できるようになります。

宣言セクションの変数
宣言セクションは、Option Explicit の次行からプロシージャ(Sub)の前までの記述を指します。ここで宣言した変数は、各プロシージャで共通の変数になります。プロシージャの終了時に値がリセットされないので、次のプロシージャへの引継ぎが可能になります。

発動頻度とエラーの対策

SelectionChangeイベント、Changeイベントともに、ワークシートの操作中に高頻度で発生します。ユーザー操作のストレスにならないように対策しましょう。

複雑な処理を避ける

複雑な処理を組み込むと、操作のたびに引っかかるような動きになって使いにくくなります。処理の内容はシンプルかつ最小限にしましょう。

処理の実行条件を絞り込む

SelectionChangeイベントはシートのどこかを選択するたびに発生し、Change イベントは値の変更以外にも行・列の追加や削除などでも発生します。不要な場面で処理が実行されないよう、条件を絞り込みます。

実行開始は避けられないので、条件に外れる場合はすぐに Exit Sub で抜けるようにします。上記サンプルでは、名前を付けた範囲内の1セルが操作された場合を条件としています。

Intersect関数で範囲の確認
Intersectは、2つのRangeの重なりを返す関数です。
Intersect(Target, Range("変更管理")) Is Nothing は、Target は “変更管理”範囲の外にあることを表します。
エラーの対策

目的の操作以外でも発動するのでTargetの中身は意図しない状態になったりします。On Error GoToOn Error Resume Next でエラーの発生に備えておきます。

例えば、シートで全選択するとSelectionChangeイベントが発生しますが、その状態では Target.Cells.Count はエラーになります。エラーにならないように制御するのではなく、エラーになったら処理を抜けるようにしています。

イベント発動の一時停止スイッチ : Application.EnableEvents

上記コードでは使っていませんが、イベントプロシージャの処理でセル入力などを行う場合は注意が必要です。その場合もChangeイベントが発生し、Worksheet_Changeプロシージャが実行されるためです。

無限入れ子のループになるような場合は、EnableEventsプロパティを使います。このプロパティで、イベントに対する反応を一時的に停止できるようになります。

Application.EnableEvents = False
' ----------------------
' イベント発動停止中の処理
' ----------------------
Application.EnableEvents = True

このマクロを応用したものを以下で紹介しています。

 

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