多くのテキスト ボックスを含むユーザー フォームがあります。これらのテキスト ボックスの値が変更されるたびに、サブルーチン AutoCalc() を呼び出して、テキスト ボックスの値に基づいて最終結果の値を再計算する必要があります。
私は約25個のボックスを持っていますが、前述のサブルーチンを呼び出す各テキストボックスにChange()イベントを個別に追加したくありません。値が変更されるたびに AutoCalc() を呼び出す最も迅速で効率的な方法は何ですか?
多くのテキスト ボックスを含むユーザー フォームがあります。これらのテキスト ボックスの値が変更されるたびに、サブルーチン AutoCalc() を呼び出して、テキスト ボックスの値に基づいて最終結果の値を再計算する必要があります。
私は約25個のボックスを持っていますが、前述のサブルーチンを呼び出す各テキストボックスにChange()イベントを個別に追加したくありません。値が変更されるたびに AutoCalc() を呼び出す最も迅速で効率的な方法は何ですか?
これは、クラス モジュールを使用して実現できます。次の例では、いくつかのテキスト ボックスを含むユーザー フォームが既にあると仮定します。
まず、VBA プロジェクトでクラス モジュールを作成します (それを呼び出しclsTextBox
ます。クラス モジュールの 'Name' プロパティを必ず変更してください)。
Private WithEvents MyTextBox As MSForms.TextBox
Public Property Set Control(tb As MSForms.TextBox)
Set MyTextBox = tb
End Property
Private Sub MyTextBox_Change()
AutoCalc() //call your AutoCalc sub / function whenever textbox changes
End Sub
次に、ユーザーフォームに次のコードを追加します。
Dim tbCollection As Collection
Private Sub UserForm_Initialize()
Dim ctrl As MSForms.Control
Dim obj As clsTextBox
Set tbCollection = New Collection
For Each ctrl In Me.Controls
If TypeOf ctrl Is MSForms.TextBox Then
Set obj = New clsTextBox
Set obj.Control = ctrl
tbCollection.Add obj
End If
Next ctrl
Set obj = Nothing
End Sub
上記の回答が示唆するように、クラスの使用は、多くのコントロールを簡潔かつエレガントな方法で処理するための優れた戦略ですが、次のようになります。
1)コントロールの数が動的でない限り、1行で25のイベントを作成し、共通のユーザーフォームプライベートルーチンを呼び出すことに問題はありません。それがKISSの哲学です。
2) 一般に、Changeイベントは、入力された各桁の再計算をすべて行うため、非常に厄介だと思います。値を決定するときにのみ再計算が行われるため、 ExitイベントまたはBefore Updateイベントを使用してこれを行う方が賢明で適度です。たとえば、Google Instantは、ユーザーが質問を定義せずに、リソースを消費して応答を返そうとするのを悩ませます。
3) 検証に問題がありました。Changeイベントで間違ったキーを回避できることに同意しますが、データを検証する必要がある場合、ユーザーが入力を続けるかどうか、またはデータを検証する準備ができているかどうかを知ることはできません。
4) ChangeまたはExitイベントはユーザーにテキスト フィールドへの入力を強制しないことを覚えておく必要があります。そのため、キャンセルせずにフォームを終了しようとすると、システムを再検証して再計算する必要があります。
次のコードは単純ですが、静的フォームに効果的です。
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Call AutoCalc(Cancel)
End Sub
Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Call AutoCalc(Cancel)
End Sub
.....
Private Sub TextBox25_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Call AutoCalc(Cancel)
End Sub
Private Function Valid
.....
End Function
Private Sub AutoCalc(Canc As Variant)
If Not Valid() Then Canc=True
' Calculation
End Sub
時間を節約することに夢中になっている場合は、一般的な VBA ルーチンを作成して、マスクに適合する形式でコントロールに関連するイベントのコードを生成できます。このコードは、フォーム モジュールにコピー アンド ペーストするよりも、下書きシート (一部の Excel バージョンではバグがあるコードを直接生成する方が安全です) に含めることができます。
Sub GenerateEvent(Form As String, Mask As String, _
Evento As String, Code As String)
' Form - Form name in active workbook
' Mark - String piece inside control name
' Evento - Event name to form procedure name
' Code - Code line inside event
Dim F As Object
Dim I As Integer
Dim L As Long
Dim R As Range
Dim Off As Long
Set F = ThisWorkbook.VBProject.VBComponents(Form)
Set R = ActiveCell ' Destination code
Off = 0
For I = 0 To F.Designer.Controls.Count - 1
If F.Designer.Controls(I).Name Like "*" & Mask & "*" Then
R.Offset(Off, 0) = "Private Sub " & _
F.Designer.Controls(I).Name & "_" & Evento & "()"
R.Offset(Off + 1, 0) = " " & Code
R.Offset(Off + 2, 0) = "End Sub"
Off = Off + 4
End If
Next I
End Sub
Sub Test()
Call GenerateEvent("FServCons", "tDt", "Exit", _
"Call AtuaCalc(Cancel)")
End Sub
テキストボックスの変更に応答するクラスを作成する方法については、これをご覧ください。例はボタン用ですが、変更できます。ただし、Textbox コントロールには Exit イベントがないことに注意してください (このイベントは実際にはユーザー フォームの一部です)。そのため、実際には Change イベントを使用する必要があります。
ただし、Textbox コントロールには Exit イベントがないことに注意してください (このイベントは実際にはユーザー フォームの一部です)。そのため、実際には Change イベントを使用する必要があります。
よくわかりません。たぶんこれは2007年に追加されたものか、ニュアンスがわからないのかもしれません。TextBox コントロールで Exit イベントを使用します。コントロールから Tab キーを押すか、別のコントロールでマウスをクリックすると、Exit イベントがトリガーされます。