Copy/PasteSpecial Offset macro is slow when switching between worksheets - vba

Intro: I've been working on this macro for quite awhile and have had success getting it to do what I need it to do, however I'm not doing it the most efficient way as my coding background is minimal. Because of this the macro is extremely slow due to switching back and forth from one worksheet "FB MATE DATA" to another "Sheet 2 (2)" copying and pasting data.
Background: A CMM machine spits out measurement data into a spreadsheet that I need to copy and paste from one sheet to another in neat X and Y columns to be overlayed in a scatter plot. The problem is that the data is in an unconventional pattern that requires the use of an offset, and different sheets have data that starts in different rows so the macro must account for that. The reason it is so slow is because the way i have achieved this is by constantly activating each worksheet back and forth, over and over to maintain control over the active cell instead of just referencing an offset from a fixed cell due to the offset changing occasionally in a row. The code i have now:
cycles down through column A until it finds a blank cell
shifts down to the cell immediately below it and starts copying data over. (This is very important because the first few rows are data irrelevant to me, and they are separated from the data i seek by a space.)
copies data from the range (G:FZ) in an offset (e.g. G21, K21, O21, S21, W21, AA21, AE21, AI21, AM21, AQ21, AU21, AY21, BG21) into a neat X|Y table from D73:E:93. Notice the irregular pattern (due to info extraneous to my plot)
Every two represent an X|Y pair (e.g. X: G21 pasted into D73 in Sheet 2, Y: K21 pasted into E73 in Sheet 2, etc.)
Problem: For each row of data, I need to copy certain columns in an interval that changes (first column, fourth column, ninth column, twelvth column, etc.) and paste it into two X|Y columns on another page.
The data grab will not always start in G21. Sometimes the first data point may be G24, or G10, or G15, hence why the macro searches for a blank row first instead of pulling from a fixed position. Below is a sample of cycling through the first four columns.
Code:
Sub LocatorTest()
'Select first row of eligible spare pallet data
Range("B73").Select
Application.Goto (ActiveWorkbook.Sheets("FB MATE DATA").Range("A1"))
Dim c
For Each c In Range("A1:A100").Cells
If c = "" Then
c.Select
Exit For
End If
Next
ActiveCell.Offset(1, 6).Range("A1").Select
Selection.Copy
Sheets("Sheet2 (2)").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("C73").Select
Worksheets("FB MATE DATA").Activate
ActiveCell.Offset(rowOffset:=0, columnOffset:=4).Activate
Selection.Copy
Sheets("Sheet2 (2)").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("B74").Select
Worksheets("FB MATE DATA").Activate
ActiveCell.Offset(rowOffset:=0, columnOffset:=8).Activate
Selection.Copy
Sheets("Sheet2 (2)").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("C74").Select
Worksheets("FB MATE DATA").Activate
ActiveCell.Offset(rowOffset:=0, columnOffset:=12).Activate
Selection.Copy
Sheets("Sheet2 (2)").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
Any help you can provide into maybe a different way of achieving this or making it run quicker would be greatly appreciated.

o wow, this can use some MAJOR improvements.
but to make it easy, you might want to put this at the start:
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
and this at the end of your macro:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
This will give it huge speed boost already. Next; you should try to reference to the cells without activating...

Related

How to edit Formula Bar in macro with variable output?

I am currently working on a macro that needs to, at one point, click into the formula bar of the current cell, and then press enter. However, when I record this, despite making no edits to the cell, it inputs it based on the text in the cell at the end. The current code is this:
Sub Macro36()
Application.CutCopyMode = False
Selection.Copy
ActiveCell.Offset(1, 0).Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ActiveCell.Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = _
"='C:\Users\User\Documents\[TimeSheet.xlsx]Sheet1'!R[-3]C[-1]"
ActiveCell.Offset(1, 0).Range("A1").Select
End Sub
The portion from "ActiveCell.FormulaR1C1" onward is where the issue occurs. It automatically does this while recording, rather than having the macro select the formula bar in the cell and then press enter. This is necessary to be able to do because it would allow a workaround for the INDIRECT function not working on closed documents.
Has anyone come across this issue/would know how to fix it? Thank you for any responses.

vba code to copy worksheets and paste as values to a new workbook

