t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Access VBAでフォームのコントロールイベント共通化

前回紹介したExcel VBAのユーザーフォームに動的メニューを追加する方法を紹介した。
thom.hateblo.jp

ただ、実は作りたかったのはAccessで、連票フォームのフッター領域にそれを配置したかったのだ。
f:id:t-hom:20171216122925p:plain

慣れないAccessと格闘する前にまずExcelフォームでプロトタイプを作ろうと思い立ったのが前回の記事。

Accessフォームで発生した問題

さて、Accessに移植するにあたり、ひとつハマったことがある。
すごく単純なことだけど、コントロールイベントをクラスで検知しようとした際に、うまく動かなかったのだ。
原因はボタンのクリック時イベントに、[イベントプロシージャ]を選択していなかったこと。

今回はこれについて順を追って説明する。

まず以下のようなフォームを作成した。
f:id:t-hom:20171216123618p:plain

それから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ならこれだけで動く。

ところがフォームを起動してボタンを押してもうんともすんとも言わない。

解決策

調べた結果、ボタンのプロパティでクリック時イベントが空だと、いくらイベント検知のコードがあっても動かないらしい。
f:id:t-hom:20171216124457p:plain

ということで全ボタンを選択し、クリック時プロパティのプルダウンからイベントプロシージャを選択。
f:id:t-hom:20171216124749p:plain

これで、無事にイベントを検知できるようになった。

仕様の推察

Excelの場合はボタンをクリックした際のイベントはVBAで書くと決まっているのでイベントを検知したら即、対応するコードが実行される。
Accessでは事情が異なり、クリックイベント=VBAとは限らない。

試しにボタンを配置した後、デザインモードでクリックしてイベントのビルドを選択してみる。
f:id:t-hom:20171216130354p:plain

すると、ビルダーの選択画面が出てきて、コード(VBA)以外にも、式・マクロといったAccess機能でイベントを作成できることがわかる。
f:id:t-hom:20171216130738p:plain

クリック時プロパティに明示的に[イベントプロシージャ]を設定しておくと、Accessにコードを実行するということが伝わり、対応するコードが実行される。

普通にイベントをビルドした場合は問題ないが、今回のようにコントロールイベントを共通化する際は明示的にイベントのビルドを行わないので、この設定が必要である。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。