通过编辑检测是否实际更改了单元格值

时间:2012-08-21 23:21:54

标签: excel vba excel-vba

当一个单元格值发生变化时,

Worksheet_Change会触发(这就是我想要的),但是当你输入一个单元格时它也会触发,就像编辑它一样但是实际上并没有改变单元格的值(这是我不想发生什么)。

假设我想为值已更改的单元格添加阴影。所以我编码:

Private Sub Worksheet_Change(ByVal Target As Range)
    Target.Interior.ColorIndex = 36
End Sub

现在测试我的工作:更改单元格A1并突出显示单元格。这是理想的行为。到现在为止还挺好。然后,双击B1但不更改其中的值,然后单击C1。你会注意到B1被突出显示!这不是理想的行为。

我是否必须完成此处讨论的捕获旧值的方法,然后在突出显示单元格之前将旧旧比较?我当然希望有一些我不知道的东西。

6 个答案:

答案 0 :(得分:4)

我建议在另一张表格中自动维护工作表的“镜像副本”,以便与更改的单元格值进行比较。

@brettdj和@JohnLBevan基本上建议做同样的事情,但他们分别在评论或字典中存储单元格值(确实为这些想法+1)。但我的感觉是,在概念上更简单地备份单元格中的单元格,而不是其他对象(尤其是您或用户可能希望用于其他目的的注释)。

所以,假设我有Sheet1其用户可能更改的单元格。我创建了另一个名为Sheet1_Mirror的工作表(您可以在Workbook_Open创建,如果您愿意,可以设置为隐藏 - 由您决定)。首先,Sheet1_Mirror的内容与Sheet1的内容相同(同样,您可以在Workbook_Open强制执行此操作)。

每次触发Sheet1 Worksheet_Change时,代码都会检查Sheet1中“已更改”单元格的值是否与Sheet1_Mirror中的值有所不同。如果是这样,它会执行您想要的操作并更新镜像表。如果没有,那就没有了。

这应该让你走上正轨:

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim r As Range
    For Each r In Target.Cells
        'Has the value actually changed?
        If r.Value <> Sheet1_Mirror.Range(r.Address).Value Then
            'Yes it has. Do whatever needs to be done.
            MsgBox "Value of cell " & r.Address & " was changed. " & vbCrLf _
                & "Was: " & vbTab & Sheet1_Mirror.Range(r.Address).Value & vbCrLf _
                & "Is now: " & vbTab & r.Value
            'Mirror this new value.
            Sheet1_Mirror.Range(r.Address).Value = r.Value
        Else
            'It hasn't really changed. Do nothing.
        End If
    Next
End Sub

答案 1 :(得分:2)

试试这段代码。输入范围时,它会将原始单元格值存储在字典对象中。触发工作表更改时,它会将存储的值与实际值进行比较,并突出显示所有更改 注意:提高效率参考微软脚本运行时间&amp;将 As Object 替换为 As Scripting.Dictionary ,将 CreateObject(“Scripting.Dictionary”)替换为 New Scripting.Dictionary

Option Explicit

Private previousRange As Object 'reference microsoft scripting runtime & use scripting.dictionary for better performance
                                'I've gone with late binding to avoid references from confusing the example


Private Sub Worksheet_Change(ByVal Target As Range)

    Dim cell As Variant

    For Each cell In Target
        If previousRange.Exists(cell.Address) Then
            If previousRange.Item(cell.Address) <> cell.FormulaR1C1 Then
                cell.Interior.ColorIndex = 36
            End If
        End If
    Next

End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    Dim cell As Variant

    Set previousRange = Nothing 'not really needed but I like to kill off old references
    Set previousRange = CreateObject("Scripting.Dictionary")

    For Each cell In Target.Cells
        previousRange.Add cell.Address, cell.FormulaR1C1
    Next

End Sub

PS。任何更新单元格的vba代码(即使只是颜色)都会阻止excel的撤消功能!要解决此问题,您可以重新编程撤消功能,但它可能会占用大量内存。示例解决方案:http://www.jkp-ads.com/Articles/UndoWithVBA00.asp / http://www.j-walk.com/ss/excel/tips/tip23.htm

答案 2 :(得分:2)

此代码使用“注释”来存储先前值(请注意,如果您确实需要注释用于其他目的,此方法将删除它们)

  1. 没有值的单元格将颜色重置为xlNone
  2. 键入单元格的初始值为蓝色(ColorIndex 34)
  3. 如果值已更改,则单元格将从蓝色变为黄色
  4. enter image description here

    普通模块 - 关闭评论显示

        Sub SetCom()
          Application.DisplayCommentIndicator = xlNoIndicator
        End Sub
    

    用于捕获更改的工作表代码

        Private Sub Worksheet_Change(ByVal Target As Range)
        Dim rng1 As Range
        Dim shCmt As Comment
        For Each rng1 In Target.Cells
    
        If Len(rng1.Value) = 0 Then
        rng1.Interior.ColorIndex = xlNone
        On Error Resume Next
        rng1.Comment.Delete
        On Error GoTo 0
        Else
    
        On Error Resume Next
        Set shCmt = rng1.Comment
        On Error GoTo 0
    
        If shCmt Is Nothing Then
            Set shCmt = rng1.AddComment
            shCmt.Text Text:=CStr(rng1.Value)
             rng1.Interior.ColorIndex = 34
        Else
            If shCmt.Text <> rng1.Value Then
                rng1.Interior.ColorIndex = 36
                shCmt.Text Text:=CStr(rng1.Value)
            End If
        End If
        End If
        Next
        End Sub
    

答案 3 :(得分:1)

我知道这是一个老线程,但是我有完全相同的问题“更改单元格A1并且单元格突出显示。这就是我所期望的。双击B1但不要更改那里的值然后点击C1。你会注意到B1被突出显示!“

我不想突出显示一个单元格,如果它只是双重单击而没有内部值。

我以简单的方式解决了。也许它将来有助于某人。

我刚刚在活动开始时添加了这个:

 If Target.Value = "" Then
      Exit Sub
 End If

答案 4 :(得分:0)

我发现另一个线程提供了捕获旧值的方法,因此您可以将其与“新”值进行比较,如果是,则直接让它什么都不做。

How do I get the old value of a changed cell in Excel VBA?

答案 5 :(得分:-1)

您可以发送代码吗?
如果Target.Value =“”然后 退出子 万一 不能为我解决问题。