【问题标题】:Run a macro when certain cells change in Excel but from my Personal workbook当某些单元格在 Excel 中更改但从我的个人工作簿中更改时运行宏
【发布时间】:2013-08-06 17:38:59
【问题描述】:

问题:我发现许多帖子(包括 Microsoft 自己的支持站点)包含有关在 Excel 中某些单元格更改时如何运行宏的信息。我可以让它工作,但我需要将该子存储在我的 Personal.xlsb 工作簿中,并让它影响另一个工作簿中的命名工作表。

背景:我经常从第三方收到一个 Excel 文件并在其上运行一系列例程,所有宏都存储在我的 Personal.xlsb 隐藏工作簿中。该过程的一部分要求我“撤消”当用户在特定单元格中输入日期时自动进行的许多格式更改。一旦用户在给定的 5 个工作表中指定的单元格中输入日期,我想在 5 个单独的工作表上调用这些“撤消”子项。但是,我已经在线阅读的所有关于此的帮助都让我将代码添加到需要进行更改的确切工作表中。我想将该代码存储在我的个人工作簿中的一个模块中,以便它可以在任何包含工作表名称的工作簿上运行......类似于我布置其他查询的方式。

到目前为止的代码

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim KeyCells As Range
    Set KeyCells = Range("W9")

    If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
        MsgBox "You changed THE CELL!"
    End If
End Sub

问题:如何修改 sub 以使其在包含指定工作表的所有工作簿中生效?或者在外面的某个地方对我来说有更好的选择吗?

【问题讨论】:

  • 我不确定您如何使用存储在您的个人宏工作簿中的代码来响应不同用户的操作?这就是我从你的问题中得到的印象,所以也许我误解了你在寻找什么......
  • 澄清一下,我知道我需要将代码添加到每个用户的个人工作簿中,以便他们拥有与我相同的功能。
  • OK - 如果你想这样做,那么你需要在应用程序级别捕获事件。请参阅此处了解概览:cpearson.com/excel/appevent.aspx
  • 感谢蒂姆的建议。我通读了那篇文章,以及该页面上的另一篇参考文章,但我认为这仍然超出了我的范围......当它位于单独的工作簿中时,我无法让该事件正常工作。哦,好吧……你能为VB/VBA初学者推荐一本好书吗?

标签: excel vba


【解决方案1】:

由于我遇到了同样的问题,我按照 Chip Pearson 的说明进行了工作,并将为您提供更全面的指南。

我也非常鼓励您通过Chip Pearson's great summary 阅读有关事件的方式。我知道要消化的内容很多,但它会极大地帮助您了解我们在这里的实际工作。

作为概述,这些是我们将要执行的步骤:

  1. 为我们的事件处理程序添加一个类模块(这是实际事件处理代码所在的位置)
  2. 向我们的 personal.xlsbThisWorkbook 模块添加一个事件处理程序来连接我们的事件处理程序类
  3. 享受无限的事件处理循环,因为我们更改了Target.Value :-P(可选

让我们开始吧。

1。添加类模块

首先,我们需要创建一个舒适的广场来放置我们所有的事件处理程序。我们将为此使用一个类模块,因为它提供了一些不错的结构,并且您可以立即知道在哪里寻找您的应用程序级事件处理程序。

在您的personal.xlsb 的VBA 项目中,通过在项目浏览器中右键单击 创建一个新类 -> 插入 -> 类模块.

通过在属性窗格中更改名称,将类重命名为 CAppEventHandler

将下面列出的源代码(设置部分和事件处理部分)添加到您刚刚创建的类中。 (请务必阅读 cmets,因为它们为我们正在做的事情和原因添加了一些额外的信息。

2。添加初始化事件处理程序

现在我们需要确保在打开 personal.xlsb 时“激活”我们的事件处理程序(因此无论何时打开 Excel :))。

为此,请双击您的 ThisWorkbook 模块并添加以下代码。

现在您实际上已经可以开始测试您的事件处理了。您唯一需要事先做的事情(为了触发“连接”过程)就是重新启动 Excel

注意事项

  • 我在事件处理程序的开头添加了对当前工作表名称的检查 - 因此请确保您的工作表名为“MySheet”:)
  • 您可以在处理程序中设置断点并观察它的运行情况,就像任何其他 VBA 代码一样

还有一点警告(又名 3. 享受无限的事件处理循环
当我对此进行测试时,我天真地使用Target.Value = "It wooooorks!" 作为我们更改右侧工作表上的右侧单元格时要执行的代码。 那不好。
有关如何防止此类事件循环,请参阅代码的最后一个 sn-p(也取自 Chip's post)。

源代码

CAppEventHandler 类中(设置)

Option Explicit

' Declare our own reference to the Application object
' WithEvents is needed to capture the events of the application object
' (Note: The events 'bubble up' from the Worksheet to the Workbook and
'        finally to the Application.
'        So event handlers in the Sheet module are executed first
'        (if any handlers are declared), then the ones in the Workbook
'        module (again, if they are declared) and finally the ones
'        in the Application module.)
Private WithEvents App As Application

' Whenever a new object of a class is instantiated, the _Initialize-Sub is called,
' that's why we use this Sub to get the reference to the current Application object
Private Sub Class_Initialize()
    Set App = Application
End Sub

CAppEventHandler 类中(实际事件处理)

' Here is the actual code executed whenever the event reaches the Application level
' (see above for the order of 'bubbling up' of the events) and hasn't been marked
' as handled before
Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range)

    If Sh.Name <> "MySheet" Then
        Exit Sub
    End If

    Dim rngKeyCells As Range
    Set rngKeyCells = Sh.Range("A5")

    If Intersect(rngKeyCells, Target) Is Nothing Then
        Exit Sub
    End If

    ' Do our actual work
    MsgBox "It wooooorks!", vbInformation

    ' Note: If you want to change the contents of your keyCells, you will
    '       have to make sure to prevent an infinite event loop (i.e. using
    '       Application.EnableEvents = False because otherwise changing
    '       the value in your macro will trigger the event again

End Sub

ThisWorkbook 模块中

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' The following code must be placed in the "ThisWorkbook" module of your personal.xlsb
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Option Explicit

Private OurEventHandler As CAppEventHandler

Private Sub Workbook_Open()
    ' Since we declared so in our _Initialize-Sub this wire-up the current
    ' Application object in our EventHandler class
    Set OurEventHandler = New CAppEventHandler
End Sub

如何防止事件循环

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    Target.Value = Target.Value + 1
    Application.EnableEvents = True
End Sub

(来自Chip Pearson's comprehensive post on events

【讨论】:

    猜你喜欢
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 2010-09-29
    相关资源
    最近更新 更多