Results 1 to 19 of 19

Thread: Help with code to copy cell value before change event

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #10
    Administrator VBAX Master georgiboy's Avatar
    Joined
    Mar 2008
    Location
    Kent, England
    Posts
    1,305
    Location
    Right, now I am not tipsy, I will show you an example of what I was "TRYING" to explain yesterday.

    In the attached file I have included a sheet named "UNDO", this sheet can be hidden, I have left it visible so you can see what is going on. I have added code to @p45cal's code from post 2, this can be found in the "Sheet1" module & below. The "UNDO" macro I have created has been set to run with CTRL+U (this can be removed if required), I have also added a button to the sheet "Sheet1" that will fire the "UNDO" macro.

    Code in the attached file is as below:

    ThisWorkbook module:
    Option Explicit
    Private Sub Workbook_Open()
        ' Code from: georgiboy - www.vbaexpress.com - 06/12/2023    
        Dim endRow As Long
        
        With Sheets("UNDO") ' all code below that starts with a full stop (period in USA) will reference the UNDO sheet
            endRow = .Cells(Rows.Count, 1).End(xlUp).Row ' set end row of the UNDO sheet
            If endRow > 1 Then ' check if endRow is the header row, if it is then don't bother clearing the UNDO sheet
                .Range("A2:D" & endRow).ClearContents ' clear contents for every cell with data under the headings of the UNDO sheet
            End If
        End With
    End Sub
    Sheet1 module:
    Option Explicit
    Dim i As Long
    Private Sub Worksheet_Change(ByVal Target As Range)
        ' Code from: p45cal - www.vbaexpress.com - 03/12/2023
        ' Edited by: georgiboy - www.vbaexpress.com - 06/12/2023
        Dim rngToProcess As Range, sNewValue, sOldValue
        Dim rCell As Range, nr As Long ' added by georgiboy
        
        Set rngToProcess = Intersect(Target, Range("C5:C14")) ' create a range from cells edited
        If Not rngToProcess Is Nothing Then ' check if the above range is empty
            Application.EnableEvents = False ' switch off events so there is not an infinite loop
            sNewValue = Target.Value ' get the value that was just entered
            sOldValue = Target.Offset(, 1).Value ' get the previous value, added by georgiboy
            Application.UNDO ' undo your last entry
            Target.Offset(, 1).Value = Target.Value ' write the previous value to the cell to the right of target
            '*'*'*' below added by georgiboy
            i = i + 1 ' increment the instance, used for the UNDO sub
            For Each rCell In rngToProcess ' loop through the cells in the target range
                With Sheets("UNDO") ' all code below that starts with a full stop (period in USA) will reference the UNDO sheet
                    nr = .Cells(Rows.Count, 1).End(xlUp).Row + 1 ' get the next blank ro of the UNDO sheet
                    .Range("A" & nr) = i ' write the instance number to the UNDO sheet
                    .Range("B" & nr) = rCell.Address ' write the target address to the UNDO sheet
                    .Range("C" & nr) = rCell.Offset(, 1).Value ' write what was the current value to the UNDO sheet
                    .Range("D" & nr) = sOldValue ' write the existing previous value to the UNDO sheet
                End With
            Next rCell
            '*'*'*' above added by georgiboy
            Target.Value = sNewValue ' write back the latest value you entered
            Application.EnableEvents = True ' switch events back on
        End If
    End Sub
    Module 1:
    Option Explicit
    Sub UNDO()
        ' Code from: georgiboy - www.vbaexpress.com - 06/12/2023
        Dim wsU As Worksheet, ws1 As Worksheet
        Dim x As Long, wsUend As Long, inst As Long
        Dim rCell As Range
        
        Application.EnableEvents = False ' switch off events so that the code below does not trigger the Worksheet_Change event
        Set wsU = Sheets("UNDO") ' the hidden sheet named UNDO
        Set ws1 = Sheets("Sheet1") ' the sheet that will be undone
        wsUend = wsU.Cells(Rows.Count, 1).End(xlUp).Row ' end row of sheet UNDO
        On Error GoTo JumpOut ' if the next line of code produces an error then it will go to JumpOut at the bottom of this sub
            inst = wsU.Range("A" & wsUend).Value ' latest instance that was added to the UNDO sheet
        On Error GoTo 0 ' switch error state back on
        
        For x = wsUend To 2 Step -1 ' loop backwards through the UNDO sheet
            If wsU.Range("A" & x) = inst Then ' check if the current row on UNDO sheet was the lates instance
                Set rCell = ws1.Range(wsU.Range("B" & x)) ' create a reference range to the cell on ws1
                rCell.Value = wsU.Range("C" & x).Value ' write the previous value back to ws1
                rCell.Offset(, 1) = wsU.Range("D" & x).Value ' write the previous previous value back to ws1
                wsU.Range("A" & x & ":D" & x).ClearContents ' empty the row from the UNDO sheet, this allows you to have more undo's
            Else
                Exit For ' jump out as was not the last instance
            End If
        Next x
        Application.EnableEvents = True ' switch events back on
        Exit Sub
    JumpOut:
        Application.EnableEvents = True ' switch events back on
        MsgBox "Nothing to undo", vbInformation, "UNDO"
    End Sub
    It looks like a lot of code but most of it is my annotation to try and help you understand what is going on - line by line.

    Hope this helps
    Attached Files Attached Files
    Last edited by georgiboy; 12-06-2023 at 05:45 AM. Reason: typo
    Click here for a guide on how to add code tags
    Click here for a guide on how to mark a thread as solved
    Click here for a guide on how to upload a file with your post

    Excel 365, Version 2408, Build 17928.20080

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •