初投稿です。
#一つのフォームを使い回すときの小技
VBAぐらいしか使えるものがない環境でフォームを使ってGUIを作るときにフォームの見た目を違う処理で使い回す場合に使っている小技。
##使い回せないやり方
Private WithEvents MyForm As UserForm1
フォームをそのまま上記のように書いてもUserForm1自体はイベントを持っていないので動作しない。
Private WithEvents MyForm As MSForms.UserForm
のようにMSFormsのUserForm型を指定すれば一部のイベントは有効になるが、ActivateやQueryCloseなどの機能が使えない。
以前はここでUserForm1側に処理の実態を書いていたが、同じような見た目でラベル名などを変えて使い回すときに不便。
##今回考えたやり方
そこで考えたのがUserForm1自体にそのイベントをリレーさせるためのイベントを用意するという方法。
Public Event Activate()
Public Event QueryClose(ByRef Cancel_ As Integer, ByRef CloseMode_ As Integer)
Private Sub UserForm_Activate()
RaiseEvent Activate
End Sub
Private Sub UserForm_QueryClose(ByRef Cancel As Integer, ByRef CloseMode As Integer)
RaiseEvent QueryClose(Cancel, CloseMode)
End If
この方法ならクラス側で最初の例のようにUserForm1型でイベントをキャッチできるようになる。
必要なイベントだけリレー用の処理を書けばいい。
この処理を書いたUserForm1を他のクラス上でNewして新規に渡せば同じフォームをベースにした複数のフォームを独立して使用できる。
※UserForm1などのフォームはただのVB_PredeclaredIdがTrueになってるクラスなのでクラスで使う場合は個別にNewする。
複数の場所でSet MyForm = UserForm1をしてしまうと同じインスタンスを参照することになる。
Set MyForm = New UserForm1 '新規インスタンス
Set MyForm = UserForm1 'PublicなUserForm1という名前の変数に作成されたインスタンス
##ちょっと凝ったことをする場合
そのまま渡すとちょっと引数が分かりにくいので下記のように自分で発行するイベントの引数の型はわかりやすいように変更してもいい。
Public Event QueryClose(ByRef Cancel As Boolean, ByRef CloseMode As VbQueryClose)
Private Sub UserForm_QueryClose(ByRef Cancel As Integer, ByRef CloseMode As Integer)
Dim RefCancel As Boolean
Dim RefCloseMode As VbQueryClose
RefCancel = Cancel
RefCloseMode = CloseMode
RaiseEvent QueryClose(RefCancel, RefCloseMode)
Cancel = RefCancel
CloseMode = RefCloseMode
End Sub
ただしBooleanはともかく、VbQueryCloseはEnumであるためIntegerの範囲外の値を入れられる。
わざと作らない限りはエラー処理は不要だがIntegerの範囲外の値を戻すことも一応は可能なので必要に応じて範囲外の値を弾く処理を入れることもあるかもしれない。