t-hom’s diary

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

VBA フォームのコントロールイベントを共通化する

こちらの記事を読んだところ、同じようなChangeイベントプロシージャがコントロールの数だけできてしまうことにお悩みの様子。
kantoku.hatenablog.com

面白そうなので色々調べながらやってみた。

参考にしたページはこちら
3.4.3 共通イベント処理クラス - EXCEL-VBA開発講座

ateitexe.com


まずEventControlというクラスモジュールを用意した。
コードはこちら

Public WithEvents chk As MSForms.CheckBox
Public WithEvents txt As MSForms.TextBox

Public Sub セット(ByRef Con As MSForms.Control)
    Select Case TypeName(Con)
    Case "CheckBox"
        Set chk = Con
    Case "TextBox"
        Set txt = Con
    Case Else
        Err.Raise 1000, "EventControl", "想定外のコントロールです。"
    End Select
End Sub

Private Sub chk_Change()
    Call 共通イベント(chk)
End Sub

Private Sub txt_Change()
    Call 共通イベント(txt)
End Sub

Private Sub 共通イベント(C As MSForms.Control)
    MsgBox C.Name & "が変更されました。"
End Sub

クラスモジュール内でオブジェクト変数の宣言にWithEventsを付けるとイベントを捕捉できるようになる。
MSForms.Control型というのもあったがこちらではイベント捕捉ができないようなので、諦めてtxtとchkの二種類を用意する。このあたり、ちょっとダサい。。

そうすると、chk_Changeとtxt_Changeのイベントで共通イベントが呼び出される。

メインのサンプルフォームはこんな感じで適当に用意した。
f:id:t-hom:20160311203719p:plain

そしてフォームのコードはこちら

Dim コントロールコレクション As Collection

Private Sub UserForm_Initialize()
    Set コントロールコレクション = New Collection
    Dim Con As Control
    Dim EC As EventControl
    For Each Con In Me.Controls
        Select Case TypeName(Con)
        Case "CheckBox", "TextBox"
            Set EC = New EventControl
            EC.セット Con
            コントロールコレクション.Add EC
        End Select
    Next
End Sub

コレクションをモジュールレベル変数としている。
フォームのInitialize時に先ほど作ったEventControl型にコントロールをセットしていく。(ただしテキストボックスとチェックボックスのみ)

これを実行すると、どのチェックボックス・テキストボックスを変更してもEventControlクラスの共通イベントが実行される。
f:id:t-hom:20160311204029p:plain

やや複雑になってはしまうけれど、クラスを汎用的に設計しておけば再利用できて便利だと思う。

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