前回紹介したExcel VBAのユーザーフォームに動的メニューを追加する方法を紹介した。
thom.hateblo.jp
ただ、実は作りたかったのはAccessで、連票フォームのフッター領域にそれを配置したかったのだ。
慣れないAccessと格闘する前にまずExcelフォームでプロトタイプを作ろうと思い立ったのが前回の記事。
Accessフォームで発生した問題
さて、Accessに移植するにあたり、ひとつハマったことがある。
すごく単純なことだけど、コントロールイベントをクラスで検知しようとした際に、うまく動かなかったのだ。
原因はボタンのクリック時イベントに、[イベントプロシージャ]を選択していなかったこと。
今回はこれについて順を追って説明する。
まず以下のようなフォームを作成した。
それからVBEでクラスモジュールを挿入し、オブジェクト名をButtonWrapperとした。
コードは以下のとおり。
Public WithEvents btn As CommandButton Private Sub btn_Click() MsgBox btn.Caption & "がクリックされました。" End Sub
フォーム本体のコードは次の通り。
Private Buttons As Collection Private Sub Form_Load() Set Buttons = New Collection For i = 0 To 4 Dim b As ButtonWrapper Set b = New ButtonWrapper Set b.btn = Me.Controls("コマンド" & i) Buttons.Add b Next End Sub
こうすると、コマンド0からコマンド4までの5つのボタンがButtonWrapperオブジェクトに包まれてCollection(Buttons)に格納される。
ButtonWrapper内ではボタン用の変数btnがWithEventsで宣言されているので、ボタンごとにイベントを書かなくてもこれでイベントを検知できる。
これだけで動くと思っていた。
実際、Excel VBAならこれだけで動く。
ところがフォームを起動してボタンを押してもうんともすんとも言わない。
解決策
調べた結果、ボタンのプロパティでクリック時イベントが空だと、いくらイベント検知のコードがあっても動かないらしい。
ということで全ボタンを選択し、クリック時プロパティのプルダウンからイベントプロシージャを選択。
これで、無事にイベントを検知できるようになった。
仕様の推察
Excelの場合はボタンをクリックした際のイベントはVBAで書くと決まっているのでイベントを検知したら即、対応するコードが実行される。
Accessでは事情が異なり、クリックイベント=VBAとは限らない。
試しにボタンを配置した後、デザインモードでクリックしてイベントのビルドを選択してみる。
すると、ビルダーの選択画面が出てきて、コード(VBA)以外にも、式・マクロといったAccess機能でイベントを作成できることがわかる。
クリック時プロパティに明示的に[イベントプロシージャ]を設定しておくと、Accessにコードを実行するということが伝わり、対応するコードが実行される。
普通にイベントをビルドした場合は問題ないが、今回のようにコントロールイベントを共通化する際は明示的にイベントのビルドを行わないので、この設定が必要である。