【问题标题】:'28' Out of Stack Space. Worksheet_Change and Application.ScreenUpdating'28' 堆栈空间外。 Worksheet_Change 和 Application.ScreenUpdating
【发布时间】:2014-04-22 06:28:34
【问题描述】:

提前感谢您提供的任何明确信息。

在一个包含许多模块和工作表的 Excel 工作簿中,在 SHEET2 的 VBA 代码的底部,有这个子例程:

Private Sub Worksheet_Change(ByVal Target As Range)

Dim TargetCells As Range

Set TargetCells = Range("B1000:B1029")

If Not Application.Intersect(TargetCells, Range(Target.Address)) Is Nothing Then
   Call SpecificSubRoutine
End If

End Sub

我对这段代码的理解是,它会监视整个工作表的任何更改。如果 ANYTHING 发生更改,则工作表上的任何位置都会运行 If 语句。如果对工作表所做的任何更改发生在指定的 TargetCells 范围之外,则 If 语句将失败,但此 Sub 仍会在每次更改工作表时尝试验证 If 语句。

现在,您可能会猜到我的问题是堆栈溢出。 (运行时错误'28':堆栈空间不足)

每当Worksheet_Change Sub 运行时,如果对工作表的更改是在TargetCells 范围内进行的,它会调用填充单元格的SpecificSubRoutine,这会在每次SpecificSubRoutine 填充时触发Worksheet_Change Sub任何细胞。 (SpecificSubRoutine 也调用不同的模块,这些模块当然会填充单元格,这当然会触发Worksheet_Change Sub)

不太好。

此外,整个应用程序中的大多数子例程都包含在Application.ScreenUpdating = False / Application.ScreenUpdating = True 中,我错误地认为这会限制Worksheet_ChangeApplication.ScreenUpdating = True 运行后立即被调用一次的次数。

重要提示: SpecificSubRoutine 和它调用的任何子例程都不会填充TargetCells 范围内的单元格。 我没那么暗。 ..

这是我的问题:

  1. 有没有办法缩小触发Worksheet_Change Sub 的范围,以便只有TargetCells 范围内的更改才会触发它? (而不是更改工作表中的任何位置)
  2. 有没有办法做我错误地认为Application.ScreenUpdating 会做的事情? (在一次批量更新中对工作表进行全部更改,而不是几乎每一步都触发更改)
  3. 另外,作为一个额外的好奇心,有没有办法让Worksheet_Change 监视 2 个特定范围(而不是整个工作表?)知道如何做到这一点至关重要,并且可能会解决所有问题工作表。

我的直觉是将End 添加到SpecificSubRoutine 的最后一部分,或者添加到它调用的任何/所有子例程的末尾,但我只是不确定这会绕过@ 987654342@ 多次,因为Application.ScreenUpdating 不会像我想的那样批量更新。

想法?

【问题讨论】:

  • Worksheet_Change和最后Application.EnableEvents=True的开头添加Application.EnableEvents=False
  • @simoco,这是一个很好的指针。谢谢!

标签: vba excel stack-overflow


【解决方案1】:

第 1 部分:否 - 事件处理程序响应工作表上的所有更改:您如何响应该更改的任何过滤都必须发生在处理程序本身中。

第 2 部分:@simoco 回答

第 3 部分(并结合 simoco 的建议):

Private Sub Worksheet_Change(ByVal Target As Range)

    Application.EnableEvents=False

    If Not Application.Intersect(Me.Range("B1000:B1029"), Target) Is Nothing Then
       Call SpecificSubRoutine
    End If

    If Not Application.Intersect(Me.Range("D1000:D1029"), Target) Is Nothing Then
       Call SomeOtherSpecificSubRoutine
    End If

    Application.EnableEvents=True

End Sub

【讨论】:

  • 除了额外的结束括号外,这可以按我的意愿工作,谢谢蒂姆。我想知道是否有任何方法可以为范围声明事件处理程序,例如:A1_Change 而不是 Worksheet_Change
  • 这在我的回答的“第 1 部分”中有所介绍。
  • 是的,我读了“第 1 部分”,因为我非常珍惜我在这个网站上得到的每一个回复。我敢肯定,对于有幸了解 VBA 的人来说,这非常有意义,但对我来说,“过滤您如何响应该更改必须发生在处理程序本身中”没有任何意义。您是在谈论更改ByVal Target As Range 部分以观看特定范围吗?我目前正在研究事件处理程序,所以如果这是一个开放式问题,我可能很快就能自己找到答案。
  • 您如何决定采取什么行动(如果有)在第 3 部分中显示 - 您需要检查提供的范围 Target,它表示更改触发 Worksheet_Change Sub 的范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 2016-05-23
相关资源
最近更新 更多