【问题标题】:How do I change my macro into a Worksheet_Change event Excel VBA如何将我的宏更改为 Worksheet_Change 事件 Excel VBA
【发布时间】:2018-05-16 05:13:42
【问题描述】:

我有一个在工作簿关闭时调用的宏。它检查不同工作表上两个表中的列,并根据找到的内容分配行号。

Worksheet_Change 处理程序位于具有Projects 范围的工作表上。 Database 范围位于同一工作簿的另一个工作表上。

每当我在其他任何地方调用宏时,它要么生成错误,要么导致 excel 部分冻结的常见错误(任何人都知道这是什么鬼?!?!?!)。

无论如何,我放弃之前的最后手段是将宏更改为工作表更改事件,我想知道是否可以在创建此事件时获得一些帮助。
原宏:

Sub FindRow()
'This module verifies row numbers in the database by matching them to the opportunities in the Projects
'worksheet. It then assigns row numbers in the Projects worksheet.

    Application.ScreenUpdating = False
    Dim LastRow As Long

    LastRow = Application.ThisWorkbook.Sheets("Projects").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

    Dim rng As Range
    Dim foundRng As Range
    For Each rng In Sheets("Projects").Range("B2:B" & LastRow)
        Set foundRng = Sheets("Database").Range("C:C").Find(rng, LookIn:=xlValues, lookat:=xlWhole)
        If Not foundRng Is Nothing Then
            rng.Offset(0, -1) = foundRng.Row
        End If
    Next rng
    Application.ScreenUpdating = True
End Sub

我提议的更改:

 Public Sub Worksheet_Change(ByVal Target As Range)
     Dim Records As Range

        Set Records = Range("Records")
        If Not Application.Intersect(Records, Range(Target.Address)) Is Nothing Then
        Application.ScreenUpdating = False
        Dim LastRow As Long    
        LastRow = Application.ThisWorkbook.Sheets("Projects").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

        Dim rng As Range
        Dim foundRng As Range
        For Each rng In Sheets("Projects").Range("B2:B" & LastRow)
            Set foundRng = Sheets("Database").Range("C:C").Find(rng, LookIn:=xlValues, lookat:=xlWhole)
            If Not foundRng Is Nothing Then
                rng.Offset(0, -1) = foundRng.Row
            End If
        Next rng
        Application.ScreenUpdating = True
End If
    End Sub

但是,我在定义变量 LastRow 的行上不断收到错误消息。
即使之前所有内容都已正确定义,我也会收到应用程序定义的错误。

提前致谢。

【问题讨论】:

  • 你做过调试吗? lastrow 的价值是什么?
  • @SJR 调试没有任何结果,因为它不喜欢这行代码,所以甚至都懒得运行它。当它在独立模块中作为宏运行时,它确实给了我正确的行,即表格的最后一行。
  • 你没有说错误是什么......this 是否有机会解决你的问题?
  • @Remi 已要求您澄清涉及哪些工作表并提供一个最小示例。你知道为什么有人问这个吗?找出您的代码不起作用的原因。因此,如果您不想提供这些信息,请不要在问题关闭时感到惊讶。
  • RE "奇怪的是,在它导致错误之后,我无法选择工作簿中任何工作表上的任何单元格,即使在我结束宏之后也是如此。我必须关闭工作簿并重新打开它以再次处理它。这就像它试图崩溃然后忘记它或其他东西。“ -​​ 那是因为您将Application.ScreenUpdating设置为False。在即时窗格 (Ctrl+G) 中键入 Application.ScreenUpdating = True,一切都会恢复正常。 Excel 不会重新绘制自己,因为您明确告诉它不要这样做。

标签: vba excel


【解决方案1】:

Worksheet_Change 句柄位于具有Projects 范围的工作表上。数据库范围位于同一工作簿中的另一个工作表上。 – 雷米 1 分钟前

这意味着rng 也在Projects 表上:

For Each rng In Sheets("Projects").Range("B2:B" & LastRow)

(顺便说一句,Me.Range("B2:B" & LastRow) 在这里就不会那么模棱两可了)

您正在处理Projects 工作表上的Worksheet_Change 事件,只要Projects 工作表上的单元格值发生更改,Excel 就会触发该事件。然后在那个处理程序中,你这样做:

rng.Offset(0, -1) = foundRng.Row

rngProjects 工作表上的一个范围,您正在进入工作表更改的递归循环, 很可能是导致代码崩溃的原因。

当您进行工作表更改同时处理工作表更改时,您需要告诉 Excel“没关系,我知道了”,方法是防止它每次都重新触发 Worksheet.Change 事件:

Application.EnableEvents = False

'...code...

Application.EnableEvents = True

此外,当您切换 Application.ScreenUpdating = False 时,您是在告诉 Excel“在我这么说之前不要重新绘制自己”——这在很多情况下可以大大加快速度,但这也意味着您需要切换如果发生不好的事情,它会手动重新启动。

您可以通过实现错误处理程序来避免这种情况 - 原则如下:

Sub DoSomething()
    On Error GoTo CleanFail
    Application.EnableEvents = False
    Application.ScreenUpdating = False

    '...code...

CleanExit:
    Application.EnableEvents = True
    Application.ScreenUpdating = True
    Exit Sub
CleanFail:
    Debug.Print Err.Description
    Stop
    Resume CleanExit
    Resume 'F8 takes you to the error-throwing statement
End Sub

【讨论】:

  • 成功了!我添加了您建议的 On Error GoToCleanExitCleanFail 代码行并且它有效!并且没有错误。我不知道它为什么会起作用,但谢谢!
【解决方案2】:

您尚未指明哪个工作表是具有 worksheet_change 事件的活动工作表。

无论如何,这里有一个代码可以在 B 列“项目”中找到最后一行

    Dim LastRow As Long, sh As Worksheet

    Set sh = Sheets("Projects")

    LastRow = sh.Cells(sh.Rows.Count, "B").End(xlUp).Row
    MsgBox LastRow & " is the last row in Column B Sheet Projects!"

【讨论】:

  • 包含Records 范围的工作表是活动工作表。但这不是问题。问题是 LastRow = ThisWorkbook.Sheets("Projects").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row 行在代码的一个版本中可以正常工作,然后在另一个版本中不工作。
  • @Remi Set Records = [Me.]Range("Records") 已经说清楚了。我们仍然不知道Sheets("Projects")是否是同一张纸。
  • @MathieuGuindon 它检查不同工作表上两个表中的列,并根据找到的内容分配行号。我在OP中说过。项目在另一个工作表中。
  • @Remi 好的,看,最后一次:具体来说,这个Worksheet_Change 处理程序是在哪个工作表中编写的?与您似乎暗示的相反,“另一张纸”不清楚。
  • @MathieuGuindon Worksheet_Change 句柄位于工作表上 Projects 范围内。 Database 范围位于同一工作簿的另一个工作表上。
猜你喜欢
  • 2017-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
相关资源
最近更新 更多