Userform closes after “End Sub” without ever calling “Unload Me”

前端 未结 1 674
攒了一身酷
攒了一身酷 2021-01-06 18:52

I have a userform (baseUF) that has multiple pages and buttons that all do different things. I have this baseUF being modeless because I want the user to be able to play wit

相关标签:
1条回答
  • 2021-01-06 19:09

    Whenever something unexpected happens with forms, consider writing End in the immediate window and pressing enter. It will kill all the unkilled instances of a form and generally any variable, thus it would be like a cold restart to the VBA program.

    After doing this, it is a good idea to consider a cleaner solution, concerning VBA & UserForms, using some OOP. (Disclaimer - the first article is mine):

    • http://www.vitoshacademy.com/vba-the-perfect-userform-in-vba/
    • https://rubberduckvba.wordpress.com/2017/10/25/userform1-show/
    • https://codereview.stackexchange.com/questions/154401/handling-dialog-closure-in-a-vba-user-form

    Although it may seem that you are achieving the same results with more code, the benefits of using this approach are quite a lot in the long term.


    This is a small example of the OOP model. Imagine you have a user form like this:

    It has only the following controls:

    • btnRun
    • btnExit
    • lblInfo
    • frmMain (the class)

    The code withing the form is the following:

    Option Explicit
    
    Public Event OnRunReport()
    Public Event OnExit()
    
    Public Property Get InformationText() As String    
        InformationText = lblInfo.Caption    
    End Property
    
    Public Property Let InformationText(ByVal value As String)    
        lblInfo.Caption = value    
    End Property
    
    Public Property Get InformationCaption() As String    
        InformationCaption = Caption    
    End Property
    
    Public Property Let InformationCaption(ByVal value As String)    
        Caption = value    
    End Property
    
    Private Sub btnRun_Click()    
        RaiseEvent OnRunReport    
    End Sub
    
    Private Sub btnExit_Click()    
        RaiseEvent OnExit    
    End Sub
    
    Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)    
        If CloseMode = vbFormControlMenu Then
            Cancel = True
            Hide
        End If    
    End Sub
    

    The form is with two events, getting caught by the clsSummaryPresenter. The clsSummaryPresenter looks like this:

    Option Explicit
    
    Private WithEvents objSummaryForm As frmMain
    
    Private Sub Class_Initialize()        
        Set objSummaryForm = New frmMain    
    End Sub
    
    Private Sub Class_Terminate()        
        Set objSummaryForm = Nothing        
    End Sub
    
    Public Sub Show()    
        If Not objSummaryForm.Visible Then
            objSummaryForm.Show vbModeless
            Call ChangeLabelAndCaption("Press Run to Start", "Starting")
        End If    
        With objSummaryForm
            .Top = CLng((Application.Height / 2 + Application.Top) - .Height / 2)
            .Left = CLng((Application.Width / 2 + Application.Left) - .Width / 2)
        End With    
    End Sub
    
    Private Sub Hide()    
        If objSummaryForm.Visible Then objSummaryForm.Hide    
    End Sub
    
    Public Sub ChangeLabelAndCaption(strLabelInfo As String, strCaption As String)    
        objSummaryForm.InformationText = strLabelInfo
        objSummaryForm.InformationCaption = strCaption
        objSummaryForm.Repaint    
    End Sub
    
    Private Sub objSummaryForm_OnRunReport()    
        MainGenerateReport
        Refresh    
    End Sub
    
    Private Sub objSummaryForm_OnExit()    
        Hide    
    End Sub    
    
    Public Sub Refresh()        
        With objSummaryForm
            .lblInfo = "Ready"
            .Caption = "Task performed"
        End With    
    End Sub
    

    Finally, we have the modMain, which is the so-called business logic of the form:

    Option Explicit
    
    Private objPresenter   As clsSummaryPresenter
    
    Public Sub MainGenerateReport()    
        objPresenter.ChangeLabelAndCaption "Starting and running...", "Running..."
        GenerateNumbers    
    End Sub
    
    Public Sub GenerateNumbers()    
        Dim lngLong         As Long
        Dim lngLong2        As Long    
        tblMain.Cells.Clear    
        For lngLong = 1 To 10
            For lngLong2 = 1 To 10
                tblMain.Cells(lngLong, lngLong2) = lngLong * lngLong2
            Next lngLong2
        Next lngLong    
    End Sub
    
    Public Sub ShowMainForm()    
        If (objPresenter Is Nothing) Then
            Set objPresenter = New clsSummaryPresenter
        End If    
        objPresenter.Show    
    End Sub
    
    0 讨论(0)
提交回复
热议问题