8

多くのテキスト ボックスを含むユーザー フォームがあります。これらのテキスト ボックスの値が変更されるたびに、サブルーチン AutoCalc() を呼び出して、テキスト ボックスの値に基づいて最終結果の値を再計算する必要があります。

私は約25個のボックスを持っていますが、前述のサブルーチンを呼び出す各テキストボックスにChange()イベントを個別に追加したくありません。値が変更されるたびに AutoCalc() を呼び出す最も迅速で効率的な方法は何ですか?

4

7 に答える 7

16

これは、クラス モジュールを使用して実現できます。次の例では、いくつかのテキスト ボックスを含むユーザー フォームが既にあると仮定します。

まず、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
于 2011-05-09T20:35:59.417 に答える
8

上記の回答が示唆するように、クラスの使用は、多くのコントロールを簡潔かつエレガントな方法で処理するための優れた戦略ですが、次のようになります。

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
于 2012-11-15T15:04:48.993 に答える
6

テキストボックスの変更に応答するクラスを作成する方法については、これをご覧ください。例はボタン用ですが、変更できます。ただし、Textbox コントロールには Exit イベントがないことに注意してください (このイベントは実際にはユーザー フォームの一部です)。そのため、実際には Change イベントを使用する必要があります。

于 2011-05-09T20:16:43.377 に答える
0

ただし、Textbox コントロールには Exit イベントがないことに注意してください (このイベントは実際にはユーザー フォームの一部です)。そのため、実際には Change イベントを使用する必要があります。

よくわかりません。たぶんこれは2007年に追加されたものか、ニュアンスがわからないのかもしれません。TextBox コントロールで Exit イベントを使用します。コントロールから Tab キーを押すか、別のコントロールでマウスをクリックすると、Exit イベントがトリガーされます。

于 2013-12-06T17:08:46.687 に答える