我希望只要包含公式的单元格中的值发生更改,我的宏就会启动。 即,用户正在修改另一个小区,从而改变了所讨论的小区的值。
我注意到使用声明(在此处找到),只有在用户修改单元格本身时才有效,但如果单元格自动更改则无效 - 由于上面指定的公式。
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A20")) Is Nothing Then ...
有什么想法吗?
我尝试按照这个问题的答案" automatically execute an Excel macro on a cell change"但它不起作用......
提前致谢:)
答案 0 :(得分:1)
可能的解决方法是,为了更改值,用户需要首先更改选择。所以我会:
1)声明一个名为" oldValue"的全局变量。在WS源代码模块之上:
Dim oldValue As Variant
2)在用户输入任何内容之前注册公式的旧值(让我们在范围中说出它(" A4"),我让你适应其他人) :
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
oldValue = Range("A4")
End Sub
3)检查更改是否影响了Change事件中的公式:
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("A4") <> oldValue Then
MsgBox "User action has affected your formula"
End If
End Sub
我已经用简单的总和进行了测试,我能够在没有任何提示的情况下编写没有涉及的单元格,但是如果我触摸了MsgBox将显示的总和中涉及的一个单元格。我让你适应多种情况,用户添加/删除行(在这种情况下,我建议命名包含你想要跟踪的公式的范围)和工作表参考。
编辑 我想立即执行此操作,而不是通过2个进程,是否可能?问题是我的宏涉及一个包含多个单元格的范围,因此很难存储10个单元格的旧值。
如果范围彼此相邻,那么您可以使用集合代替使用变量:
Dim oldValues As New Collection
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
For j = 1 To 10
oldValues.Add Range("A" & j).Value
Next j
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
For j = 1 To 10
If Range("A" & j).Value <> oldValues(j) Then
MsgBox "The value of Range(A" & j & ") has changed"
End If
Next j
End Sub
当然,如果范围彼此不相近,您可以将它们存储在SelectionChange事件中,如下所示:
oldValues.Add Range("A1").Value
oldValues.Add Range("B7").Value
'...
如果你完成了这个ONCE,只有10个范围,它应该是你的问题的合理解决方案。
答案 1 :(得分:1)
你说,“每当包含公式的单元格中的值发生变化时,我希望我的宏启动...”
如果在重新计算包含公式的单元格时运行代码(这不是您要求的那样),一个解决方案可能是创建一个VBA函数,该函数只返回传递给该值的值它, plus 做重新计算公式时你想做的其他事情......
Public Function Hook(ByVal vValue As Variant) As Variant
Hook = vValue
' Add your code here...
End Function
...然后在调用此函数时“包装”您的公式。例如,如果您感兴趣的公式为=A1+1
,则会将其更改为=Hook(A1+1)
,并且只要重新计算Hook
,就会调用A1+1
函数(例如,当A1
中的值发生变化时)。但是,重新计算A1+1
可能会产生相同的结果并仍然调用Hook
函数(例如,如果用户在A1
中重新输入相同的值)。
答案 2 :(得分:1)
声明像Matteo描述的模块级变量绝对是一个很好的方法。
Brian的答案是关于保持所有代码在同一个地方的正确轨道,但它缺少一个关键部分:Application.Caller
当在由单个单元格调用的函数中使用时,Application.Caller
将返回该单元格的Range对象。这样,您可以在调用函数时将旧值存储在函数本身中,然后在计算完新值后,可以将其与旧值进行比较,并根据需要运行更多代码。
编辑:Application.Caller
的优点是解决方案本身就可以扩展,并且无论目标细胞的排列方式如何(即连续或不连续)都不会改变。
答案 3 :(得分:1)
你可以去看看:
首先,在模块代码中声明公共变量。
Public r As Range, myVal '<~~ Place it in Module
其次,在 Workbook_Open 事件中初始化变量。
Private Sub Workbook_Open()
Set r = Sheet1.Range("C2:C3") '<~~ Change to your actual sheet and range
myVal = Application.Transpose(r)
End Sub
最后,设置 Worksheet_Calculate 事件。
Private Sub Worksheet_Calculate()
On Error GoTo halt
With Application
.EnableEvents = False
If Join(myVal) <> Join(.Transpose(r)) Then
MsgBox "Something changed in your range"
'~~> You put your cool stuff here
End If
myVal = .Transpose(r)
forward:
.EnableEvents = True
End With
Exit Sub
halt:
MsgBox "Error " & Err.Number & ": " & Err.Description
Resume forward
End Sub
当C2:C3中的值发生变化时,上面将触发事件 不是很整洁,但可以检测目标范围的变化。 HTH。