I have used an Excel macro that automatically pastes all data as values, by undoing the pasting and pasting it as value.
This is the code:
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, 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" And UndoList <> "Auto Fill" _
Then GoTo LetsContinue
'~~> Undo the paste that the user did but we are not clearing
'~~> the clipboard so the copied data is still in memory
Application.Undo
If UndoList = "Auto Fill" Then Selection.Copy
'~~> Do a pastespecial to preserve formats
On Error Resume Next
'~~> Handle text data copied from a website
Target.Select
ActiveSheet.PasteSpecial Format:="Text", _
Link:=False, DisplayAsIcon:=False
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
I am using the English Excel version where it works fine, however when other users, who e.g. have a German Excel version paste something, they get a procedure error in this line:
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
I guess the Undo command is named differently in German.
Is there a way to define the Undo list independent of the language the user is using?
Use the Control's Id number instead.
debug.Print Application.CommandBars("Standard").Controls("&Undo").Id
=> 128
debug.Print Application.CommandBars("Standard").FindControl(Id:=128).caption
=> &Undo
You should also substitute in the code the words "Paste", "Auto fill" and "Text" for your local language words.
Use the index as name:
undoname = Application.CommandBars("Standard").FindControl(ID:=128).Index
UndoList = Application.CommandBars("Standard").Controls(undoname).List(i)
Very useful code. Thank you.
Can do this also:
UndoList = Application.CommandBars("Standard").FindControl(ID:=128).List(1)
Related
Probably I'm missing something but the most simple "Worksheet_Change" doesn't work at all. The code is placed in the correct worksheet and is exactly the same as in samples I have found in my search to solve the problem. Please ignore the lines that start with "'" as they will be part of the code after the issue is solved. I've simplified the code in trying to localize the issue but as I said, even this simple code doesn't work, even if I use a new Workbook with only one sheet. As said, I might be missing something completely simple but for the moment, I don't know what it is. Thank you.
Jan
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
' Dim KeyCells As Range
' Set KeyCells = Range("Orders[Nieuw]")
' If Not Application.Intersect(Range("Orders[Nieuw]"), Target) _
' Is Nothing Then
' If Target.Address = "$C$10" Then
Application.EnableEvents = False
' If Target.Value = "Ja" Then
MsgBox "This Code Runs When Cell A1 Changes!"
Target.Font.ColorIndex = 5
' Range("AG2").Select
' Selection.Copy
' Range("Ordernummerbereik").Select
' Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
' :=False, Transpose:=False
' SendKeys ("{ESC}")
' End If
Application.EnableEvents = True
' End If
End Sub
You probably ended up in EnableEvents = False and therefore no events will be executed anymore including the Worksheet_Change event.
When using Application.EnableEvents = False make sure you use proper error handling that returns it to True otherwise if an error occurs it stays False until you close Excel.
Example for error handling
Public Sub Example()
Application.EnableEvents = False
On Error Goto EventsOn
' your code here
EventsOn:
Application.EnableEvents = True
If Err.Number Then Err.Raise Err.Number ' show the error message
End Sub
That means if any error occurs in your code it jumps to EventsOn: turns events on and throws the error message. This way you ensure that Events are always turned on in case of an error.
The only way I can reproduce your problem is by setting EnableEvents to false outside of the sub. Perhaps it crashed at some stage leaving events disabled?
Incidentally you can replace the copy and paste with
Range("Ordernummerbereik").Value = Range("AG2").Value
which is much more robust
Finally I advise you to use fully qualified ranges for ranges without an explicit name e.g. ThisWorkBook.Sheets("Sheet1").Range("A1") rather than Range("A1")
You can use (note the dot-Range on AG2)
With ThisWorkBook.Sheets("Sheet1")
Range("Ordernummerbereik").Value = .Range("AG2").Value
' ... other code with range references
End With
I'm using this vba code below, in Excel, to stop users from doing cut and paste and breaking formulas reference. The code itself works fine but it is creating an advert issue. The user will not be able to copy data from the workbook onto another workbook. Is there a work around it? Thanks
Private Sub Workbook_SheetSelectionChange(ByVal sh As Object, _
ByVal Target As Excel.Range)
Select Case Application.CutCopyMode
Case Is = False
'do nothing
Case Is = xlCopy
'do nothing
Case Is = xlCut
MsgBox "Please DO NOT Cut and Paste as it will break the formula reference." & vbNewLine & vbNewLine _
& "Use Copy and Paste, then delete the source.", vbCritical
Application.CutCopyMode = False 'clear clipboard and cancel cut
End Select
Rather than adding the code on the copy event, you need to handle the paste event. Try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
'Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(UndoList, 5) = "Paste" Then
Application.Undo
MsgBox "Please DO NOT Cut and Paste as it will break the formula reference."
& vbNewLine & vbNewLine _
& "Use Copy and Paste, then delete the source.", vbCritical
End If
End Sub
I found this code and it seems to be almost what I need. Is there a way to make it copy paste and delete the source instead of just showing a message box? I use worksheets that have links to another worksheet and if I use cut and paste I get a #REF error.
Thanks
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _
ByVal Target As Excel.Range)
Public NewRange As String
Select Case Application.CutCopyMode
Case Is = False
'do nothing
Case Is = xlCopy
'do nothing
Case Is = xlCut
MsgBox "Please DO NOT Cut and Paste. Use Copy and Paste; then delete the source."
Application.CutCopyMode = False 'clear clipboard and cancel cut
End Select
End Sub
By using .PasteSpecial Paste:=xlPasteValues, you will paste the value and not the formula so the reference to the other sheet won't exist. This means you do not have to delete any references to other sheets.
For this to work properly, just update the "Sheet2" and "A1" references in Worksheets("Sheet2").Range("A1").PasteSpecial Paste:=xlPasteValues
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Excel.Range)
Public NewRange As String
Select Case Application.CutCopyMode
Case Is = False
'do nothing
Case Is = xlCopy
'do nothing
Case Is = xlCut
MsgBox "Please DO NOT Cut and Paste. Use Copy and Paste; then delete the source."
Worksheets("Sheet2").Range("A1").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False 'clear clipboard and cancel cut
End Select
End Sub
I am relatively new to vba, so please be gentle :)
I have reviewed various scripts which supposedly preserve the formatting of cells on a spreadsheet when ctrl c/ctrl v or copy & paste is being used. Unfortunately I cannot seem to get any of the variations to work for my intentions. I suppose this might be due to the fact that a lot of the data being copy & pasted is being copied from other programs and pasted into the worksheet(therefore copying and keeping the formatting of the program from which it came). All of the macros I've tried to work with all seem to attempt to preserve formatting when copying between cells/worksheets or workbooks and doesn't address the data format when copying from another program.
I'm looking for an alternate approach. From a logical standpoint, I'm thinking that there should be a way on ctrl v or paste event, to have the copied data stored as a variable, stripped of its formatting and to only paste the raw value. I've tried playing around with pastespecial, but I'm not sure how to force a pastespecial (or replace paste with pastespecial).
Here is some code sample, but it doesn't seem to work for me. I keep getting:
cannot run the macro "C:...Test.xlsm'!MyPaste'. The macro may not be available in this workbook or all macros may be disabled
Macros are definitely enabled and the code is pasted into [ThisWorkbook(Code)]
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, 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" And UndoList <> "Auto Fill" Then GoTo LetsContinue
'~~> Undo the paste that the user did but we are not clearing the clipboard
'~~> so the copied data is still in memory
Application.Undo
If UndoList = "Auto Fill" Then Selection.Copy
'~~> Do a pastespecial to preserve formats
On Error Resume Next
'~~> Handle text data copied from a website
Target.Select
ActiveSheet.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
The reason for the error message is that your code is an event handler
see:
MSDN Office Online Reference: Creating VBA Macros to Manipulate Worksheets in Excel 2007
MSDN Office Online Reference: Running VBA Code When Events Occur in Excel 2010
and
Chip Pearson MVP and all round Excel Chieftan: Events And Event Procedures In VBA
Ozgrid MVP and all round Excel VBA Top Banana: Worksheet Events In Excel VBA
basically the Worksheet.Change Event (Excel) is fired when the user changes a cell in the worksheet. Excel passes in the Worksheet Object object as sh and the Range Object (Excel) as Target. Your code then uses these objects (Ozgrid Excel VBA Crash Course Lesson 4 - Common objects).
as David Zemens has suggested, you need to use the PasteSpecial method of the Sheet object. for further info, see MSDN libray: PasteSpecial Method [Excel 2003 VBA Language Reference].
and when you have finished all that reading, you will be ready to copy paste my code below:
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, 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" And UndoList <> "Auto Fill" Then GoTo LetsContinue
'~~> Undo the paste that the user did but we are not clearing the clipboard
'~~> so the copied data is still in memory
Application.Undo
If UndoList = "Auto Fill" Then Selection.Copy
'~~> Do a pastespecial to preserve formats
On Error Resume Next
'~~> Handle text data copied from a website
Target.PasteSpecial Paste:=xlPasteValues
On Error GoTo 0
'~~> Retain selection of the pasted data
Target.Select
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
so, bada bing bada bing, you have your working code, and some reading that should help you to understand better what your code is doing and how it does it.
I am trying to paste a manually copied sheet into a sheet named "Digital - Input".
I sometimes get the error
Pastespecial method of Range class failed
This is my paste statement:
Worksheets("Digital - Input").range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
This is my complete code:
Sub pasteDigitalInput()
Application.ScreenUpdating = False
'open the source sheet
Call unlockAll
'show the input sheet
Call showerfunc("Digital - Input")
'paste values
'On Error GoTo feilmeld
Worksheets("Digital - Input").range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'Update cell references
Call getTotals
'Set the start of ukestrykk for digital
showerfunc ("Kilder")
Sheets("Kilder").Select
range("J2").Select
Call findAnd("Netto spend pr uke:", "Kilder", "Digital - Input", 2, 0, , , True)
hiderfunc ("Kilder")
'Hide sheet
Call hiderfunc("Digital - Input")
Sheets("Digital").Select
Application.ScreenUpdating = True
'locks the sheet again
Call lockAll
Exit Sub
feilmeld:
'hiderfunc ("Digital - Input")
Sheets("Digital").Select
Call lockAll
Application.ScreenUpdating = True
MsgBox ("Du må kopiere planen fra excel utskriften til Adform før du bruker denne knappen. OBS! kopier planen på nytt og lås opp Digital arket før du prøver igjen.")
End Sub
Edit:
It seems to work right after opening the two workbooks. However if I use any other macro especially the macro that cleans the input sheet, I get the error.
Clean input sheet macro:
Sub clearInputDigital()
Call ClearInput("Digital - Input", "Digital")
End Sub
Sub ClearInput(inputsheet As String, sourceSheet As String)
Application.ScreenUpdating = False
'Show the sheet
showerfunc (inputsheet)
Sheets(inputsheet).Select
Cells.Select
Selection.ClearContents
'Hide the sheet
hiderfunc (inputsheet)
Sheets(sourceSheet).Select
Application.ScreenUpdating = True
End Sub
(obviously I'm unsure what is happening in the subs and functions that you are calling)
I don't always trust the excel VBA compiler to reference the objects that I'm coding it to reference, so I always try to fully qualify my code like the following
Sub pasteDigitalInput()
Excel.Application.ScreenUpdating = False
'open the source sheet
Call unlockAll
'show the input sheet
Call showerfunc("Digital - Input")
'paste values
'On Error GoTo feilmeld
Excel.ThisWorkbook.Worksheets("Digital - Input").Range("A1").PasteSpecial Paste:=Excel.xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'Update cell references
Call getTotals
'Set the start of ukestrykk for digital
showerfunc ("Kilder")
With Excel.ThisWorkbook.Sheets("Kilder")
.Activate
.Range("J2").Select
End With
Call findAnd("Netto spend pr uke:", "Kilder", "Digital - Input", 2, 0, , , True)
hiderfunc ("Kilder")
'Hide sheet
Call hiderfunc("Digital - Input")
Excel.ThisWorkbook.Sheets("Digital").Activate
Excel.Application.ScreenUpdating = True
'locks the sheet again
Call lockAll
Exit Sub
feilmeld:
'hiderfunc ("Digital - Input")
Excel.ThisWorkbook.Sheets("Digital").Activate
Call lockAll
Excel.Application.ScreenUpdating = True
MsgBox ("Du må kopiere planen fra excel utskriften til Adform før du bruker denne knappen. OBS! kopier planen på nytt og lås opp Digital arket før du prøver igjen.")
End Sub
If you're only moving values maybe you could try avoiding using the clipboard altogether with a structure more like this :
Sub WithoutPastespecial()
'WORKING EAXAMPLE
Dim firstRange As Excel.Range
Dim secondRange As Excel.Range
Set firstRange = Excel.ThisWorkbook.Worksheets("Cut Sheet").Range("S4:S2000")
With Excel.ThisWorkbook.Worksheets("Cutsheets")
Set secondRange = .Range("A" & .Rows.Count).End(Excel.xlUp).Offset(1)
End With
With firstRange
Set secondRange = secondRange.Resize(.Rows.Count, .Columns.Count)
End With
secondRange.Value = firstRange.Value
End Sub
Generally this error shows up when the current window(sheet) that is open is not the same one in which you are pasting something. Excel is very strict about it. When you do it manually, the sheet is selected obviously before pasting, so you will never see the error.
So before pasting into the worksheet "Digital - Input", just insert a line, above that to select the sheet that you would like to paste in and then paste. Also, I would recommend using 'Thisworkbook' if you are handling multiple files so that...you know...excel doesn't get confused which workbook you're referring to. So your code would be
Thisworkbook.Worksheets("Digital - Input").Select
Worksheets("Digital - Input").range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Hope this helps.