Excel VBAで同じ処理を複数シートに使い回したい場合、標準モジュールに処理を書いて各シートからCallする構成は非常によく使われます。しかし、その際に「オブジェクトが必要です」というエラーが発生して困るケースがあります。
特にWorksheet_Changeイベントをモジュールへ移そうとした時に発生しやすく、VBA初心者がつまずきやすいポイントでもあります。
この記事では、なぜ「オブジェクトが必要です」エラーになるのか、そして複数シート共通化する正しいVBAの書き方をわかりやすく解説します。
『オブジェクトが必要です』が出る原因
今回のコードでは、以下の部分でエラーが発生しています。
If Target.Address <> "$B$2" Then Exit Sub
これは、標準モジュール側では「Target」が存在しないためです。
TargetはWorksheet_Changeイベント専用の引数であり、シートイベント内でのみ自動的に渡されます。
つまり、標準モジュールへそのまま移動するとTargetが未定義になるため、オブジェクトエラーになります。
複数シート対応する正しい考え方
VBAで複数シート共通処理を作る場合は、以下のように役割を分けるのが基本です。
| 場所 | 役割 |
|---|---|
| 各シート | イベント受け取り |
| 標準モジュール | 実際の処理 |
つまり、Worksheet_Changeで受け取ったTargetを、標準モジュールへ引数として渡します。
正しいコード例
まず、標準モジュールに以下を書きます。
Public Sub ChangeDateFormat(Target As Range)
If Target.Address <> "$B$2" Then Exit Sub
Call setCalendarDateForCell(Target)
Dim num As Long
num = CLng(Format(Target.Value, "yyyymmdd"))
Target.Value = num
Target.NumberFormatLocal = "G/標準"
End Sub
次に、各シートモジュール側には以下を書きます。
Private Sub Worksheet_Change(ByVal Target As Range)
Call ChangeDateFormat(Target)
End Sub
この形にすると、複数シートで同じ処理を簡単に再利用できます。
Range(“B2”)を直接書かない方がよい理由
元コードでは以下のように固定セル指定されていました。
Range("B2").Value = num
これでも動作することはありますが、複数シートで使う場合はTargetを使う方が安全です。
理由は、アクティブシートが変わった際に意図しないシートのB2を操作する危険があるためです。
特にイベント処理では、どのシートから呼ばれたかを明確にすることが重要です。
複数セル変更時にも注意
Worksheet_Changeは、複数セル貼り付けでも発火します。
そのため、以下のようなチェックを追加するとさらに安全です。
If Target.Count > 1 Then Exit Sub
これを入れておくと、複数セル操作時の誤動作を防げます。
イベントループにも注意する
VBAでセル値を書き換えると、再びWorksheet_Changeが発火する場合があります。
そのため、本格的な処理では以下を使うケースもあります。
Application.EnableEvents = False
処理終了後には必ずTrueへ戻します。
Application.EnableEvents = True
これを忘れるとExcel全体のイベントが止まるため注意が必要です。
共通化すると保守がかなり楽になる
今回のように標準モジュールへ処理をまとめると、修正箇所が1つで済みます。
例えば10シートで同じ処理をしていても、標準モジュールを直すだけで全シートへ反映できます。
これは実務VBAでも非常によく使われる設計方法です。
まとめ
VBAで「オブジェクトが必要です」エラーになる原因は、Worksheet_Change専用のTargetを標準モジュール内で直接使っていたためです。
複数シート共通化する場合は、シートイベントで受け取ったTargetを引数として標準モジュールへ渡す構成にすると綺麗に動作します。
また、Targetを使うことでシート依存の不具合も防げるため、実務でも非常に重要な考え方になります。


コメント