我是一名Excel-VBA新手,我正在尝试编写一段代码,这段代码由某人更改工作表中单元格的值触发。如果已更改单元格的值小于零,则应将其设置为零。代码如下所示:
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列中任何单元格的值时,包含数字小于零的工作表中的每个单元格也更改为零。
我在想,为Worksheet_Change
事件处理程序创建的“目标”对象只包含已更改的单元格/单元格,因此我的代码只会更改已修改并触发的单元格的值事件发生在第一位。
我尝试使用Debug.Print
输出对象的地址来帮助自己。它打印出工作表中每个单元格的地址,其值小于零,所以我假设处理程序运行了几次。
我实际上找到了问题本身的解决方法,但我的问题是:我如何使用Worksheet_Change事件失败,以及我将来可以做些什么来解决这个问题?
答案 0 :(得分:0)
这有效(已更新)
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 :(得分:0)
编辑1:更新了代码中包含错误修复的代码
编辑2:更新了错误处理代码以处理数组公式
回答你的问题
[1] 我是如何使用Worksheet_Change事件失败的? [2] 我将来可以做些什么来解决这些问题呢?
您对Target
对象的理解是正确的。您的代码失败,因为SpecialCells
不喜欢单个单元格进行操作。给它一个,然后将其扩展为 整个 表格!给它任何其他东西,它工作得很好。
Debug.Print
显示所有单元格的原因是,每次代码更改单元格时,都会触发 另一个 更改事件。幸运的是,第二个找到零,所以它不会触发另一个。以下一般规则应该有助于避免很多问题,而不是这个问题:
Application.EnableEvents
更改工作簿的任何部分。要修复代码以使其正常工作,只需删除SpecialCells
方法调用即可。由于您使用Cell.Value
而不是强烈推荐的Cell.Value2
(请参阅here),因此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列中产生负值,或者完全停止输入。
答案 2 :(得分:0)
我来这里是为了寻找一种方法来阻止我的工作表“闪烁”,因为用户更改了工作表中任何地方的数据(包括“过滤器”和“排序”),该代码都会运行以格式化列和行的格式。
除了对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