Saltar al contenido

VBA: destruye correctamente una instancia de UserForm no modal

Solución:

De hecho, me he centrado bastante en las formas modales, porque eso es lo que se usa con más frecuencia. ¡Gracias por los comentarios sobre ese artículo!

Sin embargo, los principios son los mismos para las formas no modales: simplemente amplíe el Modelo-Vista-Presentador patrón descrito aproximadamente en el artículo vinculado y aquí.

La diferencia es que una forma no modal necesita un cambio de paradigma: ya no estás respondiendo a una secuencia preestablecida de eventos, sino que necesitas responder a algunos eventos asincrónicos. eventos eso puede suceder en cualquier momento, o no.

  • Cuando se maneja un formulario modal, hay un “antes de mostrar” y luego un “después de ocultar” que se ejecuta inmediatamente después de que se oculta el formulario. Puede manejar cualquier cosa que suceda “mientras se muestra” mediante eventos.
  • Cuando se maneja un formulario no modal, hay un “antes de mostrar”, y luego “mientras se muestra” y “después de mostrar” ambos deben manejarse a través de eventos.

Haga que su módulo de clase de presentador sea responsable de llevar a cabo la UserForm ejemplo, a nivel de módulo y WithEvents:

Option Explicit
Private WithEvents myModelessForm As UserForm1

El presentador Show el método será Set la instancia del formulario y mostrarla:

Public Sub Show()
    'If Not myModelessForm Is Nothing Then
    '    myModelessForm.Visible = True 'just to ensure visibility & honor the .Show call
    '    Exit Sub
    'End If
    Set myModelessForm = New UserForm1
    '...
    myModelessForm.Show vbModeless
End Sub

usted no desea que la instancia del formulario sea local para el procedimiento aquí, por lo que una variable local o a With el bloque no puede funcionar: el objeto estará fuera de alcance antes de que usted lo desee. Es por eso que almacena la instancia en un campo privado, a nivel de módulo: ahora el formulario vive tanto como la instancia del presentador.

Ahora, debe hacer que el formulario “hable” con el presentador; la forma más fácil es exponer los eventos en el UserForm1 código subyacente: por ejemplo, si queremos que el usuario confirme la cancelación, agregaremos un ByRef parámetro al evento, por lo que el controlador en el presentador puede pasar la información a la fuente del evento (es decir, al código del formulario):

Option Explicit
'...private fields, model, etc...
Public Event FormConfirmed()
Public Event FormCancelled(ByRef Cancel as Boolean)

'returns True if cancellation was cancelled by handler
Private Function OnCancel() As Boolean
    Dim cancelCancellation As Boolean
    RaiseEvent FormCancelled(cancelCancellation)
    If Not cancelCancellation Then Me.Hide
    OnCancel = cancelCancellation
End Function

Private Sub CancelButton_Click()
    OnCancel
End Sub

Private Sub OkButton_Click()
    Me.Hide
    RaiseEvent FormConfirmed
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        Cancel = Not OnCancel
    End If
End Sub

Ahora el presentador puede manejar eso FormCancelled evento:

Private Sub myModelessForm_FormCancelled(ByRef Cancel As Boolean)
    'setting Cancel to True will leave the form open
    Cancel = MsgBox("Cancel this operation?", vbYesNo + vbExclamation) = vbNo
    If Not Cancel Then
        ' modeless form was cancelled and is now hidden.
        ' ...
        Set myModelessForm = Nothing
    End If
End Sub

Private Sub myModelessForm_FormConfirmed()
    'form was okayed and is now hidden.
    '...
    Set myModelessForm = Nothing
End Sub

Una forma no modal no típicamente Sin embargo, tiene botones “Aceptar” y “Cancelar”. Más bien, tendría una serie de funcionalidades expuestas, por ejemplo, una que abre algún diálogo modal UserForm2 que hace otra cosa; de nuevo, simplemente expones un evento y lo manejas en el presentador:

Public Event ShowGizmo()

Private Sub ShowGizmoButton_Click()
    RaiseEvent ShowGizmo
End Sub

Y el presentador dice:

Private Sub myModelessForm_ShowGizmo()
    With New GizmoPresenter
        .Show
    End With
End Sub

Tenga en cuenta que el modal UserForm2 es una preocupación de una clase de presentadores separada.

Por lo general, relaciono la vida útil de una instancia de formulario de usuario sin modo con la del libro de trabajo colocando código a lo largo de esas líneas detrás de ThisWorkbook:

Option Explicit

Private m_MyForm As UserForm1

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If Not m_MyForm Is Nothing Then
        Unload m_MyForm
        Set m_MyForm = Nothing
    End If
End Sub

Friend Property Get MyForm() As UserForm1
    If m_MyForm Is Nothing Then
        Set m_MyForm = New UserForm1
    End If

    Set MyForm = m_MyForm
End Property

A continuación, puede consultar el código no modal a lo largo de su código utilizando, por ejemplo,

ThisWorkbook.MyForm.Show vbModeless

etc.

Para formularios no modales, use DoEvents junto con la propiedad de formulario de usuario personalizada.


Sub test()

    Dim frm As New UserForm1

    frm.Show vbModeless

    Do
        DoEvents
        If frm.Cancelled Then
            Unload frm
        Exit Do
    End If
    Loop Until False

    MsgBox "You closed the modeless form."

    '/ Using With
    With New UserForm1
        .Show vbModeless
        Do
            DoEvents
            If .Cancelled Then Exit Do
        Loop Until False
    End With

    MsgBox "You closed the modeless form (with)"

End Sub

‘/ Formulario de usuario

Private m_bCancelled As Boolean

Public Property Get Cancelled() As Boolean
    Cancelled = m_bCancelled
End Property

Public Property Let Cancelled(ByVal bNewValue As Boolean)
    m_bCancelled = bNewValue
End Property
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    Me.Cancelled = True
    Cancel = 1
    Me.Hide
End Sub
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *