Attivazione di eventi di ingresso ed uscita all'interno di un gestore di eventi

Aug 23 2020

Salve a tutti!

Ho un modulo in cui devo aggiungere e rimuovere alcuni TextBoxe Labelcontrolli dinamicamente.

Ognuno di questi controlli da aggiungere avrà anche 3 eventi: alcune convalide in caso di a KeyPresse altre cose su Entere Exit. Il problema sono gli eventi Entere Exitsembra non funzionare all'interno del modulo di classe del gestore di eventi.

Lo stesso progetto ha altri moduli di gestione degli eventi e funzionano bene (ma non hanno eventi EnterExit).

Il codice nel modulo di classe del gestore eventi è il seguente. Non inserirò il codice nel modulo del modulo perché funziona bene, è solo qualcosa su Entered Exiteventi all'interno dei gestori di eventi.

Conosci un modo per attivare azioni Entered Exiteventi di un aggiunto dinamicamente TextBox?

EDIT: Il mio obiettivo è produrre alcune fantastiche animazioni di transizione quando TextBoxsi concentra e quando perde la concentrazione. Questa animazione si verifica già con i controlli preesistenti; è una funzione che si attiva sugli eventi Enter e Exit (GotFocus e LostFocus sarebbero carini, ma non sono disponibili).

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

Risposte

2 chrisneilsen Aug 24 2020 at 06:03

Purtroppo l'elenco degli eventi esposti dal metodo Event Handler Class non include Entero Exiteventi. Puoi vedere quali eventi sono disponibili nell'IDE

Senza saperne di più sul tuo progetto, è difficile consigliare alternative.

CésarRodriguez Aug 24 2020 at 12:12

Ok, forse è un po 'spinoso, ma rispondo alla mia domanda per documentare la mia inversione di tendenza su questo problema.

Le risposte degli altri colleghi hanno ignorato le mie aspettative di funzionalità Entered Exiteventi nei moduli di classe del gestore di eventi, quindi ecco cosa ho fatto e sembra funzionare.

Il pensiero di base è il seguente: sto cercando di attivare funzioni che rendono piacevoli animazioni di transizione tra i controlli, quindi posso presumere che avrò solo bisogno di usarle: (a) Quando l'utente passa manualmente da un controllo a un altro (se il il codice riempie tutto automaticamente, non userò l'animazione, metto solo il markup finale tramite codice specifico); e (b) quando questi controlli di input sono selezionabili ( vale a dire , have TabStop = True).

L'utente passa manualmente da un controllo all'altro facendo clic su di essi e premendo Tabo Shift + Tab. Sono in grado di tenere traccia di questi eventi nei moduli di classe del gestore eventi, tramite KeyUp(ha funzionato meglio di KeyDownme), MouseDown(non è stato necessario provare MouseUp) e Click(nei controlli del pulsante di comando).

Il mio modulo ha 12 controlli statici con TabStop (5 caselle di testo, 5 caselle combinate e 2 pulsanti di comando), e potrebbe essere creato più 5 dinamicamente (3 caselle di testo e 2 caselle combinate).

Così ho creato 3 moduli di classe per i gestori di eventi (per pulsanti di comando, caselle combinate e caselle di testo) per tenere traccia degli eventi pseudo-Invio e pseudo-Uscita. In effetti, questi gestori di eventi ascoltano quando l'utente fa clic su un controllo o preme TAB o MAIUSC + TAB (dopotutto, questi sono i modi per passare manualmente a un altro controllo). Per sapere se l'utente è andato a un altro controllo o se ha fatto clic sullo stesso in cui si trovava già, ho definito 2 variabili oggetto globali chiamate oActiveControle oPreviousControl, che funge da token. Se il controllo su cui si è fatto clic / scheda è diverso da oActiveControl, significa che l'utente ha modificato i controlli, quindi devo aggiornare i miei token.

Ha funzionato molto bene (per queste misere 4 ore; non è stato testato duramente). Ecco il codice:

''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''' 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

Per salvare righe di codice, ho adattato la maestosa risposta di Gary McGill a questa domanda: VBA: Using WithEvents on UserForms

Grazie, Chris Nielsen e Variatus! Le tue spiegazioni mi hanno aiutato molto! Se qualcuno ha una risposta più chiara a questo problema, pubblicala qui. EDIT: Grazie ancora, Chris, per aver notato il problema che non riuscivo a vedere confrontando gli oggetti!