我在UserForm1中有一个for循环,该循环打开UserForm2的次数不定,以从用户那里获取适当数量的数据。参见下面在UserForm1中运行的代码

Private Sub Start_Click()
    Constants
    InitBoard
    While Not ValidTest
        IncParts
    Wend
End Sub

Public Sub InitBoard()
    Dim row As Integer
    Dim col As Integer
    For Mirror = 1 To NumBlocks(2, 1)
        LockType = 1
        UserForm2.Show
    Next Mirror
    For Prism = 1 To NumBlocks(2, 2)
        LockType = 2
        UserForm2.Show
    Next Prism
    For Wormhole = 1 To NumBlocks(2, 3)
        LockType = 3
        UserForm2.Show
    Next Wormhole
    For Blocker = 1 To NumBlocks(2, 4)
        LockType = 4
        UserForm2.Show
    Next Blocker
    For Splitter = 1 To NumBlocks(2, 5)
        LockType = 5
        UserForm2.Show
    Next Splitter
End Sub


现在,如果我运行代码,则可以在UserForm2中适当地获取数据。当我用红色的“ X”按钮手动关闭UserForm2时,一切正常。再次弹出UserForm2,并显示从上次循环运行中接受的数据。在每个循环运行了适当的次数之后,UserForm2停止打开,并且代码在UserForm1中继续到Start_Click()子项的While循环。但是,如果我在UserForm2内的子项末尾使用“卸载我”以在收到正确的输入后自动将其关闭,则会收到“运行时错误'91':对象变量或未设置块变量”。当我按Debug时,以上代码中的InitBoard()的第5行被突出显示(UserForm2.Show)。下面是我在UserForm2中使用的复选框单击功能。注释掉第3行可解决此问题,但我必须手动关闭表单。

Private Sub Bstate00_Click()
    BoardState(0, 0) = LockType + 5
    Unload Me
End Sub


在显示之前,我尝试过尝试可以想到的所有组合来加载UserForm2,确保在每次关闭UserForm2之前都不要结束循环,甚至添加无济于事的延迟。 Me.Hide确实解决了该问题,但没有运行更新在上一个循环中输入的信息所需的UserForm2_Initialize()子项。

请根据注释中有关402错误的对话在下面看到重新创建错误的最小代码:

在UserForm1中:

Private Sub Start_Click()
    For Mirror = 1 To 3
        LockType = 1
        With New UserForm2
            .Show
        End With
    Next Mirror
End Sub


在UserForm2中:

Private Sub Bstate00_Click()
    BoardState(0, 0) = LockType + 5
    Me.Hide
End Sub

Private Sub UserForm_Initialize()
    If BoardState(0, 0) = -1 Then
        Me.Controls("BState" & 0 & 0).Value = False
        Me.Controls("BState" & 0 & 0).Enabled = False
    ElseIf BoardState(0, 0) = 0 Then
        Me.Controls("BState" & 0 & 0).Value = False
        Me.Controls("BState" & 0 & 0).Enabled = True
    Else
        Me.Controls("BState" & 0 & 0).Value = True
        Me.Controls("BState" & 0 & 0).Enabled = False
    End If
End Sub


在第1单元中:

Public BoardState(0 To 5, 0 To 5) As Integer
Public LockType As Integer

最佳答案

tldr;按钮很重要。一切都不像在UserForm领域那样。



FWIW,我无法在Excel 2013 x64中重现402运行时错误,但确实发现了一些有趣的行为。给出以下代码:

'UserForm1.cls
Private Sub UserForm_Initialize()
    Debug.Print "UserForm1_Initialize"
End Sub

Private Sub UserForm_Click()
    Dim i As Long
    For i = 1 To 3
        With New UserForm2
            .Show vbModal
        End With
    Next
    Debug.Print "Done"
End Sub




'UserForm2.cls
Private Sub UserForm_Initialize()
    Debug.Print "UserForm2_Initialize"
End Sub

Private Sub UserForm_Click()
    Me.Hide
End Sub

Private Sub UserForm_Terminate()
    Debug.Print "UserForm2_Terminate"
End Sub




单击以关闭时,执行以上操作(将UserForm1显示为模式)将产生以下输出:

UserForm1_Initialize
UserForm2_Initialize
UserForm2_Initialize
UserForm2_Initialize
Done


请注意,当With块退出时,不会终止事件终止。在点击处理程序中调用Unload Me的行为正常。这是完全出乎意料的,因此我仔细阅读了UserForm类的文档,并从Paul Lomax1找到了这句话:


Microsoft建议仅应在Click中卸载表格
CommandButton或菜单控件的事件。调用卸载语句
在其他情况下,处理程序可能会产生不良的副作用并导致
一般保护故障(GPF)。


这使我好奇如果将Me.Hide语句移到CommandButton处理程序中会发生什么:

Private Sub UserForm_Initialize()
    Debug.Print "UserForm2_Initialize"
End Sub

Private Sub CommandButton1_Click()
    Me.Hide
End Sub

Private Sub UserForm_Terminate()
    Debug.Print "UserForm2_Terminate"
End Sub




执行此代码给出以下输出...

UserForm1_Initialize
UserForm2_Initialize
UserForm2_Terminate
UserForm2_Initialize
UserForm2_Terminate
UserForm2_Initialize
UserForm2_Terminate
Done


完全符合预期似乎在VBA处理UserForm方面存在一些未记录的怪异之处。但它变得更加离奇。如果我将CommandButton留在表单上并恢复为原始代码(从表单单击处理程序中隐藏表单,而根本没有在代码中使用UserForm_Click()处理程序,则它仍会引发Terminate事件。表单上CommandButton的名称会改变卸载行为,也就是说,您可以尝试将隐藏的CommandButton放在表单上,​​看看是否能解决该问题,否则,您始终可以从调用中显式Unload表单现场:

Private Sub UserForm_Click()
    Dim i As Long
    Dim subForm As UserForm2
    For i = 1 To 3
        Set subForm = New UserForm2
        subForm.Show vbModal
        Unload subForm
    Next
    Debug.Print "Done"
End Sub


1 Lomax,保罗。 VB和VBA简而言之:语言。加利福尼亚塞巴斯托波尔:OReilly,1999年,第567页

07-24 19:25