I'm not very good at vba so excuse my amateur question.
I have an active workbook open containing 3 tabs. I want to build a macro that opens up another workbook and pastespecial values the data from my three tabs into the three tabs on the second workbook.
This is my coding which keeps breaking on the paste special line.
Sub NewVersion_Click()
Dim y As Workbook
ThisWorkbook.Sheets("Fact Find").Range("A5:I283").Copy
Set y = Workbooks.Open("location")
y.Worksheets("Fact Find").Range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'ThisWorkbook.Sheets("Entity Fact Find").Range("A4:F237").Copy
'y.Worksheets("Entity Fact Find").Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'ThisWorkbook.Sheets("Suitability Assessment Form").Range("A4:E108").Copy
'y.Worksheets("Suitability Assessment Form").Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveWorkbook.Close
End Sub
Any help will be really appreciated.
Thanks
Arvin
Here is your paste special for worksheet fact find.
Modify the code to copy the other sheets, but no need to open the file again.
Which file are you trying to close?
Set wb = ThisWorkbook
wb.Sheets("Fact Find").Range("A5:I283").Copy
Workbooks.Open ("location")
Workbooks("location").Worksheets("Fact Find").Range("A1").PasteSpecial xlPasteValues
wb.Sheets("Entity Fact Find").Range("A4:F237").Copy
Workbooks("location").Worksheets("Entity Fact Find").Range("A1").PasteSpecial xlPasteValues

Pausing VBA and re-running it causes faster execution

