Warning before overwriting existing data in VBA - excel

I have the below code that creates a pop-up when new data is pasted into the specified range (A15 : E33). What I would like is when the user attempts to paste data into the range the pop up shows up and if the user selects no the data isn't pasted, preventing accidental overwrite.
Currently when the user selects no all it does is prevent cell B2 from being timestamped.
Thank you in advance for your help
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$15:$E$33" Then
Dim answer As Integer
answer = MsgBox("You are about to overwrite existing data, would you like to continue?", vbQuestion + vbYesNo)
If answer = vbYes Then
Range("B2") = "=NOW()"
Range("B2").Copy
Range("B2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("a15:e33").Select
Else
MsgBox "Cancelled"
End If
End If
End Sub

Your code cannot know about your intention to paste in a specific range...
The above code is an event, being automatically triggered when the pasting has already been done. What you can do is using Application.UnDo:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.address = "$A$15:$E$33" Then
Dim answer As VbMsgBoxResult
answer = MsgBox("You are about to overwrite existing data, would you like to continue?", vbQuestion + vbYesNo)
If answer = vbYes Then
Application.EnableEvents = False 'to avoid the event being triggered again...
Range("B2") = "=NOW()"
Range("B2").Copy
Range("B2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("a15:e33").Select
Application.EnableEvents = True
Else
Application.EnableEvents = False 'to avoid the event being triggered again...
Application.Undo
Application.EnableEvents = True
MsgBox "Cancelled"
End If
End If
End Sub

Related

Hot to solve: VBA Copy Values only 1004 Error?

I have an excel protected sheet that is being used by several users and I've found that they sometimes Copy&Paste info from a different application that Blocks the pasted cells (while changing other formats as well).
The solution that I've found is using a macro in ThisWorkbook that forces the Copy as Value.
As I don't have that much experience in VBA, I've decided to use some available code in the internet.
The problem is that the marco works just fine in my Excel, but not in an older version of Excel (where I need it to work...).
I'm getting the 1004 Error. From what I've read so far I believe this happens because the info in the Clipboard dissappears when I run the macro.
Does anyone know how to solve this?
Below is the code that I'm using:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim UndoString As String, srce As Range
On Error GoTo err_handler
UndoString = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(UndoString, 5) <> "Paste" And UndoString <> "Auto Fill" Then
Exit Sub
End If
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Undo
If UndoString = "Auto Fill" Then
Set srce = Selection
srce.Copy
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.SendKeys "{ESC}"
Union(Target, srce).Select
Else
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
err_handler:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Try this, two lines have been inserted
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim UndoString As String, srce As Range
On Error GoTo err_handler
UndoString = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(UndoString, 5) <> "Paste" And UndoString <> "Auto Fill" Then
Exit Sub
End If
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Undo
If UndoString = "Auto Fill" Then
Set srce = Selection
srce.Copy
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.SendKeys "{ESC}"
Union(Target, srce).Select
Else
Selection.Copy 'This line has been inserted
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False 'This line has been inserted
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
err_handler:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
It looks as though that section of the code (Else etc.) only applies if they used Paste but not AutoFill.
I don't see the merit of using the If block to distinguish between UndoString = "Auto Fill" and any other result, which based on an earlier If block can only include a situation where the last undoable action name started with (or was) Paste. Don't you want to do the same thing to both Auto Fill and Paste?

VBA - Paste Event and undo last action of Paste

I'm trying to make my excel to Paste Values instead of PasteAll by using VBA. But I'm not able to achieve it due to failure of the line :
lastAction = Application.CommandBars("Standard").Controls("&Undo").List(1)
I'm using code as below. Could anyone kindly help me to solve this? please correct my code as well if I'm wrong.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim lastAction As String
Application.ScreenUpdating = False
Application.EnableEvents = False
lastAction = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(lastAction, 5) = "Paste" Then
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Undo
Selection.PasteSpecial Paste:=xlPasteValues
End If
End Sub
After including above code, I understood that this doesn't helps if the content copied was not from Excel. Below code helps to handle the data from both Office Clipboard and Windows Clipboard.
Office Clipboard - Paste as Values
Windows Clipboard - Paste as text
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
'~~> Check if the last action was not a paste nor an autofill
If Left(UndoList, 5) = "Paste" Or UndoList = "Paste special" Then
Application.ScreenUpdating = True
On Error GoTo 0
'~~> Undo the paste that the user did but we are not clearing the
'~~> clipboard so the copied data is still in memory
Application.Undo
'~~> Do a pastespecial to preserve formats
'~~> Handle text data copied from a website
'Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'Target.PasteSpecial Paste:="Text", Operation:=xlNone, SkipBlanks:=False
Call Paste_Event
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
End If
Application.EnableEvents = True
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
Private Sub Paste_Event()
On Error GoTo Paste
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Exit Sub
On Error GoTo 0
Paste:
Selection.PasteSpecial Paste:="Text", Operation:=xlNone, SkipBlanks:=False
Exit Sub
End Sub
Here is the perfect solution which i found
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
'~~> Check if the last action was not a paste nor an autofill
If Left(UndoList, 5) = "Paste" Or UndoList = "Paste special" Then
Application.ScreenUpdating = True
On Error GoTo 0
'~~> Undo the paste that the user did but we are not clearing the
'~~> clipboard so the copied data is still in memory
Application.Undo
'~~> Do a pastespecial to preserve formats
'~~> Handle text data copied from a website
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
End If
Application.EnableEvents = True
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub

2nd change(ByVal target As Range) doesnt work

I have a small puzzle. Im using cells "K6" and "L6" as imputs (for scaning the barcode). When I select cell "K6" and scan the barcode the cell "O6" is becoming from value "0" to value "1" (by formula "=IF(K6>0,1,0)").
Im using cell "O6" (when is grater then "0") as a triger for "Sub (ByVal target As Range)"
This Sub call marco "Nasklad" which copy and paste "K6" value to sheet2 (IN_OUT) column "A" first blank. After it call macro "Clear" which select sheet1 (Sklad) and clear cell "K6".
Whole process working fine, I scan a barcode, code is copied to another sheet and I can scan another code and so on.
Sub worksheet_change(ByVal target As Range)
Set target = Range("O6")
If target.Value > 0 Then
Call Nasklad
End If
End Sub
Sub Nasklad()
Sheets("Sklad").Select
Range("K6").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("IN_OUT").Select
ActiveSheet.Range("A1").End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Call clear
End Sub
Sub clear()
Sheets("Sklad").Select
Range("K6").Select
Selection.ClearContents
End Sub
Now the catch, when I tried duplicate serie of commands for cell "K6" to work with cell "L6", then nothing happedn.
It looks like "Sub worksheet_change2(ByVal target As Range)" is not working. When I imput something to "L6" value in "P6" become "1" (by formula "=IF(L6>0,1,0)" and this time trigger dont run the Sub and I dont know why.
Sub worksheet_change2(ByVal target As Range)
Set target = Range("P6")
If target.Value = 0 Then
Call Vysklad
End If
End Sub
Sub Vysklad()
Sheets("Sklad").Select
Range("L6").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("IN_OUT").Select
ActiveSheet.Range("B1").End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Call clear2
End Sub
Sub clear2()
Sheets("Sklad").Select
Range("L6").Select
Selection.ClearContents
End Sub
Did I miss something?
Thanks for helping
Thank you #BigBen and #urdearboy, this help me and I've changed the Sub worksheet_change(ByVal target As Range) to
Sub worksheet_change(ByVal target As Range)
Set target = Range("O6")
Set target2 = Range("P6")
If target.Value > 0 Then
Call Nasklad
End If
If target2.Value > 0 Then
Call Vysklad
End If
End Sub

Macro to run a specific block of code inside another macro

I have four or five macro's each copying and pasting different subsets of data (all defined as ranges) from one tab to another tab. Occasionally someone may need to change some of the pasted data or rather portions of this.
Each of these macro's contains defined points I can goto. BUT if I needed to get to these points from another macro without running the bit before the goto point in the target macro - how can I do this.
I can call or application.run the second macro, but I need only run a part of it, not the whole thing.
I am a bit stuck.
Here is the part of the code which defines the goto point in one of the target macro's.
Grade:
Grades = Application.InputBox("Which Grade chemistry do you wish to load & Check against" & vbLf & vbLf & "1. S355 J2H" & vbLf & vbLf & "2. S355NH" & vbLf & vbLf & "3. S355NLH" & vbLf & vbLf, "Select which option to load")
Select Case Grades
Case 1
Ans = MsgBox("You have selected S355J2H is this correct?", vbYesNo) ' allows a loop if you have made a mistake and will take you back to the selection option
If Ans = vbNo Then GoTo Grade Else:
rng8.Copy: rng7.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ws.Activate
Columns("BC:BD").Select
With Selection.Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
Case 2
Ans = MsgBox("You have selected S355NH is this correct?", vbYesNo) ' allows a loop if you have made a mistake and will take you back to the selection option
If Ans = vbNo Then GoTo Grade Else:
rng8a.Copy: rng7.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ws.Activate
Columns("BC:BD").Select
With Selection.Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
Case 3
Ans = MsgBox("You have selected S355NLH is this correct?", vbYesNo) ' allows a loop if you have made a mistake and will take you back to the selection option
If Ans = vbNo Then GoTo Grade Else:
rng8b.Copy: rng7.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ws.Activate
Columns("BC:BD").Select
With Selection.Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
Case Else ' this is where no input or an alternative input is done, it will exit the subroutine
dummy = MsgBox("wrong input please try again", vbCritical)
Exit Sub
End Select
There is a similar code before this step, which I do NOT want to run and I would ideally like to not repeat this code and others from the target macro's in a separate macro, and call this new macro. When I need to update the information it means updating in multiple places instead one just the one or two maximum.
As BigBen suggested, you need to refactor your code. Copy the below code in a Module
Option Explicit
Public rRng8 As Range, rRng8a As Range, rRng8b As Range
Sub CopyRange(rCopyToRng As Range)
Dim iGrade As Long, iAns As Long, iTryAgain As Long
' Set Default Values
iAns = vbNo
iTryAgain = vbYes
' Loop to copy the correct range
Do While iAns <> vbYes And iTryAgain <> vbNo
' Get grade
iGrade = Application.InputBox("Which Grade chemistry do you wish to load & Check against" & vbLf & vbLf & "1. S355 J2H" & vbLf & vbLf & "2. S355NH" & vbLf & vbLf & "3. S355NLH" & vbLf & vbLf, "Select which option to load", , , , , , 1)
' Case to select the correct range to copy
Select Case iGrade
Case 1
iAns = MsgBox("You have selected S355J2H is this correct?", vbYesNo)
If iAns = vbYes Then CopyRangeHelper rCopyToRng, rRng8
Case 2
iAns = MsgBox("You have selected S355NH is this correct?", vbYesNo)
If iAns = vbYes Then CopyRangeHelper rCopyToRng, rRng8a
Case 3
iAns = MsgBox("You have selected S355NLH is this correct?", vbYesNo)
If iAns = vbYes Then CopyRangeHelper rCopyToRng, rRng8b
Case Else
' If the user entere incorrect number, ask if the want to try again
iTryAgain = MsgBox("Wrong input. Do you want to try again?", vbQuestion + vbYesNo)
End Select
Loop
End Sub
Sub CopyRangeHelper(rCopyToRange As Range, rRngToCopy As Range)
' Copy range
rRngToCopy.Copy: rCopyToRange.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
' Set range format
With rCopyToRange
.Interior.ThemeColor = xlThemeColorDark1
.Interior.TintAndShade = 0
End With
End Sub
NOTE: You don't need to use Select or Activate. You just reference what you need to work with
How to use this:
Below is a sample UDF that calls CopuRange UDF to perform the action
Sub TestThis()
Dim oWS As Worksheet: Set oWS = ThisWorkbook.Worksheets("Sheet3") ' Change sheet reference
Set rRng8 = oWS.Range("A1:A16") ' Set ranges as required
Set rRng8a = oWS.Range("B1:B16")
Set rRng8b = oWS.Range("C1:C16")
CopyRange ThisWorkbook.Worksheets("Sheet4").Range("A1:A16") ' Change sheet reference and range
End Sub

Paste value based on index match

I'm attempting to get a macro(button click) to paste a value into another sheet if the value is not a formula. I'm not getting any errors with the below but the function won't fire. Thank you in advance for your help!
Sub Update_Numbers(ByVal Target As Range)
' Update_Numbers Macro
'
' Keyboard Shortcut: Ctrl+j
On Error GoTo Safe_Exit
Application.EnableEvents = False
Select Case Target.Address(0, 0)
Case Sheets("Wage Run").Range("B7")
If Target.HasFormula = False Then _
Sheets("wage run").Range("B7").Copy
Sheets("With Changes").Select
Range(Application.WorksheetFunction.Index(Sheets("With Changes").Range("E2:AB138"), Application.WorksheetFunction.Match(Sheets("Wage Run").Range("D1"), Sheets("With Changes").Range("A2:A138"), 0), 1)).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Select
Safe_Exit:
Application.EnableEvents = True
End Sub
EDIT: Changed with the below suggestions, but it still won't fire.
Sub Update_Numbers(ByVal Target As Range)
With Sheets("wage run")
' Update_Numbers Macro
'
' Keyboard Shortcut: Ctrl+j
On Error GoTo Safe_Exit
Application.EnableEvents = False
Select Case Target.Address(0, 0)
Case "B7"
If Target.HasFormula = False Then
Sheets("wage run").Range("B7").Copy
Sheets("With Changes").Select
Range(Application.WorksheetFunction.Index(Sheets("With Changes").Range("E2:AB138"), Application.WorksheetFunction.Match(Sheets("Wage Run").Range("D1"), Sheets("With Changes").Range("A2:A138"), 0), 1)).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
End Select
Safe_Exit:
Application.EnableEvents = True
End Sub
In addition to #Scott Craner's comment above: Note that the "If-Then" construct doesn't need any corresponding "End If" when you have only one statement on one line following "Then". But when the If construct contains more than one statement, as in your case, the code block must end with "End If". You have a line continuation symbol ( _) immediately after "Then". Try removing this and include an End If statement instead, like this:
Select Case Target.Address(0, 0)
Case Sheets("Wage Run").Range("B7")
If Target.HasFormula = False Then
Sheets("wage run").Range("B7").Copy
Sheets("With Changes").Select
Range(Application.WorksheetFunction.Index(Sheets("With Changes").Range("E2:AB138"), Application.WorksheetFunction.Match(Sheets("Wage Run").Range("D1"), Sheets("With Changes").Range("A2:A138"), 0), 1)).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
End Select
In addition to my comments above, here is a very minimal example that seems to do what you are asking for, but without any other context. It works on a workbook with (at least) two sheets. Maybe useful as a starting point.
Sub Macro1()
'
' Macro1 Macro
'
' Paste a value into another sheet if the value is not a formula.
Dim sourcecell As Range
Dim targetcell As Range
Set sourcecell = Sheets(1).Range("D8")
Set targetcell = Sheets(2).Range("D8")
If Not sourcecell.HasFormula Then targetcell = sourcecell
End Sub

Resources