久方ぶりにVBAを書くことになったのでその時の新たな発見
C#ではイベントハンドラーにラムダ式を突っ込んだりしてたが、VBAで動的に関数を切り替える方法を知らなかった。
今回、その方法を知ることができたのでまとめる
とその前にWithEventsというやつを説明するのでそのために
英字を受け付けないTextBox(疑似拡張コントロール)を作ってみる
作るもの
手順
1.ユーザーフォームを追加(UserForm1とする)
2.クラスモジュール(CustomCrl)に
Private pvForm As MSForms.UserForm
Private WithEvents myTextBox As MSForms.TextBox '※1
Public Property Set SetForm(ByRef aForm As MSForms.UserForm)
Set pvForm = aForm
Call ControlAdd
End Property
Private Sub ControlAdd()
'ProgIDを指定してTextBoxのインスタンス生成+追加
Set myTextBox = pvForm.Add("Forms.TextBox.1") '※2
With myTextBox
.Left = 10
.Top = 10
.Width = 100
.Height = 15
End With
End Sub
Private Sub myTextBox_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
pvForm.Caption = Chr(KeyCode) + CStr(KeyCode)
'英字のみ不可。半角数字は可。バックスペースは可。全角も可
If 65 <= KeyCode And KeyCode <= 90 Then
KeyCode = 0
End If
End Sub
3.標準モジュールに
Sub 拡張コントロール()
Dim Custom1 As New CustomCrl
Set Custom1.SetForm = UserForm1
UserForm1.Show
End Sub
フロー説明
初期化の過程としては
拡張コントロール()を呼び出す
↓
CustomCrlクラスを初期化し、UserForm1を格納する
↓
UserForm1を受け取ったクラスはUserForm1にTextBoxを追加する
※1
クラスモジュールに
Private WithEvents myTextBox As MSForms.TextBox
と宣言しTextBoxを格納することで、ControlCrsクラスは格納したTextBoxでハンドルされるイベント処理を記述することができるようになる
※2
Set myTextBox = pvForm.Add("Forms.TextBox.1")
この記述により、追加されたコントロールでKeyDownイベントが発生したとき
myTextBox_KeyDownが処理されるようになる
結語
WithEventsで宣言したコントロールを変数に持つクラスで、該当のコントロールをラップすることにより、
標準モジュールの処理次第でラップクラスの切り替え、動的にフォームの内容を変更できる
この例では標準モジュールの記述でUserFormにカスタムTextBoxを追加したが、
ユーザーフォーム内のコードでCustomCrlの生成・操作も可能
その場合、ユーザーフォームから見れば、自身と追加されるであろうコントロールをラップしたインスタンスを変数に持つことになる。
また、UserFormではなくPageを親コントロールとすることもできるし、Object型にして使いまわすことも可。
気が向いたら続きを書く