vba - 如果从右上角关闭 Excel-VBA 表单的实例,则打开时会出现错误 红色 `X`

标签 vba winforms excel

史前

我已经阅读了创建表单的最佳实践,其中涉及这样一个事实:人们应该始终引用表单的对象而不是表单本身。因此,我决定为自己构建一个样板表单。

问题

一切都很顺利,直到我决定用右上角的红色X关闭表单。关闭就OK了但是,当我尝试再次打开表单时,我收到此运行时错误:

enter image description here

错误出现在 objPresenter.Show 上(请参阅下面的代码)。显然,它没有进入上面的if中。但问题是 X 的关闭不能正常工作。当我通过 End 按钮关闭表单时,一切正常。甚至,如果我将关闭代码从 btnEnd 复制到 UserForm_QueryClose ,它仍然无法正常工作。

表格

因此,我有一个 modMainfrmMainclsSummaryPresenter,它们都负责处理表单。我从 modMain

开始代码

我的表单如下所示:

enter image description here

它有btnRunbtnExitlblInfo。类的名称是frmMain

代码

frmMain中:

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(CloseMode As Integer, Cancel As Integer)

    If CloseMode = vbFormControlMenu Then
        Cancel = True
        Hide
        'Even if I change the two lines above with this the error happens:
        'RaiseEvent OnExit
        'However, if I simply write END in stead of those two lines
        'anything works quite ok...
        'but that is a bit brutal.

    End If

End Sub

clsSummaryPresenter

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

Public 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

modMain

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 4
        For lngLong2 = 1 To 1
            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

问题

再说一遍,为什么我无法用红色X关闭表单?我可以用 End 替换 UserForm_QueryClose 中的代码,但这有点残酷。有什么想法吗?

最佳答案

将表单模式从 vbModeless 更改为 vbModal 可以让您更早地获得更丰富的失败信息:

run-time error: "automation error; connection to type library or object library for remote process has been lost."

问题似乎是因为 QueryClose 处理程序中的 Cancel = True 赋值由于某种原因不起作用。

QueryClose 处理程序的签名如下:

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

你的是:

Private Sub UserForm_QueryClose(CloseMode As Integer, Cancel As Integer)

您不应该自己手动键入这些处理程序签名 - 相反,请使用代码 Pane 右上角的下拉菜单,并让 VBE 为您生成处理程序 stub :

QueryClose event in the dropdown

这样,您的处理程序签名将始终与其所属的接口(interface)相匹配。

VBA 并不真正关心处理程序中的参数名称:运行时匹配处理程序签名的方式是根据预期的参数索引及其类型进行匹配。由于两个 QueryClose 参数都是 Integer 值,因此反转它们可以很好地编译 - 除非您设置 Cancel = True,运行时看到的是您已分配 CloseMode = -1 并保留 Cancel 参数

这意味着您的表单不会取消其关闭,因此该对象每次都会被销毁。

反转 QueryClose 处理程序中的参数,一切都工作得很好并且完全符合预期。

关于vba - 如果从右上角关闭 Excel-VBA 表单的实例,则打开时会出现错误 红色 `X`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42255695/

相关文章:

javascript - HTML/VBA Click 事件未触发

c# - 在 AfterLabelEdit 期间无法更改 treeView 中的 selectedNode

c# - WinForms 应用程序中的初始化代码 - Program.cs 或 MainForm?

vba - Excel VBA : Consolidate the iterating group in "For Each" block

ms-access - 捕捉粘贴事件?

winforms - WM_NCHITTEST、HTCAPTION 和最大化窗口

vb.net - 使用 vb 查找特定文件夹下 Excel 中的行数的脚本

excel - 如何获得英文字母表中的第n个字母

excel - 如何从Excel中的求解器中删除所有约束?

ms-access - 如何使用 VBA 刷新导航 Pane