前項では、
以上の機能を実件するために、
を実装しました。
本章では、特にあるシートから別のシートを操るための処理に注目して話を進めたいと思います。
さて、まずは前章のDecoratorとfoo.xlsをリンクさせるための標準モジュールをもう一度示します。
public bdeco As New BookDecorator
Sub Test()
bdeco.Initialize Workbooks("foo.xls")
End Sub
|
このプログラムには、以下の2つの問題点があります:
後者について少し補足します。もし、foo.xls自体にマクロを実装した場合、ガーベジコレクション機能によって、参照されなくなったとき、すなわちfoo.xlsが閉じられたときにDecoratorは解放されます。しかし、別に実装した場合は、実装したブックを閉じるまでDecoratorは解放されません。ここでは簡便のために1つのブックしか扱わないので問題ではありませんが、複数のブックを扱う場合に問題になります。
この2つの問題点は、以下のような機能を実装すれば解決できます:
これらの機能は、ブックを開いたり、閉じたりするイベントをフックする事で実現できます。ブックを扱うイベントは、前章で示した3つのレベルで言えば、Excelアプリケーションのレベルになります。したがって、アプリケーションに機能を追加するAppDecoratorクラスを作成し、必要な処理を実装すればよいことになります。
実装の方に話を移しましょう。まずは、AppDecoratorの実装を全て示します:
Private WithEvents app As Application
Private bookDeco As BookDecorator
Public Sub Initialize()
Set app = Application
Dim wb As Workbook
For Each wb In Workbooks
If wb.Name = "foo.xls" Then
Set bookDeco = New BookDecorator
bookDeco.Initialize wb
End If
Next
End Sub
Private Sub Class_Terminate()
Set bookDeco = Nothing
End Sub
Private Sub app_WorkbookOpen(ByVal wb As Workbook)
If wb.Name = "foo.xls" Then
Set bookDeco = New BookDecorator
bookDeco.Initialize wb
End If
End Sub
Private Sub app_WorkbookBeforeClose(ByVal wb As Workbook, Cancel As Boolean)
If wb.Name = ("foo.xls") Then
Set bookDeco = Nothing
End If
End Sub
|
では部分ごとに見ていきましょう。まずはメンバ変数です。
Private WithEvents app As Application Private bookDeco As BookDecorator |
Public Sub Initialize()
Set app = Application
Dim wb As Workbook
For Each wb In Workbooks
If wb.Name = "foo.xls" Then
Set bookDeco = New BookDecorator
bookDeco.Initialize wb
End If
Next
End Sub
|
初期化の部分です。まずapp変数でアプリケーションとマクロのリンクを設定し、その後foo.xlsが開いていたらBookDecoratorを確保します。ここで、foo.xlsの存在はWorkbooksコレクションで調べています。
Private Sub Class_Terminate()
Set bookDeco = Nothing
End Sub
|
Class_という始まりのメソッドは、クラスに関するイベントを表します。Class_Initialize()はそのクラスのインスタンスが確保された直後に、Class_Terminate()は逆に解放される直前に呼び出されます(前者がコンストラクタ、後者がデストラクタですね)。これらの処理はイベントなので、イベントの中身だけを書いておけば勝手に呼び出されるので、呼び出し忘れを未然に防ぐことができます。
ここではClass_Terminate()イベントのみをフックしています。ここでは、解放が失敗したときのために、Decoratorを明示的に解放しています。
Private Sub app_WorkbookOpen(ByVal Wb As Workbook)
If Wb.Name = "foo.xls" Then
Set bookDeco = New BookDecorator
bookDeco.Initialize Wb
End If
End Sub
Private Sub app_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
If Wb.Name = ("foo.xls") Then
Set bookDeco = Nothing
End If
End Sub
|
この部分は非常に単純です。ApplicationのWorkbookOpenイベントとWorkbookBeforeCloseイベントをフックし、変数bookDecoの確保・解放をおこなっています。
これまで、AppDecoratorの実装について説明してきました。AppDecoratorはBookDecoratorを、BookDecoratorはSheetDecoratorを(前項参照)それぞれ管理していますから、マクロを書いたブックは、AppDecoratorだけを管理すれば十分です。そこで、マクロを書いたブックを開いたときにAppDecoratorの取得と初期化をするルーチンを追加すればよいことになります。しかし、自分自身の初期化はClass_Initializeイベントで設定されていますから、単純にAppDecoratorのインスタンスを作るだけで大丈夫です:
[AppDecoModule] Public appDeco As New AppDecorator Sub Initialize() appDeco.Initialize End Sub |
これで、全ての機能を実装することが出来ました。