イベントハンドラー内でのEnterイベントとExitイベントのトリガー

Aug 23 2020

みなさん、あられ!

一部TextBoxLabelコントロールを動的に追加および削除する必要があるフォームがあります。

以下の場合は、いくつかの検証:これらのコントロールのそれぞれは、3つのイベントがあります追加するKeyPressと、上のいくつかの他のものEnterとはExit。問題はイベントでEnterありExit、イベントハンドラークラスモジュール内では機能しないようです。

同じプロジェクトに他のイベントハンドラモジュールがあり、それらはうまく機能します(ただし、イベントEnterもありませんExit)。

イベントハンドラクラスモジュールのコードは次のとおりです。それが正常に動作していますので、私はそれがちょうど約何か、フォームモジュール内のコードを投稿しないだろうEnterし、Exitイベントハンドラ内のイベント。

動的に追加されたアクションEnterExitイベントをトリガーする方法を知っていますTextBoxか?

編集:私の目的は、TextBoxフォーカスが合ったときとフォーカスがなくなったときに、クールなトランジションアニメーションを作成することです。このアニメーションは、既存のコントロールですでに発生しています。これは、EnterイベントとExitイベントでトリガーされる関数です(GotFocusとLostFocusがあれば便利ですが、使用することもできません)。

Option Explicit

Private WithEvents moTextDate As MSForms.TextBox

Public Property Set DateTextBox(ByVal oTxtBox As MSForms.TextBox)
    Set moTextDate = oTxtBox
End Property

Private Sub moTextDate_Enter()
    ' Things to do on receiving focus
End Sub

Private Sub moTextDate_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    If ValidateNumbers(KeyAscii, "/", ":", " ") = False Then KeyAscii = 0
End Sub

Private Sub moTextDate_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    ' Things to do when lost focus
End Sub

回答

2 chrisneilsen Aug 24 2020 at 06:03

残念ながら、Event Handler Classメソッドによって公開されるイベントのリストには、EnterまたはExitイベントが含まれていません。IDEで利用可能なイベントを確認できます

あなたのプロジェクトについてもっと知らなければ、他の方法を勧めるのは難しいです。

CésarRodriguez Aug 24 2020 at 12:12

わかりました、多分それはちょっと厄介です、しかし私はこの問題に関する私のターンアラウンドを文書化するために私の質問に答えています。

他の仲間の回答は、イベントハンドラークラスモジュールの機能EnterExitイベントに対する私の期待を却下したので、これが私がしたことであり、うまくいくようです。