We are using a macro for some analysis that that we want to be able to look at the process, and for a reason that is out of scope here, we are forced to use Activate and Select in the macro. Both my colleagues and I are aware of downsides of using such methods. Meanwhile, it has been tested that explicit coding and selecting and activating is not the main reason for this issue.
In one of the sub-modules, that I am posting the (pseudo-)code of it below, we basically get the data from a sheet and copying it over to another one.
Problem
The problem is that this process is really slow, but when I pause the macro(Esc), hit debugging, step through (F8) for one or two steps of for-loop and run again (F5) it runs much faster.
This does not happen around specific steps of my for loop or for a specific sheet so has nothing to do with my data and how it is structured.
Question: What are the possible reasons for this? Does pausing/step running cause something like memory to clear or any other possible scenario that makes this to run faster? And how I can fix this (Make it run as fast without the need to pause and so on.)?
Important Note
As stated above, using Select and Activate is not the main reason that for slowing down the process. I am sorry to say this again, but I know how to use explicit option, set ranges, set values instead of copying, etc. I have already changed my code to avoid selecting to see if that resolves the issue to no avail. It was still running slow until pausing, stepping through and running again. I would appreciate if you take a closer look at the problem and describe the reason behind the issue. Or at least, specifically let me know why this issue has something to do with Select/Activate.
This is part of a bigger main module that runs a program as a whole but this is the part that causes the slow down. I have used some optimizing techniques in the main module.
Sub Copy_ModelInputs(RootDir, FileName, TranID, ModOutDir, Angle, x, y, Method, TypeN)
'For each 150 storms, step through model event tabs and copy into runup tabs
FileName = RootDir & "NWM\" & FileName
FileName_output = ModOutDir & TranID & "_Outputs.xlsm"
Workbooks.Open (FileName)
FileName = ActiveWorkbook.Name
Workbooks.Open (FileName_output)
Filename2 = ActiveWorkbook.Name
'copy the angle into the doc sheet
Windows(FileName).Activate
Sheets("doc").Select
Range("c12").Select
ActiveCell.value = Angle
'File Transect ID
Range("c6").Select
ActiveCell.value = TranID
ActiveCell.Offset(1, 0).Select
ActiveCell.value = FileName_output
Range("I4").Select
ActiveCell.value = Now
Range("d8").Select
ActiveCell.value = x
ActiveCell.Offset(0, 2).Select
ActiveCell.value = y
'copy model output to input into excel spreadsheets
For i = 1 To 150
'input SWELs
Windows(Filename2).Activate
Sheets("Event" & i).Select
Range("B2:B300").Select
'Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Windows(FileName).Activate
Sheets("Event" & i).Select
Range("B7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'input H
Windows(Filename2).Activate
Range("C2:C300").Select
'Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
'Open runup template spreadsheet, copy H0
Windows(FileName).Activate
Range("D7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'input T
Windows(Filename2).Activate
Range("D2:D300").Select
'Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("G7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
If TypeN = 1 Or TypeN = 3 Then
'input deep
Windows(Filename2).Activate
Range("E2:E300").Select
'Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("H7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
'input local
Windows(Filename2).Activate
'If Method = 2 Then
If TypeN = 2 Then
Range("G2:G300").Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("I7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'input model
Windows(Filename2).Activate
Range("F2:F300").Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("H7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'input length
Windows(Filename2).Activate
Range("J2:J300").Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("J7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'input data
Windows(Filename2).Activate
Range("I2:I300").Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("K7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
'input sheet
Windows(Filename2).Activate
If TypeN = 3 Then
Range("H2:H300").Select
Selection.Copy
'Open template
Windows(FileName).Activate
Range("S7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
Windows(Filename2).Activate
Application.StatusBar = "Model Output copied Event " & i
Next i
ActiveWorkbook.Save
ActiveWindow.Close
ActiveWorkbook.Save
ActiveWindow.Close
Sheets("Summary").Select
End Sub
P.S. I wonder if Application.Cursor = xlWait would significantly improve performance in addition to other Application properties.
N.B. Please do not bring up Select, Activate and Copy Paste argument. It has been already covered numerous times in the lines above and comments :)
I had a similar issue with Microsoft 365 (64-bit Windows 10 Pro, i5 9th gen. processor, 16GB RAM. Excel file size 4MB, heavy use of VBA. 64-bit Excel).
Code Sub length - around 770 lines and it called several functions and branched to several subs.
The trouble being the software worked/works fine when using Office 2010 (32-bit Excel on the same machine - and for that matter, on my previous machine of considerably lower specs).
On the MS365 machine. At Runtime, code would stall for between 30 to 300 or more seconds at random places in the code but never if in debug mode.
I tried all the suggested tips like inserting DoEvents and adding Waits of one or two seconds at various locations in the code. Even uninstalled MS365 and reinstalled with 32-bit.
To cut a long story short, I broke the code into smaller parts and called them from within the original code block as in the sample below ...
Sub xyz()
.....
.....
Call SetDoCalcPages
Call SetDoCalcPages1(r, ACellAddr, errStr, NowStr, errAddr)
Call SetDoCalcPages2(temWatch, fYoung, temYoung, doneonce, fK4, ACellAddr, goQT)
.....
.....
End Sub
Around 70 lines of code were shifted to the three subs mentioned above.
I cannot say why, but this resolved the issue. At runtime, the computation is done at great speed.
One thing is sure. The code activates sheets and cells and sets the colour and fonts - all of which are frowned upon by suggestions on many forums. I can confirm that these do not have any bearing on the symptom - which was random long stalls in the execution of macro code at run time.
After spending fair amount of time on the problem I want to report back on the issue;
As #Slai suggested I tried to find the bottleneck of the code by printing time between each process. It turned out that there is a lag between each step of the for loop that then disappears after Debug/Continue.
Also Application properties are not changing before and after Debug/Continue.
What #YowE3K proposed about running the macro from the Immediate Window actually resolved the issue. Somehow, it seems activated VBE is the solution.
I also tried saving my main workbook as * .xlsb which resolves the issue. However, it causes slower loading of the file at the beginning but in total overhead time-cost is not substantial.
I know immediate window is different in scope. It assumes global (Public) scope if nothing is running. Otherwise, it will be in the Application scope. I would appreciate if someone can explain in detail that in what way activated VBE is different from running the macro from a command button.
For reference, I want to also include in the answer that not disabling Application.ScreenUpdating can affect time of execution significantly. FWIW, select, activate and similar practices should be avoided if possible (programming-wise, they are always avoidable).

Excel delete formula but keep values witha lot of rows

I'm working with a macro excel. I'm trying to delete the formula but keep the values of the cells as it makes filtering/sorting so slow. I already tried the following:
Range("A2:E70000").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks :=False, Transpose:=False
and
Sheet1.Range("A2:E70000").Values = Sheet1.Range("A2:E70000").Values
but both of them take too long to finish(about 30mins. to complete). Are there any faster ways to do this? Thanks in advance.
Bracket your code with
Application.ScreenUpdating = False
and
Application.ScreenUpdating = True
and you should see performance improve dramatically.
Visuals like selecting the cells are going to slow this down considerably. Also selecting to row 70,0000? If this is actually the case then fair enough, but if not then why?
Have edited your first code slightly. This will stop the screen updating until finished, won't 'select' any cells (visually) and will find the last actual row that is in use instead of just blanket selecting a range in hope it gets everything.
Try:
Application.ScreenUpdating = False
with Sheet1.Range("A2:E" & Sheet1.Range("E" & .Rows.Count).End(xlUp).Row)
.copy
.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks :=False, Transpose:=False
end with
Application.ScreenUpdating = True

VBA across multiple worksheets

I perform this code 11 times on my macro
Windows("LOFORM.xls").Activate
Sheets("Becke").Select
Range("A6:J25").Select
Selection.Copy
Windows("Comp Reform LO.xls").Activate
Sheets("Becke").Select
Range("A6").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
for all different sheets. Instead of having this entire code 11 separate time with different sheet names can I condense it?
This is much mroe compact, but also as it avoids all selects, activates and working with the clip board it will also be much faster.
Windows("Comp Reform LO.xls").Sheets("Becke").Range("A6:J25") = _
Windows("LOFORM.xls").Sheets("Becke").Range("A6:J25")
If you have this code 11 times through out your code you should turn it into its own sub, and simply call it as CopyValues() or something.
Or if the code 11 times is similar but different locations you could also pass in the Workbook and worksheet params:
Sub SampleCopyValues(DestinationWorkSheet As Worksheet)
DestinationWorkSheet.Range("A6:J25") = _
Windows("LOFORM.xls").Sheets("Becke").Range("A6:J25")
End Sub
Then you could call it as SampleCopyValues(Windows("Comp Reform LO.xls").Sheets("Becke"))