3.2 イベントをフックする

マクロはブックの中にしか記載できない以上、マクロとブックを分離するには、マクロだけを独立したブックに保存し、そこから他のブックを参照しながらマクロを使うことになります。一つのブックの中にマクロを書く場合には、シート1のためのマクロはsheet1に、ブックのためのマクロはThisWorksheetに書けばいいのですが、それでは不特定多数のブックを参照できません。したがって、そのための機構が必要です。

ここではブックを考えてみましょう。他のブックを扱うためには、どのような処理を書けばいいのでしょうか。まずはごく単純な例で見てみましょう:


Dim wb As Workbook
Set wb = Workbooks("foo.xls")
MsgBox wb.Worksheets("goo").Cells(1, 1)

このように書けばとりあえず参照できます。しかし、ワークブックに関するイベントを取得することはできません。

実は、Excelには、イベントを取得することのできるクラスを作成することができます。そのためには、変数をWithEventsというキーワードとともに宣言し、そこにイベントをフックしたいオブジェクトへの参照を格納すればよいことになります。以下に、BeforeSaveイベントをフックし、ブックを保存する際に確認のメッセージを出すクラスを示します。なお、BeforeSaveイベントの中身はExcelVBAのヘルプにあるものを一部改変したものです。


[class1]

Private WithEvents wbook As Workbook

Sub Initialize(wb As Workbook)
    Set wbook = wb
End Sub

Private Sub wbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    Dim f As Boolean
    f = MsgBox("ブックを本当に保存してよろしいでしょうか。", vbYesNo)
    If f = vbNo Then Cancel = True
End Sub

今作ったクラスを呼び出すモジュールを作ってみましょう。ここでは、すでに開いているfoo.xlsという名前のブックにフックするテストプログラムを示します:


[module]
public cls1 As New class1

Sub Test()
    cls1.Initialize Workbooks("foo.xls")
End Sub

これを実行すると、ブックfoo.xlsが開いていれば、それを保存する際に確認のメッセージを出すようになります。変数cls1はモジュール変数ですから、Testプロシージャを一度実行すれば、マクロの書いてあるブックを閉じるまで有効です。

ここまで、ブックのイベントを別クラスでフックできることを示しました。同様にして、ブックを統括するアプリケーションや、ブックの部分であるシートのイベントもフックすることが出来ます。