【问题标题】:Excel detecting and keeping track of (value) changes in any worksheetExcel 检测并跟踪任何工作表中的(值)变化
【发布时间】:2016-01-26 15:54:40
【问题描述】:

我设法编写了一个代码来检测任何工作表中特定单元格的值变化,但我一直在努力构建检测和跟踪范围(值)变化的东西。

例如,如果用户决定复制和粘贴某个范围的数据(比如说超过 1 个单元格),它不会被宏捕获。用户选择一个范围,然后在仍然选择范围时手动将值输入到每个单元格中也是如此。

我当前的代码由 2 个宏构成,第一个在工作表选择发生更改时运行,并将 target.value 存储到以前的 value 变量中。第二个宏在工作表发生更改时运行,并测试目标值是否与前一个不同,如果是,则通知用户已发生的更改。

【问题讨论】:

  • 您应该编辑您的帖子并添加您的代码或您迄今为止尝试过的内容,否则您可能无法获得帮助......
  • 查看问题右下方的“相关”问题 - 这里有很多以前的类似问题(有答案)

标签: excel macros vba


【解决方案1】:

好的,我在这里看不到任何涵盖整个事情的东西,所以这是一个粗略的尝试。

它将处理单个或多个单元格更新(您可以设置一些您不想超过的限制...)

它不会处理多区域(非连续)范围更新,但可以扩展来处理。

您可能还应该添加一些错误处理。

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim Where As String, OldValue As Variant, NewValue As Variant
    Dim r As Long, c As Long

    Dim rngTrack As Range

    Application.EnableEvents = False
    Where = Target.Address
    NewValue = Target.Value
    Application.Undo
    OldValue = Target.Value 'get the previous values
    Target.Value = NewValue
    Application.EnableEvents = True

    Set rngTrack = Sheets("Tracking").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)

    'multi-cell ranges are different from single-cell ranges
    If Target.Cells.CountLarge > 1 And Target.Cells.CountLarge < 1000 Then
        'multi-cell: treat as arrays
        For r = 1 To UBound(OldValue, 1)
        For c = 1 To UBound(OldValue, 2)
            If OldValue(r, c) <> NewValue(r, c) Then
                rngTrack.Resize(1, 3).Value = _
                  Array(Target.Cells(r, c).Address, OldValue(r, c), NewValue(r, c))
                Set rngTrack = rngTrack.Offset(1, 0)
            End If
        Next c
        Next r
    Else
        'single-cell: not an array
        If OldValue <> NewValue Then
            rngTrack.Resize(1, 3).Value = _
              Array(Target.Cells(r, c).Address, OldValue, NewValue)
            Set rngTrack = rngTrack.Offset(1, 0)
        End If
    End If

End Sub

获取先前值的“撤消”部分来自 Gary's Student's answer here: Using VBA how do I detect when any value in a worksheet changes?

【讨论】:

  • 感谢您的回答。这正是我一直在寻找的。有什么方法可以使这项工作在更高的水平上进行 - 例如工作簿级别?非常感谢。亲切的问候,Domen
  • 工作簿级别有一个Workbook_SheetChange 事件。您可以在那里使用非常相似的代码:只需要添加对工作表名称的跟踪,并排除您不想跟踪的任何工作表(例如跟踪表本身)。
  • 有什么办法可以克服在 application.undo 代码通过时发生的选择返回。就像我在一个空白单元格中写入“5”然后单击另一个单元格一样,(application.undo)会将我的选择返回到我更改值的单元格,所以返回到我写 5 的单元格。有什么办法防止这种情况发生?我提前感谢您分享的任何智慧。亲切的问候
  • 在执行撤消之前,存储当前选择:然后您可以在撤消后恢复它
【解决方案2】:

这个 subs 会为你工作,但你只是在每张表中手动实现代码。只需要复制粘贴。请参阅下面的截图,这是一张Sheet1

(1) 声明一个公共变量。

Public ChangeTrac As Variant

(2) 在 Worksheet_SelectionChange 事件中编写以下代码

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    ChangeTrac = Target.Value
End Sub

(3) 在 Worksheet_Change 事件中编写以下代码

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Application.Intersect(Target, Cells()) Is Nothing Then
        If ChangeTrac <> Target.Value Then
            MsgBox "Value changed to Sheet1 " & Target.Address & " cell."
            Range(Target.Address).Select
        End If
    End If
End Sub

然后通过更改任何单元格中的数据进行测试。如果任何单元格值发生更改,它会提示。

【讨论】:

  • 它实际上返回了一个错误。 (运行时错误'13'类型不匹配)。我遇到的问题是检测发生了什么。什么改变了我的问题,所以我必须将以前的值存储在某个地方。似乎 excel 在将值存储到范围时存在问题。
  • 如果我复制我的代码并拍摄自己的视频以向您展示我正在搜索的内容会有帮助吗?
  • 您最好共享一个示例工作簿。只需将示例文件上传到谷歌驱动器并在此处分享链接。
  • onedrive.live.com/… 如您所见,此代码跟踪单个单元格的更改。但是,如果我决定一次更改“一个区域”或多个单元格(例如通过复制粘贴,...),它不会检测和记录。
  • 代码如下: Dim PreviousValue Public Sub Worksheet_Change(ByVal Target As Range) logDate = Format(Now(), "dd/mmm/yyyy") logTime = Format(Now(), " hh : mm: ss") On Error Resume Next If ActiveSheet.UsedRange.Address = "$A$1" And Range("A1") = "" Then Else If Target.Value PreviousValue Then Sheets("Audit").Cells (65000, 1).End(xlUp).Offset(1, 0).Value = _ logDate & " " & logTime & ": " & Environ("用户名") & " 更改单元格 " & Target.Address & _ "从 " & PreviousValue & " 到 " & Target.Value & " in " & ActiveSheet.Name End If End If End If End Sub
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 2013-03-21
相关资源
最近更新 更多