为啥 MS Excel 在 Worksheet_Change Sub 过程中崩溃并关闭?

Posted

技术标签:

【中文标题】为啥 MS Excel 在 Worksheet_Change Sub 过程中崩溃并关闭?【英文标题】:Why MS Excel crashes and closes during Worksheet_Change Sub procedure?为什么 MS Excel 在 Worksheet_Change Sub 过程中崩溃并关闭? 【发布时间】:2012-12-01 09:42:47 【问题描述】:

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

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

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

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

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

但我真的需要它在Worksheet_Change() 过程中工作。

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

【问题讨论】:

类中的代码不会在那里“崩溃”,而是在调用代码中。 “测试页”是否存在? 是的,它存在,错误似乎只发生在我在 Worksheet_Change 中运行代码时发生 写公式时“testpage”表中的 Range("A1:A8") 是否干净?那里没有数据透视表或类似的东西吗?另外,只是好奇,为什么每次更改工作表后都需要在同一位置编写相同的公式? 【参考方案1】:

我在使用Worksheet_Change时推荐这个

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

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

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

试试这个

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

CountLarge 是从 Excel 2007 开始引入的,因为Target.Cells.Count 返回的 Long 值可能会在 Excel 2007 中出错,因为总单元格数增加。

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

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

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

要检测特定范围内的变化,请再次使用Intersect。例如,如果在A1: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

【讨论】:

感谢 Siddharth,当我删除工作表名称时它工作正常,没有任何崩溃 Gr8!我希望您按照上面的建议关闭/打开事件? +1。另一种好的做法是进一步限制更改触发代码的区域,方法是使用以下内容:If Not Intersect(Target, Range("D1:D8")) Is Nothing Then ...End If。在此示例中,只有在此范围内的单元格发生更改时,您的代码才会运行。 @Siddharth, @Doug,为什么在 Worksheet_Change 函数中使用Range(),而不是Target.Parent.Range(),我认为它更正确、更安全? Range() 指的是活动工作表,它不一定是被更改的工作表(例如,如果 VBA 代码导致在另一个工作表处于活动状态时更改此工作表)。 @ErikEidt,我通常在事件中使用 Me.Range。但我的测试证实了 Siddharth 在他的回答中所说的话,即工作表的 Change 事件中的 Range 将引用该工作表中的一个范围,无论哪个工作表处于活动状态。【参考方案2】:

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

【讨论】:

【参考方案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

【讨论】:

以上是关于为啥 MS Excel 在 Worksheet_Change Sub 过程中崩溃并关闭?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 中从 ms-word 或 ms-excel 打开 excel、doc

如何从我的应用程序在MS-Excel或MS-Word - Android中打开excel,doc文件

MS Excel:在Excel中按总和分组

在 VBA 中查找适用于 MS Access 和 MS Excel 的应用程序目录路径

将 MS Excel 链接到 MS Access 查询

更新 MS - 通过 MS-Excel 单元格访问字段