在更改 Excel 单元格时调用自定义构建的 VBA 函数
Calling a custom built VBA function when an Excel cell is changed
我想先说明一下这个问题,我是一名了解 C++ 的大学本科生,对 VBA 有非常初步的了解。
那么,正如标题中所述,我需要一些帮助来为 Excel 工作表配置一些 VBA 代码,以便每当修改列中的单元格(特别是 D 列)时将自动更新同一行中的其他单元格。
基本上我希望它能工作,这样当用户 Bob 修改单元格 D26(例如)时,它将调用我构建的自定义函数并将该代码插入单元格 B26,然后对单元格 C26 重复不同的函数。
但是,此函数需要这样,如果修改单元格 D27,它只会修改第 27 行中的其他单元格,而保留第 26 行和之前或后续行,直到在 D28 中调用此函数,并且等等。
我不确定这是否可行,但如果有人可以帮助我配置它,我将不胜感激。
我 built/scavenged 来自互联网的自定义函数代码是这样的:
http://pastebin.com/RE0V2nrT
我想为这个项目调用的第二个函数是 Excel.
中内置的 =TODAY() 函数
到目前为止,我拼凑的用于检查单元格是否已更改的代码是这样的:
http://pastebin.com/S5E8cmty
如果有人能帮助我理解如何写出我正在寻找的东西,我将不胜感激。如果你有不同的方法来解决这个问题,我也很想听听...只要你能帮助我然后制定你的解决方案,哈哈!
无论如何,感谢所有回复的人。
查看 Excel 命名空间中可用的 worksheet events。
为此,您将使用 Change event
如果双击要监视的工作表,可以插入一个Worksheet_Change
子。然后您可以使用 intersect function 检查更改的单元格是否在您要监视的范围内(例如 D:D)。
您可以指定要更改的单元格。在这里,我只是根据您的要求举了一个例子。这会将函数的输出放入单元格 B[R],并将当前日期放入单元格 C[R]。请注意,我使用的是 Now()
函数,因为 VBA 中没有 Today()
函数。由于此 return 既是日期又是时间,因此我使用 Format 函数来获取日期。
只是为了好玩,让我们更深入地研究对象模型,首先得到 Worksheet object to which the target range belongs. This is not 100% necessary - you could just rely on ActiveSheet. Now, you probably don't need to do this, and it's mostly just for fun, but it's also worth noting that if you were programmatically making changes to this sheet, but had not activated this sheet first (so another sheet was active) and you had not turned off 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 对象具有预定义的事件方法存根。有点像一个接口,虽然没有在文档中列为接口。如果你用那个概念来想,这就是你的事件握手。 请参阅我上面发布的 link 以获取可用的工作表事件列表。
Private Sub Worksheet_Change(ByVal Target As Range)
在接下来的几行中,我们将获取名为 Target
的对象所属的工作表对象。您可以在子声明中看到 Target
被声明为 Range
类型的对象。如果您签出 Worksheet 对象(link 以上)或 Range object documentation you'll see that the range object is a member of the worksheet object, and the documentation kind of sucks here, but FYI the worksheet object is contained within the 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 to check if the result of the intersect function (linked above) Is Nothing。我们这样做的原因是检查 return 是否已分配。如果分配了一个对象,Not SomeObject Is Nothing
条件将计算为 False
。如果未分配对象(即我们的 Intersect 函数无法 return 任何东西),则该语句的计算结果为 True
。因此,从 Intersect 函数文档中我们知道,如果我们的 return 被分配,则范围相交并且相交的范围对象被 returned。因此,如果我们想知道它们是否相交,我们可以只检查失败的反面。
If Not Application.Intersect(Target, .Range("D:D")) Is Nothing Then
接下来的几行只是在与 Target
相同行内的单元格上执行一些代码。我们使用 Cells member of the worksheet object to specify what cells to modify. Per the documentation, the default property for Cells
is Item,它允许我们通过行和列索引访问范围对象,如下所示:.Cells[Row,Column]
。所以,我简单地使用我们的 Target
对象的行和你想要的列(列 "A" =1,"B"=2 等。你可以通过更改 excel 属性到 R1C1 参考样式,如果您有兴趣)。
.Cells(Target.Row, 2) = ExtractWindowsUser()
而且我认为 Format() 和 Now() 函数在文档中有很好的解释。
我想先说明一下这个问题,我是一名了解 C++ 的大学本科生,对 VBA 有非常初步的了解。
那么,正如标题中所述,我需要一些帮助来为 Excel 工作表配置一些 VBA 代码,以便每当修改列中的单元格(特别是 D 列)时将自动更新同一行中的其他单元格。
基本上我希望它能工作,这样当用户 Bob 修改单元格 D26(例如)时,它将调用我构建的自定义函数并将该代码插入单元格 B26,然后对单元格 C26 重复不同的函数。
但是,此函数需要这样,如果修改单元格 D27,它只会修改第 27 行中的其他单元格,而保留第 26 行和之前或后续行,直到在 D28 中调用此函数,并且等等。
我不确定这是否可行,但如果有人可以帮助我配置它,我将不胜感激。
我 built/scavenged 来自互联网的自定义函数代码是这样的: http://pastebin.com/RE0V2nrT
我想为这个项目调用的第二个函数是 Excel.
中内置的 =TODAY() 函数到目前为止,我拼凑的用于检查单元格是否已更改的代码是这样的: http://pastebin.com/S5E8cmty
如果有人能帮助我理解如何写出我正在寻找的东西,我将不胜感激。如果你有不同的方法来解决这个问题,我也很想听听...只要你能帮助我然后制定你的解决方案,哈哈!
无论如何,感谢所有回复的人。
查看 Excel 命名空间中可用的 worksheet events。 为此,您将使用 Change event
如果双击要监视的工作表,可以插入一个Worksheet_Change
子。然后您可以使用 intersect function 检查更改的单元格是否在您要监视的范围内(例如 D:D)。
您可以指定要更改的单元格。在这里,我只是根据您的要求举了一个例子。这会将函数的输出放入单元格 B[R],并将当前日期放入单元格 C[R]。请注意,我使用的是 Now()
函数,因为 VBA 中没有 Today()
函数。由于此 return 既是日期又是时间,因此我使用 Format 函数来获取日期。
只是为了好玩,让我们更深入地研究对象模型,首先得到 Worksheet object to which the target range belongs. This is not 100% necessary - you could just rely on ActiveSheet. Now, you probably don't need to do this, and it's mostly just for fun, but it's also worth noting that if you were programmatically making changes to this sheet, but had not activated this sheet first (so another sheet was active) and you had not turned off 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 对象具有预定义的事件方法存根。有点像一个接口,虽然没有在文档中列为接口。如果你用那个概念来想,这就是你的事件握手。 请参阅我上面发布的 link 以获取可用的工作表事件列表。
Private Sub Worksheet_Change(ByVal Target As Range)
在接下来的几行中,我们将获取名为 Target
的对象所属的工作表对象。您可以在子声明中看到 Target
被声明为 Range
类型的对象。如果您签出 Worksheet 对象(link 以上)或 Range object documentation you'll see that the range object is a member of the worksheet object, and the documentation kind of sucks here, but FYI the worksheet object is contained within the 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 to check if the result of the intersect function (linked above) Is Nothing。我们这样做的原因是检查 return 是否已分配。如果分配了一个对象,Not SomeObject Is Nothing
条件将计算为 False
。如果未分配对象(即我们的 Intersect 函数无法 return 任何东西),则该语句的计算结果为 True
。因此,从 Intersect 函数文档中我们知道,如果我们的 return 被分配,则范围相交并且相交的范围对象被 returned。因此,如果我们想知道它们是否相交,我们可以只检查失败的反面。
If Not Application.Intersect(Target, .Range("D:D")) Is Nothing Then
接下来的几行只是在与 Target
相同行内的单元格上执行一些代码。我们使用 Cells member of the worksheet object to specify what cells to modify. Per the documentation, the default property for Cells
is Item,它允许我们通过行和列索引访问范围对象,如下所示:.Cells[Row,Column]
。所以,我简单地使用我们的 Target
对象的行和你想要的列(列 "A" =1,"B"=2 等。你可以通过更改 excel 属性到 R1C1 参考样式,如果您有兴趣)。
.Cells(Target.Row, 2) = ExtractWindowsUser()
而且我认为 Format() 和 Now() 函数在文档中有很好的解释。