【问题标题】:Calling a custom built VBA function when an Excel cell is changed更改 Excel 单元格时调用自定义构建的 VBA 函数
【发布时间】:2015-07-28 11:07:08
【问题描述】:

我想先说我是一名大学本科生,了解 C++ 并对 VBA 有非常基本的了解。

现在,如标题中所述,我需要一些帮助来为 Excel 工作表配置一些 VBA 代码,以便每当修改列中的单元格(特别是 D 列)时,它会自动更新同一行中的其他单元格。

基本上我希望它能够工作,这样当用户 Bob 修改单元格 D26(例如)时,它将调用我构建的自定义函数并将该代码插入到单元格 B26 中,然后对单元格 C26 使用不同的函数重复。

然而,这个函数需要这样,如果单元格 D27 被修改,它只会修改第 27 行中的其他单元格,只留下第 26 行和前面或后面的行,直到在 D28 中调用这个函数等等.

我不完全确定这是否可能,但如果有人可以帮助我配置它,我会很感激。

我为自定义函数从 Internet 构建/清除的代码如下: http://pastebin.com/RE0V2nrT

我要为这个项目调用的第二个函数是 Excel 中内置的 =TODAY() 函数。

到目前为止,我为检查单元格是否已更改而拼凑的代码是这样的: http://pastebin.com/S5E8cmty

如果有人可以帮助我了解如何编写我正在寻找的内容,将不胜感激。如果你有不同的方法来解决这个问题,我也很想听听......只要你能帮助我,然后制定你的解决方案,哈哈!

无论如何,感谢任何回复的人。

【问题讨论】:

    标签: excel vba automation


    【解决方案1】:

    查看 Excel 命名空间中可用的 worksheet events。 为此,您将使用Change event

    如果您双击要监控的工作表,您可以插入一个Worksheet_Change 子。然后您可以使用intersect function 检查更改的单元格是否在您要监控的范围内(例如 D:D)。

    您可以指定要更改的单元格。在这里,我只是根据您的要求举了一个例子。这会将函数的输出放入单元格 B[R] 并将当前日期放入单元格 C[R]。请注意,我使用的是 Now() 函数,因为 VBA 中没有 Today() 函数。因为这会返回日期和时间,所以我使用 Format 函数来获取日期。

    为了好玩,让我们再深入一点对象模型,首先获取目标范围所属的Worksheet object。这不是 100% 必要的 - 你可以只依赖 ActiveSheet。现在,您可能不需要这样做,这主要是为了好玩,但还值得注意的是,如果您以编程方式更改此工作表,但没有先激活此工作表(因此另一个工作表处于活动状态)和你没有关闭EnableEvents 你会得到一些奇怪的结果:)

    Private Sub Worksheet_Change(ByVal Target As Range)
        Dim TargetSheet As Worksheet
        Set TargetSheet = Target.Parent
        With TargetSheet
            If Not Application.Intersect(Target, .Range("D:D")) Is Nothing Then
                .Cells(Target.Row, 2) = ExtractWindowsUser()
                .Cells(Target.Row, 4) = Format(Now(), "YYYY-MM-DD")
            End If
        End With
    
    End Sub
    

    说明

    Worksheet change sub 是这样声明的。 Worksheet 对象具有用于事件的预定义方法存根。有点像一个接口,虽然没有在文档中列为接口。如果您在该概念中考虑它,这就是您的事件握手。 有关可用工作表事件的列表,请参阅我在上面发布的链接。
    Private Sub Worksheet_Change(ByVal Target As Range)

    在接下来的几行中,我们将获取名为Target 的对象所属的工作表对象。您可以在子声明中看到Target 被声明为Range 类型的对象。如果您查看 Worksheet 对象(上面链接)或Range object 文档,您会看到范围对象是工作表对象的成员,并且这里的文档有点糟糕,但仅供参考,工作表对象包含在Parent property现在,最初我的代码使用 Application 对象的 ActiveSheet 成员 - 但出于上述答案中给出的原因,我已经对其进行了编辑。

    Dim TargetSheet As Worksheet
    Set TargetSheet = Target.Parent
    

    我使用With Blocks 来节省在多个位置键入相同的工作表引用。 With 块只允许我通过键入.SomeMember 访问指定命名空间的成员(在本例中为对象TargetSheet 的成员)。编译器理解每个像这样的引用都指的是在开头的With .... 语句中指定的任何内容。我个人喜欢这样的可读性,但我也推荐它进行维护(更改引用一个地方与多个地方)。同样,拥有一个引用也会带来微小的、微不足道的、可能不值得一提的对多个引用的性能提升。

    With TargetSheet

    接下来我们检查Target 是否在我们想要观察的单元格范围内。 If....Then 应该看起来很熟悉。对于我们的条件,我们使用boolean operator Not 来检查相交函数(上面链接)的结果是否为Nothing。我们这样做的原因是检查是否分配了回报。如果分配了一个对象,则Not SomeObject Is Nothing 条件将评估为False。如果对象未分配(即我们的 Intersect 函数未能返回任何内容),则该语句的计算结果为 True。因此,从 Intersect 函数文档中我们知道,如果我们的 return 被分配,则范围相交并且相交范围对象被返回。因此,如果我们想知道它们是否相交,我们可以只检查失败的反面。

    If Not Application.Intersect(Target, .Range("D:D")) Is Nothing Then

    接下来的几行只需在与Target 相同的行中的单元格上执行一些代码。我们使用工作表对象的Cells 成员来指定要修改的单元格。根据文档,Cells 的默认属性是Item,它允许我们通过如下的行和列索引访问范围对象:.Cells[Row,Column]。因此,我只需使用我们的Target 对象的行和您想要的列(列“A”=1、“B”=2 等。如果您有兴趣,可以通过将 excel 属性更改为 R1C1 引用样式来看到这一点)。

    .Cells(Target.Row, 2) = ExtractWindowsUser()

    我认为Format() 和 Now() 函数在文档中得到了很好的解释。

    【讨论】:

    • 感谢您的回复!不过,我想提出一个简短的问题,您为什么使用“With ActiveSheet”以及“If Not Application.Intersect”有什么作用?
    • @Jason - 如果我的回答有助于解决您的问题,请单击旁边的复选标记使其变为绿色 :) 谢谢!
    • 我会更新我的答案来解释这些事情。我想来自 C++ 他们会很明显。等一下……
    • 好的,是的,也许可以确切地问​​“它们是什么?”并不能很好地表明我的实际问题。我认为我的措辞很糟糕,应该是:ActiveSheet 将使它成为启用此 Worksheet_Change 加载项的 Excel 文件中的任何工作表都能够使用它,对吗?那么如果 sheet2 和 sheet1 检测到 D 列发生变化,它们会自动更新吗?我只是好奇,因为我现在还不能完全让代码工作。我将您的代码保存为加载项 (.xlam),但是当我更改 D 列中的单元格时它不会运行。我是否正确保存它?
    • 不要将其保存为加载项。从 excel (Alt+F11) 进入 VBA,查看左侧的项目资源管理器树。在那里看到你的工作簿?单击加号 - 您将看到该工作簿中的所有模块。双击要监视更改的工作表以打开该工作簿的代码模块。将代码粘贴到那里。见截图:i.imgur.com/fJEeXd8.png
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2016-12-18
    相关资源
    最近更新 更多