为什么 MS Excel 在 Sub 过程中崩溃和关闭Worksheet_Change?

Why MS Excel crashes and closes during Worksheet_Change Sub procedure?

提问人:derek 提问时间:12/13/2012 最后编辑:Andrei Konstantinovderek 更新时间:12/30/2022 访问量:40058

问:

当我在 Excel 工作表上运行 VBA 代码时,我遇到了 Excel 崩溃的问题。
我正在尝试在工作表更改上添加以下公式:

Private Sub Worksheet_Change(ByVal Target As Range)
   Worksheets("testpage").Range("A1:A8").Formula = "=B1+C1"
End Sub

运行此代码时,我收到一条消息,说“excel 遇到了问题,需要关闭”,excel 关闭

enter image description here

如果我在过程中运行代码,它工作正常并且不会崩溃Worksheet_Activate()

Private Sub Worksheet_Activate()
   Worksheets("testpage").Range("A1:A8").Formula = "=B1+C1"
End Sub

但我真的需要它在手术中工作。Worksheet_Change()

有没有人在使用该事件时遇到过类似的崩溃,任何人都可以指出正确的方向来解决这个问题吗?Worksheet_Change()

Excel VBA

评论

0赞 iDevlop 12/13/2012
类中的代码不会在那里“崩溃”,而是在调用代码中“崩溃”。“testpage”存在吗?
0赞 derek 12/13/2012
是的,它存在,错误似乎只发生在我在 Worksheet_Change 中运行代码时
0赞 Scott Holtzman 12/13/2012
编写公式时,“testpage”表中的 Range(“A1:A8”) 是否干净?那里没有数据透视表或类似的东西吗?另外,只是好奇,为什么在工作表的每次更改后都需要在同一个地方编写相同的公式?

答:

85赞 Siddharth Rout 12/13/2012 #1

我建议在使用时这样做Worksheet_Change

  1. 不需要工作表名称。在工作表代码模块中,非限定范围参照引用该工作表。也就是说,使用限定符更清楚。如果尝试使用其他工作表,请使用该工作表限定范围参考。Me

  2. 每当使用事件时,如果要将数据写入任何单元格,请始终切换事件。这是必需的,以便代码不会重新触发 Change 事件,并进入可能的无限循环Worksheet_ChangeOff

  3. 每当关闭事件时,请使用错误处理将其重新打开,否则,如果出现错误,代码下次将不会运行。

试试这个

Private Sub Worksheet_Change(ByVal Target As Range)
    On Error GoTo Whoa
    
    Application.EnableEvents = False
    
    Me.Range("A1:A8").Formula = "=B1+C1"
    
Letscontinue:
    Application.EnableEvents = True
    Exit Sub
Whoa:
    MsgBox Err.Description
    Resume Letscontinue
End Sub

在处理此事件时,您可能想知道的其他一些事情。

如果要确保代码在更改多个单元格时不会运行,请添加一个小检查

Private Sub Worksheet_Change(ByVal Target As Range)
    '~~> For Excel 2003
    If Target.Cells.Count > 1 Then Exit Sub
    
    '
    '~~> Rest of code
    '
End Sub

这是在 Excel 2007 中引入的,因为返回一个值,由于单元格总数增加,该值可能会在 Excel 2007 中出错。CountLargeTarget.Cells.CountLong

Private Sub Worksheet_Change(ByVal Target As Range)
    '~~> For Excel 2007
    If Target.Cells.CountLarge > 1 Then Exit Sub
    '
    '~~> Rest of code
    '
End Sub

若要使用所有已更改的单元格,请使用此代码

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim aCell As Range
    
    For Each aCell In Target.Cells
        With aCell
            '~~> Do Something
        End With
    Next
End Sub

要检测特定单元格的变化,请使用 。例如,如果在 Cell 中发生更改,则将触发以下代码IntersectA1

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("A1")) Is Nothing Then
        MsgBox "Cell A1 was changed"
        '~~> Your code here
    End If
End Sub

若要检测特定范围集的变化,请再次使用。例如,如果 范围 发生更改,则将触发以下代码IntersectA1:A10

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("A1:A10")) Is Nothing Then
        MsgBox "one or more Cells in A1:A10 range was changed"
        '~~> Your code here
    End If
End Sub

注意:如果您之前收到错误并且进行了上述更改,并且如果您的代码仍然不起作用,则事件可能尚未重置。在 中,键入并按 键。这会将其重置为 。如果您没有看到 ,请按快捷键 + 启动 .Immediate WindowApplication.EnableEvents = TrueENTERTrueImmediate WindowCtlGImmediate Window

enter image description here

评论

0赞 derek 12/13/2012
感谢 Siddharth,当我删除工作表名称时,它工作正常,没有任何崩溃
1赞 Siddharth Rout 12/13/2012
Gr8!我希望您按照上面的建议关闭/打开事件?
11赞 Doug Glancy 12/13/2012
+1.另一个好的做法是进一步限制其更改触发代码的区域,方法是用类似 ... .在此示例中,仅当更改了此范围内的单元格时,代码才会运行。If Not Intersect(Target, Range("D1:D8")) Is Nothing ThenEnd If
1赞 Erik Eidt 12/19/2012
@Siddharth,@Doug,为什么要在 Worksheet_Change 函数中使用,而不是我认为更正确、更安全的 ? 指活动工作表,它不一定是正在更改的工作表(例如,如果VBA代码导致对另一个工作表处于活动状态的此工作表进行更改)。Range()Target.Parent.Range()Range()
1赞 Doug Glancy 12/19/2012
@ErikEidt,我通常在事件中使用 Me.Range。但我的测试证实了 Siddharth 在他的回答中所说的话,即在工作表的 Change 事件中,无论哪个工作表处于活动状态,都将引用该工作表中的一个范围。Range
15赞 stenci 1/8/2013 #2

Excel 崩溃了,而不是 VBA 函数。
事件未被禁用,调用堆栈由无限循环的 OnChange 事件填充。
有助于查找此类错误的一些建议:在事件的第一行设置断点,然后按 F8 逐步执行它。

0赞 Mario Palumbo 8/18/2018 #3

这个解决方案也很好:

Option Explicit
Private Busy As Boolean
Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Busy Then
        Busy = True
        Range("A1:A8").Formula = "=B1+C1"
        Busy = False
    End If
End Sub