关于Excel中VBA的两个问题:1.返回列名并返回单元格的旧值

kzipqqlq  于 2022-12-30  发布在  其他
关注(0)|答案(2)|浏览(280)

我正在创建一个包含另一个工作表的logdetails的电子表格,其中的信息不断变化,我必须跟踪这些变化。我能够将部分变化记录到logdetails电子表格中

而不是列名(基于单元地址和旧值)。
这里是我的VBA代码到目前为止。

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)

If ActiveSheet.Name <> "logdetails" Then

Application.EnableEvents = False

Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = ActiveSheet.Name & "-" & Target.Address(0, 0)
Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 3).Value = Target.Value
Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 4).Value = Environ("username")
Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 5).Value = Now
Sheets("logdetails").Columns("A:H").AutoFit

Application.EnableEvents = True

End If

End Sub
lrl1mhuk

lrl1mhuk1#

首先你需要通过工作簿事件把旧值保存在某个地方。下面的变量lastRng会保存每个活动单元格的值,如果有变化会恢复

Dim lastRng

Private Sub Workbook_Open()
    Set lastRng = ActiveCell
End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    lastRng = Target.Value
End Sub

之后,添加下面两行

Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 1).Value = Target.Address
Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 2).Value = lastRng

我不是很明白你所说的列名是什么意思,但是如果你想要用字母来代替列号或单元格地址,你可以在question中找到很好的解决方案来将一个转换成另一个
总而言之,您的合并代码将如下所示:

Dim lastRng

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If ActiveSheet.Name <> "logdetails" Then

        Application.EnableEvents = False
        
        Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = ActiveSheet.Name & "-" & Target.Address(0, 0)
        Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 1).Value = Target.Address
        Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 2).Value = lastRng
        Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 3).Value = Target.Value
        Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 4).Value = Environ("username")
        Sheets("logdetails").Range("A" & Rows.Count).End(xlUp).Offset(0, 5).Value = Now
        Sheets("logdetails").Columns("A:H").AutoFit
        
        Application.EnableEvents = True

    End If
End Sub

Private Sub Workbook_Open()
    Set lastRng = ActiveCell
End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    lastRng = Target.Value
End Sub
zf9nrax1

zf9nrax12#

工作簿工作表变更:记录多个工作表中的更改

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    Const LogName As String = "logdetails"
    Const DST_COLUMNS_COUNT As Long = 6
    
    On Error GoTo ClearError
    
    If Sh.Name = "logdetails" Then Exit Sub
    If Not TypeOf Sh Is Worksheet Then Exit Sub ' not a worksheet
    
    Dim twsName As String: twsName = Sh.Name
    Dim usName As String: usName = Environ("USERNAME")
    Dim cTime As String: cTime = Now
    
    Dim nDict As Object: Set nDict = DictRangeAddressAndFormulas(Target)
    
    Application.EnableEvents = False
    
    Dim oDict As Object
    Application.Undo
        Set oDict = DictRangeAddressAndFormulas(Target)
    Application.Undo

    Dim drCount As Long, nKey
    
    For Each nKey In nDict.Keys
        drCount = drCount + UBound(nDict(nKey), 1)
    Next nKey

    Dim dData() As Variant: ReDim dData(1 To drCount, 1 To DST_COLUMNS_COUNT)
    
    Dim sr As Long, sc As Long, dr As Long, nString As String, oString As String
    
    For Each nKey In nDict.Keys
        Debug.Print nKey, nDict(nKey)(1, 1), oDict(nKey)(1, 1)
        For sr = 1 To UBound(nDict(nKey), 1)
            For sc = 1 To UBound(nDict(nKey), 2)
                nString = CStr(nDict(nKey)(sr, sc))
                oString = CStr(oDict(nKey)(sr, sc))
                If StrComp(nString, oString, vbBinaryCompare) <> 0 Then
                    dr = dr + 1
                    With Sh.Range(nKey).Cells(sr, sc)
                        dData(dr, 1) = twsName & "-" & .Address(0, 0)
                        dData(dr, 2) = Split(.Address, "$")(1)
                    End With
                    dData(dr, 3) = oDict(nKey)(sr, sc)
                    dData(dr, 4) = nDict(nKey)(sr, sc)
                    dData(dr, 5) = usName
                    dData(dr, 6) = cTime
                End If
            Next sc
        Next sr
    Next nKey
    
    Dim dws As Worksheet: Set dws = Me.Sheets(LogName)
    Dim dlCell As Range: Set dlCell = dws.Cells(dws.Rows.Count, "A").End(xlUp)
    Dim drg As Range: Set drg = dlCell.Offset(1).Resize(dr, DST_COLUMNS_COUNT)
    
    drg.Value = dData
    
    drg.EntireColumn.AutoFit
    
ProcExit:
    On Error Resume Next
        If Not Application.EnableEvents Then Application.EnableEvents = True
    On Error GoTo 0
    Exit Sub
ClearError:
    Debug.Print "Run-time error '" & Err.Number & "':" & vbLf & Err.Description
    Resume ProcExit
End Sub

Function DictRangeAddressAndFormulas( _
    ByVal rg As Range) _
As Object
    Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
    Dim arg As Range
    For Each arg In rg.Areas
        dict(arg.Address) = GetRangeFormulas(arg)
    Next arg
    Set DictRangeAddressAndFormulas = dict
End Function

Function GetRangeFormulas( _
    ByVal rg As Range) _
As Variant
    Dim Data() As Variant
    If rg.Rows.Count * rg.Columns.Count = 1 Then ' one cell
        ReDim Data(1 To 1, 1 To 1): Data(1, 1) = rg.Formula
    Else ' multiple cells
        Data = rg.Formula
    End If
    GetRangeFormulas = Data
End Function

相关问题