Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vba MS Excel工作表更改事件-保留旧单元格值与新值的记录_Vba_Excel - Fatal编程技术网

Vba MS Excel工作表更改事件-保留旧单元格值与新值的记录

Vba MS Excel工作表更改事件-保留旧单元格值与新值的记录,vba,excel,Vba,Excel,我是这个论坛的新手,但由于我当前角色的VBA要求,我在过去几个月里一直在积累编码经验。今天的问题让我浏览了很多网站(还有我的Excel VBA for Dummies书籍),但我还没有完全解决它 我正试图在Excel中为我们公司的风险登记册制作一个审计跟踪文件。其想法是,一旦建立了风险登记簿,任何更改都将创建一个审计跟踪(在单独的选项卡上),其中显示旧记录和新记录 我已经使用变更事件处理程序编写了代码。我希望在每次发生更改时启动宏,并执行以下操作: 1。引用旧单元格值(用户刚刚覆盖的值) 2.跳

我是这个论坛的新手,但由于我当前角色的VBA要求,我在过去几个月里一直在积累编码经验。今天的问题让我浏览了很多网站(还有我的Excel VBA for Dummies书籍),但我还没有完全解决它

我正试图在Excel中为我们公司的风险登记册制作一个审计跟踪文件。其想法是,一旦建立了风险登记簿,任何更改都将创建一个审计跟踪(在单独的选项卡上),其中显示旧记录和新记录

我已经使用变更事件处理程序编写了代码。我希望在每次发生更改时启动宏,并执行以下操作:
1。引用旧单元格值(用户刚刚覆盖的值)
2.跳转到“审计跟踪”选项卡并粘贴完整风险记录的两份副本-每个风险记录是一行数据,占据17列
3.在这17列的第一个副本中,找出编辑了哪一列,并将此单元格替换为旧单元格值(在步骤1中捕获)
4.插入时间戳
5.使用条件格式突出显示已更改的记录[代码中不需要此函数,因为我已在电子表格中设置了它]
6.跳回用户刚刚编辑的单元格(在“风险登记”选项卡上)

我已经管理了步骤1、2和4-7,但是我在让代码将“旧单元格值”输入到“审核跟踪程序”选项卡的正确位置时遇到了问题。如果我手动定义要粘贴到其中的单元格范围,我可以将其粘贴到其中,但我似乎无法使其成为动态的,以便它自动识别用户正在更改的字段,并确保在审核跟踪中修改相同的字段

如果您能深入了解“PasteRange.Value=工作表(“风险登记簿”).Range(“oldValuePaste”)行不起作用的原因,我将不胜感激

我的代码如下:

    Dim oldValue As Variant
    Dim LastRow As Long
    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
        Application.ScreenUpdating = False
            If Not Intersect(Target, Range("b13:r13")) Is Nothing Then
                oldValue = Target.Value
            End If
        Application.ScreenUpdating = True
    End Sub

    Private Sub Worksheet_Change(ByVal Target As Range)
        Application.ScreenUpdating = False

    If Not Intersect(Target, Range("b13:r14")) Is Nothing Then
        If Target.Value <> oldValue Then
            'MsgBox "You just changed " & Target.Address
             Cells(65, 5).Value = oldValue       'this cell is a named range called: OldValuePaste
             Cells(66, 5).Value = Target.row     'this cell is a named range called: OldValueRowNumber
             Cells(67, 5).Value = Target.Column  'this cell is a named range called: OldValueColumnNumber

            Range(Cells(Target.row, 2), Cells(Target.row, 18)).Copy
            'Cells(70, 2).PasteSpecial xlPasteValues

            Call Paste_on_AuditSheet
            Sheets("Risk Register").Activate
            Target.Select
            Application.CutCopyMode = False

        End If
    End If

Application.ScreenUpdating = True
End Sub

_____________________________________________________________________________________________________

Sub Paste_on_AuditSheet()
Application.ScreenUpdating = False
Dim LastRow As Long
Dim ColNum As Long
Dim PasteRange As Range
ColNum = OldValueColumnNumber

    Sheets("Audit trail").Select
    'MsgBox "Activated " & ActiveSheet.Name

        'Find the last used row in a Column: column B in this example
        With ActiveSheet
            LastRow = .Cells(.Rows.Count, "B").End(xlUp).row
        End With

    Set PasteRange = Cells(LastRow, ColNum)

'The following two lines bring in the new data and paste into old record and new record sections:
        Cells(LastRow + 1, 2).PasteSpecial xlPasteValues
        Cells(LastRow + 1, 20).PasteSpecial xlPasteValues

'Then this line goes back over the piece just pasted in and changes one cell in "old record" section to what it was prior to the edit:
        'PasteRange.Value = Worksheets("Risk Register").Range("oldValuePaste")
'Above line of code is not working, but can get it to do the right thing using this code (although it's not dynamic):
        Range("E3").Value = Worksheets("Risk Register").Range("oldValuePaste")

