Worksheet_Change 事件中的目标范围不正确
Incorrect target range in Worksheet_Change event
我是一名 Excel-VBA 新手,我正在尝试编写一小段代码,该代码由更改作品中单元格值的人触发sheet。如果 changed 单元格的值小于零,它应该将其设置为零。代码如下所示:
Private Sub Worksheet_Change(ByVal Target As Range)
'Debug.Print Target.Address
If Target.Column = 6 Then
For Each Cell In Target.SpecialCells(xlCellTypeConstants, 3)
If Cell.Value < 0 Then
Cell.Value = 0
End If
Next
End If
End Sub
现在发生的情况是,当我更改第 6 列中任何单元格的值时,sheet 中包含小于零的数字的每个单元格 也 更改为零。
我在想为 Worksheet_Change
事件处理程序创建的 "Target" 对象将仅包含更改的 cell/cells,因此我的代码只会更改单元格的值首先被修改并触发了事件。
我试图通过使用 Debug.Print
输出对象的地址来帮助自己。它打印出 sheet 中每个单元格的地址,其值小于零,因此我多次假设处理程序 运行。
我实际上找到了问题本身的解决方法,但我的问题是:我是如何在使用 Worksheet_Change 事件时失败的?将来我该怎么做才能避免此类问题?
有效(已更新)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim c As Range
For Each c In Target
If c.Column = 6 Then If IsNumeric(c) Then If c < 0 Then c = 0
Next c
End Sub
请学习并使用 OPTION EXPLICIT
!
编辑 1: 使用评论中建议的错误修复更新了代码
编辑 2: 更新了带有错误处理的代码以处理数组公式
回答你的问题
[1] how did I fail in using the Worksheet_Change event and [2] what can I do in the future to not have such problems?
- 从技术上讲你没有
- 对于此类问题没有任何帮助,尽管以下规则通常有帮助
你对Target
对象的理解是正确的。您的代码失败,因为 SpecialCells
不喜欢对单个单元格进行操作。给它一个,它会扩展到 整个 sheet!给它任何其他东西,它工作得很好。
您的 Debug.Print
显示所有单元格的原因是每次您的代码更改单元格时,另一个 更改事件被触发。幸运的是,第二个找到了一个零,因此它不会触发 另一个。以下一般规则应该有助于避免很多问题,但不是这个特定的问题:
- 始终用
Application.EnableEvents
. 将更改工作簿任何部分的事件处理程序中的任何代码括起来
要修复代码使其正常工作,只需删除 SpecialCells
方法调用即可。由于您使用的是 Cell.Value
而不是强烈推荐的 Cell.Value2
(请参阅 ),因此 VBA 隐式类型会为您将格式化为文本的数字转换为实际数字。因此,该代码适用于数字和文本值。
代码:
Private Sub Worksheet_Change(ByVal Target As Range)
'Debug.Print Target.Address;
Application.EnableEvents = False
For Each Cell In Target '.SpecialCells(xlCellTypeConstants, 3)
If Cell.Column = 6 And Cell.Value < 0 Then
On Error GoTo Error:
Cell.Value = 0
On Error GoTo 0
End If
Next
GoTo ExitSub:
Error:
If Err.Number = 1004 Then ' 1004 -> "You cannot change part of an array."
'Application.Undo ' Uncomment to disallow array entering a negative value formula into/across column 6
MsgBox "A cell could not be zeroed as" & vbCr & "it is part of an array formula.", vbExclamation, "Microsoft Office Excel"
On Error GoTo 0
Else
On Error GoTo 0
Resume
End If
ExitSub:
Application.EnableEvents = True
End Sub
备注:
- 更新 1:代码现在可以正确处理多单元更改。
- 更新 2:代码现在捕获错误 1004 以处理输入数组公式。它可以允许输入数组公式导致第 6 列中出现负值,或者完全停止输入。
我来这里是为了寻找一种方法来停止我的工作sheet 从 "flashing" 因为它 运行 代码格式化列和行,因为用户在 sheet,包括过滤器和排序。
此外,根据对 OP 问题的官方回答,如果您试图控制 Worksheet_Change()
事件完全不触发 (它仍会触发,但您可以绕过它),例如,在您希望用户更改数据但不更改数据周围区域(例如作为 VBA 系统一部分的字段或标签)的情况下,我使用 Target.Row
元素确定我的极限。与 Target.Column
相结合,您可以专注于用户可以自由控制的特定单元格。
即
Dim myTopLimit AS Integer
myTopLimit = 6
etc..etc
if Target.Row < myTopLimit and Target.Row > myBottomLimit and Target.Column < myLeftLimit and Target.Column > myRightLimit then
.... code to allow WorkSheet_Change() to do somthing
else
.... code to force WorkSheet_Change() to drop through or no code
End If
我是一名 Excel-VBA 新手,我正在尝试编写一小段代码,该代码由更改作品中单元格值的人触发sheet。如果 changed 单元格的值小于零,它应该将其设置为零。代码如下所示:
Private Sub Worksheet_Change(ByVal Target As Range)
'Debug.Print Target.Address
If Target.Column = 6 Then
For Each Cell In Target.SpecialCells(xlCellTypeConstants, 3)
If Cell.Value < 0 Then
Cell.Value = 0
End If
Next
End If
End Sub
现在发生的情况是,当我更改第 6 列中任何单元格的值时,sheet 中包含小于零的数字的每个单元格 也 更改为零。
我在想为 Worksheet_Change
事件处理程序创建的 "Target" 对象将仅包含更改的 cell/cells,因此我的代码只会更改单元格的值首先被修改并触发了事件。
我试图通过使用 Debug.Print
输出对象的地址来帮助自己。它打印出 sheet 中每个单元格的地址,其值小于零,因此我多次假设处理程序 运行。
我实际上找到了问题本身的解决方法,但我的问题是:我是如何在使用 Worksheet_Change 事件时失败的?将来我该怎么做才能避免此类问题?
有效(已更新)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim c As Range
For Each c In Target
If c.Column = 6 Then If IsNumeric(c) Then If c < 0 Then c = 0
Next c
End Sub
请学习并使用 OPTION EXPLICIT
!
编辑 1: 使用评论中建议的错误修复更新了代码
编辑 2: 更新了带有错误处理的代码以处理数组公式
回答你的问题
[1] how did I fail in using the Worksheet_Change event and [2] what can I do in the future to not have such problems?
- 从技术上讲你没有
- 对于此类问题没有任何帮助,尽管以下规则通常有帮助
你对Target
对象的理解是正确的。您的代码失败,因为 SpecialCells
不喜欢对单个单元格进行操作。给它一个,它会扩展到 整个 sheet!给它任何其他东西,它工作得很好。
您的 Debug.Print
显示所有单元格的原因是每次您的代码更改单元格时,另一个 更改事件被触发。幸运的是,第二个找到了一个零,因此它不会触发 另一个。以下一般规则应该有助于避免很多问题,但不是这个特定的问题:
- 始终用
Application.EnableEvents
. 将更改工作簿任何部分的事件处理程序中的任何代码括起来
要修复代码使其正常工作,只需删除 SpecialCells
方法调用即可。由于您使用的是 Cell.Value
而不是强烈推荐的 Cell.Value2
(请参阅
代码:
Private Sub Worksheet_Change(ByVal Target As Range)
'Debug.Print Target.Address;
Application.EnableEvents = False
For Each Cell In Target '.SpecialCells(xlCellTypeConstants, 3)
If Cell.Column = 6 And Cell.Value < 0 Then
On Error GoTo Error:
Cell.Value = 0
On Error GoTo 0
End If
Next
GoTo ExitSub:
Error:
If Err.Number = 1004 Then ' 1004 -> "You cannot change part of an array."
'Application.Undo ' Uncomment to disallow array entering a negative value formula into/across column 6
MsgBox "A cell could not be zeroed as" & vbCr & "it is part of an array formula.", vbExclamation, "Microsoft Office Excel"
On Error GoTo 0
Else
On Error GoTo 0
Resume
End If
ExitSub:
Application.EnableEvents = True
End Sub
备注:
- 更新 1:代码现在可以正确处理多单元更改。
- 更新 2:代码现在捕获错误 1004 以处理输入数组公式。它可以允许输入数组公式导致第 6 列中出现负值,或者完全停止输入。
我来这里是为了寻找一种方法来停止我的工作sheet 从 "flashing" 因为它 运行 代码格式化列和行,因为用户在 sheet,包括过滤器和排序。
此外,根据对 OP 问题的官方回答,如果您试图控制 Worksheet_Change()
事件完全不触发 (它仍会触发,但您可以绕过它),例如,在您希望用户更改数据但不更改数据周围区域(例如作为 VBA 系统一部分的字段或标签)的情况下,我使用 Target.Row
元素确定我的极限。与 Target.Column
相结合,您可以专注于用户可以自由控制的特定单元格。
即
Dim myTopLimit AS Integer
myTopLimit = 6
etc..etc
if Target.Row < myTopLimit and Target.Row > myBottomLimit and Target.Column < myLeftLimit and Target.Column > myRightLimit then
.... code to allow WorkSheet_Change() to do somthing
else
.... code to force WorkSheet_Change() to drop through or no code
End If