複数のコントロールのイベント処理を1つのプロシージャに集約する方法です。
集約するというのは、例えば、フォームの中のテキストボックス全部について、GotFocusイベントが走る時に必ず所定の処理を走らせる、というものです。
これが何の役に立つかと言えば、例えば、「フォーカスがあるテキストボックスだけ背景色を変える」機能を実装する際、コーディングの量を減らすことができ、作業が楽になります。
方法ですが、WithEventsキーワードを使用してイベンドハンドラを自作することで実装します。
以下、具体的に解説しましょう。
集約しない場合どうなるか
例えば、Form1という名前のフォームにTextBox1、TextBox2という名前のテキストボックス2つがあるとします。
以下のような感じですね。
フォーカス時の背景色だけを変える処理を実装する場合、もし処理を集約しないと、VBAで以下のでコーディングを実装しないといけません。
'フォーカス取得時に背景色を変える
Private Sub TextBox1_GotFocus()
TextBox1.BackColor = RGB(239, 242, 247)
End Sub
'フォーカス喪失時に背景色を戻す
Private Sub TextBox1_LostFocus()
TextBox1.BackColor = vbWhite
End Sub
'フォーカス取得時に背景色を変える
Private Sub TextBox2_GotFocus()
TextBox2.BackColor = RGB(239, 242, 247)
End Sub
'フォーカス喪失時に背景色を戻す
Private Sub TextBox2_LostFocus()
TextBox2.BackColor = vbWhite
End Sub
1つのテキストボックスに対し、フォーカス取得時(GotFocusイベント)に背景色を変える処理、フォーカス喪失時(LostFocusイベント)に背景色を戻す処理という、合計2つの処理を各々のコントロールに対して実装する必要があります。
テキストボックスの数が多くなるとコーディングの量が増加して修正箇所も多くなり、効率が悪いです。
各イベント処理を1つのイベントハンドラにまとめる(WithEventsを使用する)
Access VBAでも、複数のイベント処理を1つのイベントハンドラにまとめることが可能です。
ちなみに、.NETだと、この手の処理を簡単に実装できるのですが、VBAは工夫が必要です。
ここで、用語が出てきたので整理します。
・イベント
フォーカス取得後・喪失後、起動後、終了時、キー入力時など、何らかの動作のこと。
・イベントハンドラ
イベントが発生した際に実行される処理のことです。
上でも挙げたTextBox1_GotFocus()とTextBox2_GotFocus()がそれになります。
どちらも「フォーカス取得後」です。
WithEventsキーワード
WithEventsキーワードに関しては以下のMicrosoftのドキュメントに解説があります。
Dimステートメントの解説ですがPrivateでもPublicでも同じです。
イベント処理の集約をするには、イベントハンドラを新たに実装しなければいけませんが、このWithEventsを使うのがポイントです。
オブジェクトの宣言では以下のように書きます。
Private WithEvents txtevent As TextBox
注意点としては、WithEventsキーワードを使用したオブジェクトは、配列にはできません。
1つのオブジェクトに1つのコントールが紐づきますので、作り方を工夫する必要があります(今回は複数のテキストボックスのイベントを1つのイベントハンドラに記述するので)。
具体的な実装方法は以下の通りです。
全体像と概念図
まず、Form1とは別のクラスを作成し、その中にイベントハンドラを記述します。
それを仮にclsEventsクラスとしましょう。
そのクラスを、Form1の中でオブジェクト配列として使用します。
UMLのクラス図で分かりやすく図示してみました(記法が間違っていたらごめんなさい)。
こうすることで、複数のコントロールのイベント処理を1つのイベントハンドラに実装できます。
具体的な実装方法
まず、clsEventsクラスを作成します。
clsEvents
clsEventsクラスの中身は以下の通りです。
Option Compare Database
Option Explicit
Private WithEvents txtevents As TextBox
'TextBoxをセットするプロパティ
Public Property Let setTextBox(ByVal tb As TextBox)
Set txtevents = tb
txtevents.OnGotFocus = "[EVENT PROCEDURE]"
txtevents.OnLostFocus = "[EVENT PROCEDURE]"
End Property
'フォーカス取得後処理
Private Sub txtevents_GotFocus()
txtevents.BackColor = RGB(239, 242, 247)
End Sub
'フォーカス喪失後処理
Private Sub txtevents_LostFocus()
txtevents.BackColor = vbWhite
End Sub
Private Sub Class_Terminate()
Set txtevents = Nothing
End Sub
イベントに応答するオブジェクトをtxteventsとして宣言しています。
また、イベントハンドラもこのクラス(clsEvents)の中に書きます。
GotFocusでフォーカス時の背景色を変え、LostFocusでフォーカス喪失時に背景色を白に戻します。
注意点ですが、OnGotFocusプロパティとOnLostFocusプロパティに、文字列”[EVENT PROCEDURE]”をセットする必要があります。
(イベントプロシージャとして実行する場合はこれがないと動作しません。MicrosoftのVBAリファレンスにも書いてありますので、参考までにどうぞ)。
補足ですが、WithEventsでオブジェクトを宣言すると、下の画像のように画面からイベントが選択できるようになります。
Form1
Form1のVisual Basicコードは以下の通り。
Option Compare Database
Option Explicit
Private events() As New clsEvents
'起動時処理
Private Sub Form_Load()
Dim c As Control
'TextBoxをセット
ReDim Preserve events(0)
For Each c In Me.Controls
Select Case TypeName(c)
Case "TextBox"
ReDim Preserve events(UBound(events) + 1)
events(UBound(events)).setTextBox = c
End Select
Next
End Sub
'終了時処理
Private Sub Form_Close()
Erase events
End Sub
clsEventsクラスを、eventsオブジェクトの配列として宣言します。
フォーム起動時に、型が”TextBox”のコントロールだけをevents配列にセットしていきます。
フォーム終了時には配列を消去してやります。
これで、必要なコードは書けました。
フォームを表示させてみると、フォーカスがあるテキストボックスだけ背景色が設定され、外れると白に戻るはずです。
イベントハンドラが2つある時はどうなる?
clsEventsとForm1の両方に同じイベントを記述すると、どうなるでしょうか?
ちょっと、試してみました。
Form1に、TextBox01のGotFocusイベントを追加します。
(メッセージを出して、背景を薄い緑色に変える処理)
'Form1のGotFocusイベント
Private Sub TextBox01_GotFocus()
MsgBox "背景を緑にする処理"
Me.TextBox01.BackColor = RGB(226, 240, 217)
End Sub
Form1を立ち上げると、以下のようになりました。
Form1側のイベント処理もきちんと実行されているようです。
「OK」を押すと、こうなります。
clsEvents側のイベント処理も実行されているようです。
つまり、①フォーム側のイベント処理 → ②追加したイベントハンドラ側の処理、という順序になっているようですね。
以上です。
終わり。