基本的な考え方は次のとおりです。コントロール間で快適な遷移アニメーションを作成する関数をトリガーしようとしているので、それらを使用するだけでよいと想定できます。(a)ユーザーが手動でコントロールから別のコントロールに移動する場合(コードはすべてを自動的に埋めます。アニメーションは使用せず、特定のコードを介して終了マークアップを配置するだけです。及び(b)は、これらの入力コントロールが選択されている場合(すなわち、有しますTabStop = True)。

ユーザーは、コントロールをクリックしてTabまたはを押すことにより、コントロールから別のコントロールに手動で移動しますShift + Tab。これらのイベントは、イベントハンドラークラスモジュールで、(私KeyUpよりもうまく機能KeyDownしました)、MouseDown(試す必要はありませんでしたMouseUp)、およびClick(コマンドボタンコントロールで)を介して追跡できます。

私のフォームには、TabStopを備えた12個の静的コントロール(5個のテキストボックス、5個のコンボボックス、2個のコマンドボタン)があり、さらに5個の動的に作成される可能性があります(3個のテキストボックスと2個のコンボボックス)。

したがって、疑似Enterイベントと疑似Exitイベントを追跡するために、3つのイベントハンドラークラスモジュール(コマンドボタン、コンボボックス、テキストボックス用)を作成しました。実際、これらのイベントハンドラーは、ユーザーがコントロールをクリックするか、TabキーまたはShift + Tabキーを押すとリッスンします(結局のところ、これらは別のコントロールに手動で移動する方法です)。ユーザーが別のコントロールに移動したのか、それとも既にいるコントロールをクリックしただけなのかを知るために、トークンとして機能するoActiveControlandという2つのグローバルオブジェクト変数を定義しましたoPreviousControl。クリック/タブインされたコントロールがと異なる場合oActiveControl、これはユーザーがコントロールを変更したことを意味するため、トークンを更新する必要があります。

これは本当にうまくいきました(これらのわずか4時間の間、ハードテストされていませんでした)。コードは次のとおりです。

''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''' ANY MODULE ''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''

Public oActiveControl As MSForms.Control, oPreviousControl As MSForms.Control



''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''' USER FORM MODULE '''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''

Private Sub UserForm_Initialize()
' On loading the UserForm, we are going to create the event handlers for the static controls.
    Dim oControl As MSForms.Control
    Dim oEvHandlerExitText As EvHndlExitTxt
    Dim oEvHandlerExitCombo As EvHndlExitCbx
    Dim oEvHandlerExitButton As EvHndlExitBtn
    Dim colEventHandlers as Collection

    Set colEventHandlers = New Collection
    
    ' Loop to create the event handlers and store them in a collection
    For Each oControl In Me.Controls
        Select Case TypeName(oControl)
        Case "TextBox"
            If oControl.TabStop = True Then
                Set oEvHandlerExitText = New EvHndlExitTxt
                Set oEvHandlerExitText.TextBox = oControl
                colEventHandlers.Add oEvHandlerExitText
            End If
            
        Case "ComboBox"
            If oControl.TabStop = True Then
                Set oEvHandlerExitCombo = New EvHndlExitCbx
                Set oEvHandlerExitCombo.ComboBox = oControl
                colEventHandlers.Add oEvHandlerExitCombo
            End If
            
        Case "CommandButton"
            If oControl.TabStop = True Then
                Set oEvHandlerExitButton = New EvHndlExitBtn
                Set oEvHandlerExitButton.Button = oControl
                colEventHandlers.Add oEvHandlerExitButton
            End If
            
        End Select
    Next oControl
End Sub


Private Sub UserForm_AddControl(ByVal Control As MSForms.Control)
' Whenever we add a control to the UserForm, if it is a Combobox, Textbox
' or Button, we are also creating their event handlers.

    Select Case TypeName(Control)
    Case "TextBox"
        If Control.TabStop = True Then
            Dim oEvHandlerExitText As EvHndlExitTxt
            Set oEvHandlerExitText = New EvHndlExitTxt
            Set oEvHandlerExitText.TextBox = Control
            colEventHandlers.Add oEvHandlerExitText
        End If
        
    Case "ComboBox"
        If Control.TabStop = True Then
            Dim oEvHandlerExitCombo As EvHndlExitCbx
            Set oEvHandlerExitCombo = New EvHndlExitCbx
            Set oEvHandlerExitCombo.ComboBox = Control
            colEventHandlers.Add oEvHandlerExitCombo
        End If
        
    Case "CommandButton"
        If Control.TabStop = True Then
            Dim oEvHandlerExitButton As EvHndlExitBtn
            Set oEvHandlerExitButton = New EvHndlExitBtn
            Set oEvHandlerExitButton.Button = Control
            colEventHandlers.Add oEvHandlerExitButton
        End If
        
    End Select
End Sub

Private Sub UserForm_Terminate()
' On unloading the form, we need to dump the global token variables
    Set oActiveControl = Nothing
    Set oPreviousControl = Nothing
End Sub



''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''' CLASS MODULE EvHndlExitBtn ''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''

Option Explicit

Private WithEvents moBtn As MSForms.CommandButton

Public Property Set Button(ByVal oBtn As MSForms.CommandButton)
    Set moBtn = oBtn
End Property

' The command buttons have no transitions, so there are no functions in pseudo-Enter nor
' pseudo-Exit events. This class module is here only to detect clicks or tabs which leaves
' other controls.

Private Sub moBtn_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = 9 Or KeyCode = 16 Then ' 9 = Tab, 16 = Shift + Tab
        If oActiveControl Is Nothing Then Set oPreviousControl = oActiveControl
        Set oActiveControl = moBtn
    End If
End Sub

Private Sub moBtn_Click()
    If oActiveControl Is Nothing Then Set oPreviousControl = oActiveControl
    Set oActiveControl = moBtn
End Sub



''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''' CLASS MODULE EvHndlExitTxt ''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''

Option Explicit

Private WithEvents moTxtBox As MSForms.TextBox

Public Property Set TextBox(ByVal oTxtBox As MSForms.TextBox)
    Set moTxtBox = oTxtBox
End Property

Private Sub moTxtBox_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = 9 Or KeyCode = 16 Then ' 9 = Tab, 16 = Shift + Tab
        If Not oActiveControl Is Nothing Then Set oPreviousControl = oActiveControl
        Set oActiveControl = moTxtBox

        If Not oActiveControl Is oPreviousControl Then ' If user changed controls...
        ' Here is the pseudo-Enter event from the TextBox reached via Tab/Shift+Tab:
            ' Instructions... (these instructions will have to be repeated below, so
            ' Instructions...  consider creating a function if there are many of them.)
                
            If Not oPreviousControl Is Nothing Then
            ' Here is the pseudo-Exit event from the previous control:
                ' Instructions... (Use oPreviousControl to refer the control which lost focus.
                ' Instructions...  Will have to be repeated below also)
            End If
        End If
    End If
End Sub

Private Sub moTxtBox_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    If Not oActiveControl Is Nothing Then Set oPreviousControl = oActiveControl
    Set oActiveControl = moTxtBox

    If Not oActiveControl Is oPreviousControl Then ' If user changed controls...
    ' Here is the pseudo-Enter event from the TextBox reached via mouse clicking:
        ' Instructions... (these instructions where repeated above, so consider
        ' Instructions...  creating a function if there are many of them.)
            
        If Not oPreviousControl Is Nothing Then
        ' Here is the pseudo-Exit event from the previous control:
            ' Instructions... (Use oPreviousControl to refer the control which lost focus.
            ' Instructions...  Was repeated above also)
        End If
    End If
End Sub



''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''' CLASS MODULE EvHndlExitCbx ''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''

Option Explicit

Private WithEvents moCmbBox As MSForms.ComboBox

Public Property Set ComboBox(ByVal oCmbBox As MSForms.ComboBox)
    Set moCmbBox = oCmbBox
End Property

Private Sub moCmbBox_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = 9 Or KeyCode = 16 Then
        If Not oActiveControl Is Nothing Then Set oPreviousControl = oActiveControl
        Set oActiveControl = moCmbBox
        
        If Not oActiveControl Is oPreviousControl Then ' If user changed controls...
        ' Here is the pseudo-Enter event from the ComboBox reached via Tab/Shift+Tab:
            ' Instructions... (these instructions will have to be repeated 4 times, so
            ' Instructions...  consider creating a function if there are many of them.)
            
            If Not oPreviousControl Is Nothing Then
            ' Here is the pseudo-Exit event from the previous control:
                ' Instructions... (Use oPreviousControl to refer the control which lost focus.
                ' Instructions...  Will have to be repeated below also)
            End If
        End If
    End If
End Sub

Private Sub moCmbBox_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    If Not oActiveControl Is Nothing Then oPreviousControl = oActiveControl
    Set oActiveControl = moCmbBox
    
    If Not oActiveControl Is oPreviousControl Then ' If user changed controls...
    ' Here is the pseudo-Enter event from the ComboBox reached via mouse clicking:
        ' Instructions... (these instructions where repeated above, so consider
        ' Instructions...  creating a function if there are many of them.)
            
        If Not oPreviousControl Is Nothing Then
        ' Here is the pseudo-Exit event from the previous control:
            ' Instructions... (Use oPreviousControl to refer the control which lost focus.
            ' Instructions...  Was repeated above also)
        End If
    End If
End Sub

コード行を節約するために、この質問に対するGary McGillの壮大な応答を採用しました:VBA:UserFormsでのWithEventsの使用

ありがとう、クリス・ニールセンとヴァリアタス!あなたの説明は私をとても助けてくれました!誰かがこの問題に対するより良い答えを持っているなら、ここに投稿してください。編集:オブジェクトの比較で私が見ることができなかった問題に気づいてくれてありがとう、クリス!