如何仅在单元格值更改时执行指令?
How do I execute instructions only if the cell value change?
我有一个 ByVal 代码可以清除 table 内特定范围的内容,它有效。但是我需要为指令执行添加一个条件 如果范围值(内容)发生变化,而不是如果我只将光标放在它上面。
此外,有人知道如何在 VBA 中引用 table 列 ?现在我使用的是估计范围“C1:C999”,但我想使用他的名字“A_[OPERATION]”。
这是代码:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Application.Intersect(Range("C1:C999"), Range(Target.Address)) Is Nothing Then
Range(Selection, Selection.End(xlToRight)).ClearContents
End If
End Sub
您可以改用更改事件。
这是文档的 link:
https://docs.microsoft.com/en-us/office/vba/api/excel.worksheet.change
或者,您可以将目标单元格的值保存在变量中,并在执行清除内容之前检查该值是否发生变化。
对于你的第二个问题,你可能应该单独问一下 post。
工作表更改
- 调整table名称(
tName
)和header(列)名称(hName
)。
- 我已经调整它以清除列后单元格中的内容。
- 如果您确实也需要清除该列的内容,请将
cel.Offset(, 1)
替换为 cel
。
- 在 table 中,如果手动或通过 VBA 更改了列中的值,当前设置将自动清除指定列右侧所有单元格的内容。如果该列包含公式,这将不起作用。 Non-contiguous 也支持删除。
代码
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const ProcName As String = "Worksheet_Change"
On Error GoTo clearError
Const tName As String = "A_"
Const hName As String = "OPERATION"
Dim rng As Range
Set rng = Range(tName & "[" & hName & "]")
Set rng = Intersect(rng, Target)
If rng Is Nothing Then GoTo ProcExit
Application.EnableEvents = False
With ListObjects(tName).HeaderRowRange
Dim LastColumn As Long
LastColumn = .Columns(.Columns.Count).Column
End With
Dim cel As Range
For Each rng In rng.Areas
For Each cel In rng.Cells
With cel.Offset(, 1)
.Resize(, LastColumn - .Column + 1).ClearContents
End With
Next cel
Next rng
CleanExit:
Application.EnableEvents = True
GoTo ProcExit
clearError:
Debug.Print "'" & ProcName & "': " & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
On Error GoTo 0
GoTo CleanExit
ProcExit:
End Sub
Worksheet_Change
event-handle.
捕获了单元格值的变化
不过这个句柄即使是假改也会触发。例如,如果更改前的单元格值为“A”,而用户刚刚在单元格中再次输入“A”,无论如何都会触发更改事件过程。
为了避免这种情况,我们可以同时使用 Worksheet_Change
和 Worksheet_SelectionChange
。
使用Worksheet_SelectionChange
,我们在某处记录旧值,比如Name
。然后使用 Worksheet_Change
,我们可以将用户输入的内容与 Name
进行比较,以查看是否进行了真正的更改。
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Nm As Name: Set Nm = ActiveWorkbook.Names("OldValue")
If Target.Count = 1 Then
'This only record one old cell value.
'To record multiple cells old value, use a hidden Worksheet to do so instead of a Name.
Nm.Comment = Target.Value2
else
Nm.Comment = Target.Value2(1, 1)
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Nm As Name: Set Nm = ActiveWorkbook.Names("OldValue")
If Target.Value2 <> Nm.Comment Then
Debug.Print "True change"
Else
Debug.Print "False change"
End If
End Sub
您可以通过 listobject
对象访问 table 的方法和属性。以下是如何执行此操作的示例。
Sub Example()
Dim lo As ListObject
Dim lc As ListColumn
Set lo = Range("Table1").ListObject
Set lc = lo.ListColumns("Column2")
End Sub
也就是说,对于您的情况,它将是 Range("A_").ListObject.ListColumns("OPERATION").DataBodyRange
。
我有一个 ByVal 代码可以清除 table 内特定范围的内容,它有效。但是我需要为指令执行添加一个条件 如果范围值(内容)发生变化,而不是如果我只将光标放在它上面。
此外,有人知道如何在 VBA 中引用 table 列 ?现在我使用的是估计范围“C1:C999”,但我想使用他的名字“A_[OPERATION]”。
这是代码:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Application.Intersect(Range("C1:C999"), Range(Target.Address)) Is Nothing Then
Range(Selection, Selection.End(xlToRight)).ClearContents
End If
End Sub
您可以改用更改事件。
这是文档的 link: https://docs.microsoft.com/en-us/office/vba/api/excel.worksheet.change
或者,您可以将目标单元格的值保存在变量中,并在执行清除内容之前检查该值是否发生变化。
对于你的第二个问题,你可能应该单独问一下 post。
工作表更改
- 调整table名称(
tName
)和header(列)名称(hName
)。 - 我已经调整它以清除列后单元格中的内容。
- 如果您确实也需要清除该列的内容,请将
cel.Offset(, 1)
替换为cel
。 - 在 table 中,如果手动或通过 VBA 更改了列中的值,当前设置将自动清除指定列右侧所有单元格的内容。如果该列包含公式,这将不起作用。 Non-contiguous 也支持删除。
代码
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const ProcName As String = "Worksheet_Change"
On Error GoTo clearError
Const tName As String = "A_"
Const hName As String = "OPERATION"
Dim rng As Range
Set rng = Range(tName & "[" & hName & "]")
Set rng = Intersect(rng, Target)
If rng Is Nothing Then GoTo ProcExit
Application.EnableEvents = False
With ListObjects(tName).HeaderRowRange
Dim LastColumn As Long
LastColumn = .Columns(.Columns.Count).Column
End With
Dim cel As Range
For Each rng In rng.Areas
For Each cel In rng.Cells
With cel.Offset(, 1)
.Resize(, LastColumn - .Column + 1).ClearContents
End With
Next cel
Next rng
CleanExit:
Application.EnableEvents = True
GoTo ProcExit
clearError:
Debug.Print "'" & ProcName & "': " & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
On Error GoTo 0
GoTo CleanExit
ProcExit:
End Sub
Worksheet_Change
event-handle.
不过这个句柄即使是假改也会触发。例如,如果更改前的单元格值为“A”,而用户刚刚在单元格中再次输入“A”,无论如何都会触发更改事件过程。
为了避免这种情况,我们可以同时使用 Worksheet_Change
和 Worksheet_SelectionChange
。
使用Worksheet_SelectionChange
,我们在某处记录旧值,比如Name
。然后使用 Worksheet_Change
,我们可以将用户输入的内容与 Name
进行比较,以查看是否进行了真正的更改。
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Nm As Name: Set Nm = ActiveWorkbook.Names("OldValue")
If Target.Count = 1 Then
'This only record one old cell value.
'To record multiple cells old value, use a hidden Worksheet to do so instead of a Name.
Nm.Comment = Target.Value2
else
Nm.Comment = Target.Value2(1, 1)
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Nm As Name: Set Nm = ActiveWorkbook.Names("OldValue")
If Target.Value2 <> Nm.Comment Then
Debug.Print "True change"
Else
Debug.Print "False change"
End If
End Sub
您可以通过 listobject
对象访问 table 的方法和属性。以下是如何执行此操作的示例。
Sub Example()
Dim lo As ListObject
Dim lc As ListColumn
Set lo = Range("Table1").ListObject
Set lc = lo.ListColumns("Column2")
End Sub
也就是说,对于您的情况,它将是 Range("A_").ListObject.ListColumns("OPERATION").DataBodyRange
。