我在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页