'Add a time stamp:
    Cells(LastRow + 1, 1) = Now

Application.ScreenUpdating = True
End Sub
Dim oldValue作为变量
最后一排一样长
专用子工作表\u选择更改(ByVal目标作为范围)
Application.ScreenUpdating=False
如果不相交(目标,范围(“b13:r13”))则为零
oldValue=Target.Value
如果结束
Application.ScreenUpdating=True
端接头
私有子工作表_更改(ByVal目标作为范围)
Application.ScreenUpdating=False
如果不相交(目标,范围(“b13:r14”))则为零
如果目标值为oldValue,则
'MsgBox“您刚刚更改”&目标地址
单元格(65,5)。Value=oldValue'此单元格是一个命名区域,名为:OldValuePaste
单元格(66,5).Value=Target.row'此单元格是一个命名范围,名为:OldValueRowNumber
单元格(67,5).Value=Target.Column'此单元格是一个命名范围,名为:OldValueColumnNumber
范围(单元格(Target.row,2),单元格(Target.row,18))。复制
'单元格(70,2).粘贴特殊XLPaste值
在审核表上调用粘贴
表格(“风险登记簿”)。激活
目标。选择
Application.CutCopyMode=False
如果结束
如果结束
Application.ScreenUpdating=True
端接头
_____________________________________________________________________________________________________
子粘贴在审核表()上
Application.ScreenUpdating=False
最后一排一样长
淡色秋千一样长
将范围设置为范围
ColNum=OldValueColumnNumber
工作表(“审计跟踪”)。选择
“MsgBox”已激活(&ActiveSheet.Name)
'查找列中最后使用的行:本例中的B列
使用ActiveSheet
LastRow=.Cells(.Rows.Count,“B”).End(xlUp).row
以
设置粘贴范围=单元格(LastRow,ColNum)
'以下两行引入新数据并粘贴到旧记录和新记录部分:
单元格(LastRow+1,2).粘贴特殊XLPaste值
单元格(LastRow+1,20).粘贴特殊XLPaste值
'然后这一行返回刚刚粘贴的片段,并将“旧记录”部分中的一个单元格更改为编辑之前的单元格:
'PasteRange.Value=工作表(“风险登记簿”).Range(“oldValuePaste”)
'上面的代码行不起作用,但可以使用此代码让它做正确的事情(尽管它不是动态的):
范围(“E3”).值=工作表(“风险登记簿”).范围(“旧值粘贴”)
'添加时间戳:
单元格(最后一行+1,1)=现在
Application.ScreenUpdating=True
端接头
最后一点——尽管我反复使用Application.screenUpdated命令,我仍然会看到一些屏幕闪烁——你知道为什么吗


提前感谢您的帮助

在查看您的代码时,我看到了一些我认为不会像您想象的那样工作的东西,并且认识到您的代码可以变得更简单,只需从
工作表\u Change
事件调用即可

下面是重构代码,如果您有问题,请告诉我:

Private Sub Worksheet_Change(ByVal Target As Range)

If Not Intersect(Target, Range("b13:r14")) Is Nothing Then

    'get oldValue
    Dim sNewVal As String, sOldVal As String
    sNewValue = Target.Value 'store current or "new" value since this is what is stored after the cell change takes place
    With Application
        .EnableEvents = False 'turns off event firing so the code will not go into endless loop
        .Undo 'undo the change (to store old value in next line)
    End With
    sOldValue = Target.Value 'store old value
    Target.Value = sNewValue 'reset new value

    Dim lCol As Long
    lCol = Target.Column 'which column of data was changed 

    'assumes columns A-Q are 17 columns
    Me.Range(Me.Cells(Target.Row, 1), Me.Cells(Target.Row, 17)).Copy

    With Sheets("Audit Trail")

        Dim lRow As Long
        lRow = .Range("B" & .Rows.Count).End(xlUp).Offset(1).Row

        .Range("B" & lRow).PasteSpecial xlPasteValues
        .Range("B" & lRow + 1).PasteSpecial xlPasteValues
        .Range("A" & lRow).Value = Now

        .Cells(lRow, lCol + 1).Value = sOldValue 'store old value in first pasted line ... add 1 since starting from column B

    End With

End If

Application.EnableEvents = True

End Sub

屏幕更新
上快速从
审核表粘贴
子项中删除
应用程序。屏幕更新=True
。它会在
工作表
事件中的其余代码中重新启用。如果目标不是单个单元格,则会出现问题,而且,当目标是多个单元,但只有其中一些单元在B13:R14中时(如果它与>1个单元一起工作),它仍然会处理整个
目标
范围,而不仅仅是B13:R14中的部分。感谢您指出@TimWilliams。我会让奥普告诉我他是否需要对这些问题进行调整。了不起的努力@ScottHoltzman-非常感谢你的帮助。我采纳了你的建议,并用它简化了我的代码。关键的是,目标值字符串和lCol=Target.Column维度一起工作。我做了一些小的修改以适应: