Vba Userform会根据条件使Excel崩溃
我正面临一个有趣的问题,我不明白 在VBA中,我希望在用户双击单元格时加载Userform,具体取决于单元格内容。但是,根据我询问的条件,一旦我退出Sub,Excel就会崩溃(即使在UserForm关闭之后,它也会继续执行代码) 这项工作:Vba Userform会根据条件使Excel崩溃,vba,excel,userform,Vba,Excel,Userform,我正面临一个有趣的问题,我不明白 在VBA中,我希望在用户双击单元格时加载Userform,具体取决于单元格内容。但是,根据我询问的条件,一旦我退出Sub,Excel就会崩溃(即使在UserForm关闭之后,它也会继续执行代码) 这项工作: Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean) Dim myForm As New U
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
Dim myForm As New UserForm1
If Target.Cells(1).Value = "" Then
myForm.Show
End If
Debug.Print ("OK")
End Sub
这三个因素使Excel崩溃:
一,
三,
我正在使用一个空的UserForm进行测试尝试更改If块中的代码,以便它执行一个
Cancel=True
来忽略双击操作并预先加载表单,如下所示:
If Target.Cells(1).Value = "Test" Then
Cancel = True
Load myForm
myForm.Show
End If
这似乎是一个很好的方法来限制可能出错的事情的数量
不过还有更多
Dim myForm As New UserForm1
这是在本地范围内创建一个自动实例化的UserForm1
对象。由于Dim
语句不可执行,这意味着无论是否显示表单,只要输入过程范围,就会创建对象
使用With
块,可以轻松避免无条件创建该对象,甚至可以避免为其声明变量:
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
If Target.Cells(1).Value = "Test" Then
Cancel = True
With New UserForm1
.Show
End With
End If
Debug.Print "OK"
End Sub
这样,表单实例只有在需要时才会被创建。避免了默认实例陷阱,这是一个巨大的荣誉——你可以阅读更多关于这方面的内容
注意,我还删除了Debug.Print
参数列表周围的多余括号。括号在过程调用中实际上是有害的;当您将编译错误与多参数过程一起使用时,您将遇到编译错误;当您需要传递对象引用时,您将遇到运行时错误;当您打算传递参数时,您将遇到逻辑错误,不管被调用的过程是否表示它使用了ByRef
参数
调用函数并在局部变量中捕获其返回值时,请使用括号。Load myForm
将是多余的,因为myForm
是一个对象变量,在那个时候自动实例化…我不确定这会在OP的计算机上产生什么影响,但没有其他两个人测试相同的代码?我不知道我可以直接在With块中实例化和创建对象。从现在起,如果适用,我将尝试使用此选项。感谢您提供有关使用括号的详细信息。@Svatik或者,您可以通过将局部变量Dim myForm声明为UserForm1
,然后在条件块内执行Set myForm=New UserForm1
来分离Dim
和New
。尽管如此,我喜欢使用New
保存对象实例并确保其正确销毁的方式(永远不要跳入/跳出带有New块的),至于作为New
的含义,尝试使用New UserForm1执行Dim foo,然后执行设置foo=Nothing
,然后,Debug.Print foo什么都不是
-比较期望值和实际值;-)我不确定是否理解最后一部分。这是否意味着即使我对物体没有任何影响,它也不会被摧毁?或者,当我在Debug.Print中使用它时,它是否再次实例化?当您将Dim foo作为新事物
时,VBA确保foo
在其声明的整个范围内都是事物
的有效实例,无论发生什么情况。在UserForm
的情况下,这可能意味着用户单击红色的“X”关闭表单,对象与其状态一起被销毁(假设您没有处理QueryClose
),然后当调用代码查询表单的状态(例如某些属性或复选框状态)时,它读取的是默认状态,因为它不是在看同一个对象,而是一个当场重生的对象:VBA根据需要重新创建对象;这段对话已经结束。
If Target.Cells(1).Value = "Test" Then
Cancel = True
Load myForm
myForm.Show
End If
Dim myForm As New UserForm1
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
If Target.Cells(1).Value = "Test" Then
Cancel = True
With New UserForm1
.Show
End With
End If
Debug.Print "OK"
End Sub