Re: .Copy and .Paste in Excel VBA - vba

Why, when copying a cell, shape, etc in Excel VBA, is ActiveSheet.Cells(i,j).Paste not valid?
Instead I have
Cells(i,j).Select
ActiveSheet.Paste
which works, but why?

Because .Paste has to be applied to a SheetObject (as you have written correctly: ActiveSheet.Paste)
Check out the method on MSDN. It has to be used the following way:
Worksheets("Sheet1").Range("C1:C5").Copy
ActiveSheet.Paste Destination:=Worksheets("Sheet1").Range("D1:D5")
Or more shortly:
Cells(j,i).Copy Destination:=Cells(y,z)
Or use the PasteSpecial-method. It can be applied to Range-objects:
With sheet
.Range("C1:C5").Copy
.Range("D1:D5").PasteSpecial Operation:=xlPasteSpecialOperationAdd
End With

You don't have to tell it to paste for example,
if you have the variables set for i and j then you can use this
Range("A1").Copy Cells(i, j)
You could even have no copying at all, such as:
Cells(i, j)=Range("A1")

Related

VBA not updating Excel rows referring to other sheets in same workbook when sorting rows alphabetically

I'm having problems, Excel is not updating rows referring to other sheets in same workbook when ordering rows alphabetically.
I have a userform in which there's a button insertCM with this code:
Private Sub insertButton_Click()
ActiveCell.EntireRow.Select
Selection.Insert Shift:=xltoDown
Range("A9:AK9").Copy
Range("A8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Selection.PasteSpecial Paste:=xlPasteFormats
Range("C10").Copy
Range("C8:C9").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy
Range("H8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteAll
nomCM = Empty
CXinitial = Empty
resteCX = Empty
CCselect = Empty
C4initial = Empty
resteC4 = Empty
compteurCT = Empty
Range("A8").Activate
ActiveCell.RowHeight = 18.6
For i = 2 To ThisWorkbook.Sheets.Count
With Sheets(i).Select
emptyRow = Range("A9").End(xlDown).Offset(0, 2).Row
Range("A9:AL" & emptyRow).Sort _
Key1:=Range("A9"), Order1:=xlAscending
Set SearchRange = Range("A8", Range("A200").End(xlUp))
Set FindRow = SearchRange.Find(nomCM, LookIn:=xlValues, LookAt:=xlWhole)
Range("A" & FindRow.Row).Select
ActiveCell.EntireRow.Activate
End With
Next i
Sheet2.Select
End
End Sub
The userform is used for inserting new clients in several sheets at the same time. Textbox inserts Name, Cost Center, etc., in a blank row and insertButton inserts a new row leaving data inserted in row 8 to go to row 9. After that the code puts all rows alphabetical order so the new client now in row 9 goes to the new one, and cells containing formulas change row numbers.
However some of the sheets have cells containing references to other sheets' cells in the same row. So imagine:
I insert client name "LORUM" "Cost Center 4" and it puts him in row 9 so formula is:
=$C9-COUNTIF($E9:$P9;"CT")+'Sheet5'!$D9
...but when it changes his row to the final one, formula row is:
=$C18-COUNTIF($E18:$P18;"CT")+'Sheet5'!$D9
It does not change row when referring to other sheets.
Any ideas?
It's looks like you've made a good effort, but there are still numerous problems with your code (beside the one line), and I can guarantee that a combination of these issues are preventing your intended outcome.
I can't fix it completely because there are so many bugs that I'm not clear on what you're trying to do, but hopefully this will get you started on the right track...
xlToDown is not a valid reference. You probably mean xlDown
you have a number of undeclared variables and objects, like: i, emptyRow, SearchRange, FindRow, nomCM
you have things (objects?) "set to nothing" that aren't declared or used anywhere: CXinitial, resteCX, CCselect, C4initial, resteC4, compteurCT
your Find statement is looking for nomCM which is empty (and never set), so the Find statement will never find anything.
You should put Option Explicit at the top of every module (especially when learning or troubleshooting). This will prevent issues like the ones above by "forcing" you to properly declare & handle all of your variables, objects, properties, etc.
Near the end, you refer to Sheet2.Select as if Sheet2 is a declared object, instead of using Sheets("Sheet2").Select. I'm not sure why you're selecting the sheet at the very end anyhow.
You have an With..End statement that is doing absolutely nothing since you don't reference it with a . dot anywhere: With Sheets(i).Select .. End With, and also Select isn't used like that.
A mystery End near the end for some reason.
Also, you're unnecessarily doubling up commands like:
ActiveCell.EntireRow.Select
Selection.Insert Shift:=xlDown
..instead of:
ActiveCell.EntireRow.Insert Shift:=xlDown
and another example, all this:
Range("A9:AK9").Copy
Range("A8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Selection.PasteSpecial Paste:=xlPasteFormats
Range("C10").Copy
Range("C8:C9").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy
Range("H8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteAll
...instead of:
Range("A9:AK9").Copy
Range("A8:AK8").PasteSpecial xlPasteValuesAndNumberFormats
Range("C10").Copy
Range("C8:C9").PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy Range("H8:AK8")
All of this would be more clear by Googling the documentation for each command you're unfamiliar with, such as:
Range.Copy Method (Excel)
Range.PasteSpecial Method (Excel)
XlPasteType Enumeration (Excel)
All the ActiveCell and ThisWorkbook references are troublesome but again, I'm not sure what to do with them since I don't know your workbook.
Indentation (and general organization) are very important as well. It may not change the way that the code runs, but it will help you (and others) track down existing & potential issues more easily.
Here is your code cleaned up as best as I could:
Option Explicit 'this line goes at the very top of the module
Private Sub insertButton_Click()
Dim i As Long, emptyRow As Long, SearchRange As Range, FindRow As Range, nomCM
nomCM = Empty
ActiveCell.EntireRow.Insert Shift:=xlDown
Range("A9:AK9").Copy
Range("A8:AK8").PasteSpecial xlPasteValuesAndNumberFormats
Range("C10").Copy
Range("C8:C9").PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy Range("H8:AK8")
Range("A8").RowHeight = 18.6
For i = 2 To ThisWorkbook.Sheets.Count
With Sheets(i)
emptyRow = .Range("A9").End(xlDown).Offset(0, 2).Row
.Range("A9:AL" & emptyRow).Sort Key1:=.Range("A9"), Order1:=xlAscending
Set SearchRange = .Range("A8", .Range("A200").End(xlUp))
Set FindRow = SearchRange.Find(nomCM, LookIn:=xlValues, LookAt:=xlWhole)
.Range("A" & FindRow.Row).Select
ActiveCell.EntireRow.Activate
End With
Next i
Sheets("Sheet2").Select
End Sub
as per my test, sorting actually doesn't change other sheet direct references
so you may want to use OFFSET to keep referencing the actual current row index
instead of:
=$C9-COUNTIF($E9:$P9;"CT")+'Sheet5'!$D9
use
=$C9-COUNTIF($E9:$P9;"CT")+ OFFSET('Sheet5'!$D1,ROW()-1,0)
I found a solution:
=INDIRECT(ADDRESS(ROW();4;3;1;"Sheet5"))
Where Row() will always refer to the actual cell's row.
Hope it will help you!

VBA - Pasting/Inserting a range without formatting shifted down

This is probably pretty simple but as a beginner I am not sure how to combine these two codes into one.
Right now I use this code to copy and paste a table into specific range.
Sheet3.Range("MyTable").Copy
Sheets("MyWorksheet").Range("B12:D12").Insert Shift:=xlDown
Now I want to paste it without formatting and this code should do the work:
Sheets("MyWorksheet").Range("B12:D12").PasteSpecial xlPasteValuesAndNumberFormats
All I need to do is add the Shift:=xlDown to the second code somehow... Is it possible to do it all in one line?
Try with this solution where 1st- we copy + insert as previously, 2nd- we copy to paste with values to overwrite what was inserted:
Sheet3.Range("MyTable").Copy
Sheets("MyWorksheet").Range("B12:D12").Insert Shift:=xlDown
With Sheets("MyWorksheet").Range("B12").Resize(Sheet3.Range("MyTable").Rows.Count, Sheet3.Range("MyTable").Columns.Count)
.Copy
.PasteSpecial xlPasteValuesAndNumberFormats
End With
Application.CutCopyMode = False
Try to do it in two lines but you have to keep the right order of all instructions:
Sheets("MyWorksheet").Range("B12:D12").Insert Shift:=xlDown
Sheet3.Range("MyTable").Copy
Sheets("MyWorksheet").Range("B12").PasteSpecial xlPasteValuesAndNumberFormats
It could be also required the following line before .insert:
application.CutCopyMode = false

Runtime error 1004 when using Cut and PasteSpecial

I have to cut the contents from active cell for a specific range in sheet 1 and paste it into the active cell of that range in sheet 2. Cutting the specific range of contents is working fine, but in the paste options I am getting runtime error 1004 as application defined or object defined error.
Here is the code I am using:
Sub sheet1_sheet2_copy_click()
Sheets("sheet1").Activate
ActiveCell.Resize(1, 26).Cut
Sheets("sheet2").Activate
ActiveCell.Resize(1, 26).PasteSpecial
End Sub
Your question is a little unclear, but you can try doing this:
Sub sheet1_sheet2_copy_click()
Sheets("sheet1").Cells(1, 26).Cut
Sheets("sheet2").Cells(1, 26).PasteSpecial Paste:=xlPasteValues
End Sub
Better yet, you can just do this:
Sub sheet1_sheet2_copy_click()
Sheets("sheet2").Cells(1, 26).value = Sheets("sheet1").Cells(1, 26).Value
End Sub
In general, it is better to not use .Activate or .Select, but to instead explicitly define your references like I showed. Modify the Paste:= to whatever parameter you are trying to use for PasteSpecial.
See https://msdn.microsoft.com/VBA/Excel-VBA/articles/range-pastespecial-method-excel for more information on this command.
Personally, I think using the active cell as a source and destination is rather unreliable, but if you change the paste line to activesheet.paste it should work fine.
I have tested your code and it looks like PasteSpecial only works if you use Copy instead of Cut, so you should modify your code this way:
Sheets("sheet1").Activate
ActiveCell.Resize(1, 26).Copy
Sheets("sheet2").Activate
ActiveCell.Resize(1, 26).PasteSpecial
If you need to delete the data from sheet1, then do it after the PasteSpecial.

VBA turning sections of a recorded macro into something more efficcient

I am trying to optimise some data sorting code, the original code looks like it has been "written" through the use of excels "Record Macro" function.
The following is an example from the code.
Range("A12").Offset(z, 0).Select
Selec.Resize(Selection.Rows.Count, Selection.Columns.Count + (X2 - 1)).Select
Selection.Copy
Range("C4").Offset(y, 0).Select
ActiveSheet.Paste
In order to make this code more efficient, should i re-write this section to involve a range variable that its' .Value is equal to the Selection data?
The X2, z and y variables are used as part of the copy function and are slowly increased to make reading the end product much easier. They are altered elsewhere in the module.
I would just like to see some suggestions for what you think I should do.
I have read the very popular "How to avoid using Select in Excel VBA Macros" question on here, and am just looking for some further advice.
(How to avoid using Select in Excel VBA macros)
Thanks
I guess this would be the easiest way.
Range("C4").Offset(y, 0).Resize(1, x2) = Range("A12").Offset(z, 0).Resize(1, x2)
Although I would advise:
to avoid .Offset and work with named ranges instead
to avoid .Copy and .Paste sometimes your data might be too big for your clipboard and using just the =-operator is way faster
to not name your variables with capital letters or additional ciphers, it can be very confusing
use this format .Cells( row, column ) instead of `.Cells("A1"). It's easier to handle and can be changed more easily via calculations
HTH
Copy/pasting isn't very efficient. Doing Range("X1").value = Range("Y1").value is better. This is what I would do
'change this
Selection.Copy
Range("C4").Offset(y, 0).Select
ActiveSheet.Paste
'to this
Range("C4").Offset(y, 0).Value = Selection.Value 'selection value is the range that is being copied.

How to paste value of a sheet using VBA?

I have always used following to make a sheet to contain only values:
Sheets("NameOfTheTab").Activate
Cells.Select
Selection.Copy
Selection.PasteSpecial Paste:= xlPasteValues
But this is not safe, if someone/event change the selection, the program runs into random behaviour. How can can I get rid of this pattern?
Well, for one thing, you can avoid selecting the cells, just directly copy them:
Sheets("NameOfTheTab").Activate
Cells.Copy
Cells(1,1).PasteSpecial Paste:= xlPasteValues
Although this might not be the fastest way, depending on your sheet/actual problem.
You should always avoid using select method, beacuse it is not reliable. The sub below is a sample to copy data from a worksheet and paste only values to another one. This sample sub assumes you are running this macro from your target workbook if not change ThisWorkbook to your target workbook.
Sub copy_paste_only_values()
'will copy all cells in your tab that contain data
ThisWorkbook.Worksheets("NameOfTheTab").Cells.Copy
'will paste only values to your target worksheet
ThisWorkbook.Worksheets("NameOfTheTargetTab").Range("A1")._
PasteSpecial Paste:=xlPasteValues
'empty the clipboard
Application.CutCopyMode = False
End Sub