我在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
在Module1中:
Public BoardState(0 To 5, 0 To 5) As Integer
Public LockType As Integer
答案 0 :(得分:2)
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 Lomax 1 找到了这句话:
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()
处理程序,则 it still 触发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页