VBA Macro to copy and paste sheets into new workbook - vba

I do a report every day in which I have to copy and paste several sheets into a new workbook titled Report (today's date).
In my report I have 4 sheets : Customers, Orders, Country, ID.
Customer and Country are a simple copy and paste from the master file, but Orders and ID are filtered data from one of my sheets in the master file. Orders is filtered to "Complete" and Id is everything except ID 200 and 500.
I tried building a macro based on this solution found here :
http://www.hivmr.com/db/ack717pc8f88jpdsf7838pcaspkcsdmd
The copy and paste works but I am unable to copy and paste multiple sheets/ rename sheets and filter the data.
Edit:
Sub CopyInNewWB()
'has been tested
Dim newWS, WS As Worksheet
Application.ScreenUpdating = False
Set WS = ThisWorkbook.Sheets("Sheet1")
Set newWS = Workbooks.Add.Sheets("Sheet1")
WS.Cells.Copy
newWS.Cells.PasteSpecial xlValues Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub

No clue how your filtered sheets are set up, but this method will copy the sheets in your master exactly how they are currently filtered to a new workbook:
Sub CopyInNewWB()
Dim wbO As Workbook, wbN As Workbook
On Error GoTo ErrHandler
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
Set wbO = ActiveWorkbook
Set wbN = Workbooks.Add
wbO.Sheets("Customers").Copy wbN.Sheets(1)
wbO.Sheets("Orders").Copy wbN.Sheets(2)
wbO.Sheets("Country").Copy wbN.Sheets(3)
wbO.Sheets("ID").Copy wbN.Sheets(4)
wbN.Sheets("Sheet1").Delete
wbN.Sheets("Customers").Activate
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
ErrHandler:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
End Sub

Related

VBA Code takes too long to Run

Please see the below VBA Code that I've came up with. Essentially, this is to open another workbook, Unmerge the Rows, Copy the Columns and Paste it into my Active Workbook. However after copy pasting, when the code runs to the CalculationAutomatic line, it takes around 15mins. Is there any other way to make it more efficient?
Thank you
Option Explicit
Sub ImportRemarks()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Dim PLPath As String
PLPath = Sheets("Instructions").Range("C16").Text
Dim wbThis As Workbook
Dim wbTarget As Workbook
Set wbThis = ActiveWorkbook
Set wbTarget = Workbooks.Open(PLPath)
wbTarget.Worksheets("Performance List").Select
Rows("1:2").Select
Selection.UnMerge
wbThis.Worksheets("keys").Range("I:I").Value =
wbTarget.Worksheets("Performance List").Range("F:F").Value
wbThis.Worksheets("keys").Range("J:L").Value =
wbTarget.Worksheets("Performance List").Range("P:R").Value
wbThis.Activate
Application.CutCopyMode = False
wbTarget.Close savechanges:=False
ActiveWorkbook.Sheets("Instructions").Select
Range("C22").Select
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Maybe something like as follows for starters. Ideally, the optimization steps would go in their own subs. One to switch on optimization at the start and the other to return everything to how it was at the end (or on error).
As requested, this shows you how to remove the .Select parts of your code by using With statements. It also includes a safe exit, in case of error, to switch back on everything you disabled.
Option Explicit
Public Sub ImportRemarks()
Dim PLPath As String, wbThis As Workbook, wbTarget As Workbook
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo Errhand
Set wbThis = ThisWorkbook
Set wbTarget = Workbooks.Open(PLPath)
PLPath = wbThis.Worksheets("Instructions").Range("C16").Text
wbTarget.Worksheets("Performance List").Rows("1:2").UnMerge
With wbThis.Worksheets("keys")
.Range("I:I") = wbTarget.Worksheets("Performance List").Range("F:F")
.Range("J:L") = wbTarget.Worksheets("Performance List").Range("P:R")
End With
wbTarget.Close savechanges:=False
With wbThis
.Activate
' .Worksheets("Instructions").Range("C22").Activate '<=consider whether this is needed?
End With
Errhand:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
More info on optimization here:
https://www.thespreadsheetguru.com/blog/2015/2/25/best-way-to-improve-vba-macro-performance-and-prevent-slow-code-execution
http://www.cpearson.com/excel/optimize.htm

buttons not copying with sheet excel vba

I have some macros that copy my sheet in excel,and delete certain data. Unfortunately the buttons to which the macros are assigned do not copy over when the macros are run.
Sub CandD()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim sh As Shape, strtSh As Worksheet
Set strtSh = ActiveSheet
Sheets("BM Condition").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = "BM Condition" & Sheets.Count - 1
Range("E14:E33,I14:I33,M14:M33").ClearContents
For Each sh In ActiveSheet.Shapes
sh.Delete
Next sh
strtSh.Select
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
This is the macro I am using. I have very limited VBA experience and am not finding google very helpful. Could someone recommend a fix for my buttons not copying over?
EDIT: I forgot to mention that when manually copying the buttons remain. I am not sure why this is.
As FunThomas mentioned, I've tried and tested the following without any errors:
Sub CanD()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim sh As Shape, strtSh As Worksheet
Set strtSh = ActiveSheet
Sheets("BM Condition").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = "BM Condition" & Sheets.Count - 1
Range("E14:E33,I14:I33,M14:M33").ClearContents
strtSh.Select
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

VBA Excel: Deleting all charts and graphs in a workbook, except one

I have a macro that generates a lot of worksheets and charts. There's also various subroutines that run so the names and quantity of each worksheet/chart generated is never the same. What is constant is my HOME worksheet which is the UI for the user and I want it to be unaffected.
I found a similar question here about deleting all worksheets except the one you are working with (i.e. HOME). Here's what I have so far.
Sub ZRESET()
Dim ws As Worksheet, wb As Workbook
Set wb = ActiveWorkbook
Sheets("HOME").Select
Application.DisplayAlerts = False
For Each ws In wb.Worksheets
If ws.Name <> "HOME" Then
ws.Delete
End If
If Chart.Name = "" Then
Charts.Delete
End If
Next
Application.DisplayAlerts = True
Range("B5:E5,B9:E9,B13:E13,B14:E14").ClearContents
Range("A1").Select
End Sub
The worksheets delete fine, the hang up I have is the charts. I tried various attempts to remove charts and sometimes they work (i.e placing Charts.Delete outside of a FOR loop and IF statement). But this requires me to actually have a chart in the workbook. Sometime the user can just develop worksheets but no charts.
Any advice to continue my goal of deleting SHEETS and/or CHARTS, while keeping my HOME sheet intact?
Option Explicit
Sub GetRid()
Dim ASheet As Worksheet
Dim AChart As Chart
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'** first scan for and delete all non HOME worksheets ***
For Each ASheet In ActiveWorkbook.Worksheets
If UCase(ASheet.Name) <> "HOME" Then
ASheet.Delete
End If
Next
'** Now scan and delete any ChartSheets ****
For Each AChart In ActiveWorkbook.Charts
AChart.Delete
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Option Explicit
Sub AllSheetsAndcharts()
Dim AChart As ChartObject
Dim ASheet As Worksheet
Application.DisplayAlerts = False
For Each ASheet In ActiveWorkbook.Worksheets
If UCase(ASheet.Name) <> "HOME" Then
For Each AChart In ASheet.ChartObjects
AChart.Delete
Next
ASheet.Delete
End If
Next
Application.DisplayAlerts = False
End Sub

Looping a copy to new workbook function across multiple tabs based on tab names in cell values

I want to copy data from each tab in a spreadsheet and save it as new workbooks. The original workbook has many tabs (approx 50) and one of these tabs set up for the macro to run data from, as there may be new tabs added in the future. The macro data tab contains the file location for each new workbook, the name of the tab and also some information used by another macro to e-mail these newly created workbooks to relevant parties.
The issue is getting the macro to recognize the tab names for finding the range to copy, as the tab names are listed in a cell. I am unsure if it is possible to use this list, or whether I add a sheet at the end to loop through all the sheets from a specified start location until that one with an if.
Sub Datacopy()
Dim ws As Worksheet
With Application
.ScreenUpdating = False
End With
Application.DisplayAlerts = False
Set ws = Sheets("email")
For Each Cell In ws.Columns("B").Cells
Dim file1 As String
file1 = Cell.Offset(0, 3).Text
Sheets("cell.value").Range("A1:L500").Copy
Workbooks.Add.Worksheets("Sheet1").Range("A1").PasteSpecial (xlPasteAllUsingSourceTheme)
Worksheets("Sheet1").Range("A1").PasteSpecial (xlPasteComments)
ActiveWorkbook.SaveAs Filename:=file1
ActiveWorkbook.Close
Next Cell
Application.DisplayAlerts = True
With Application
.ScreenUpdating = True
End With
MsgBox ("Finished making files!")
End Sub
Something like this should work for you. Note the following:
Code assumes that on sheet "email" it has a header row which is row 1 and the actual data starts on row 2.
It checks to see if the B column cell is a valid worksheet name in the workbook
I have verified that this code works properly and as intended based on your original post:
Sub Datacopy()
Dim wb As Workbook
Dim wsData As Worksheet
Dim wsTemp As Worksheet
Dim rSheetNames As Range
Dim rSheet As Range
Set wb = ActiveWorkbook
Set wsData = wb.Sheets("email")
Set rSheetNames = wsData.Range("B2", wsData.Cells(Rows.Count, "B").End(xlUp))
If rSheetNames.Row < 2 Then Exit Sub 'No data
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
For Each rSheet In rSheetNames
If Not Evaluate("ISERROR('" & rSheet.Text & "'!A1)") Then
Set wsTemp = Sheets.Add
Sheets(rSheet.Text).Range("A1:L500").Copy
wsTemp.Range("A1").PasteSpecial xlPasteAllUsingSourceTheme
wsTemp.Range("A1").PasteSpecial xlPasteComments
wsTemp.Move
ActiveWorkbook.SaveAs rSheet.Offset(, 3).Text
ActiveWorkbook.Close False
End If
Next rSheet
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
MsgBox "Finished making files!"
End Sub

Copying Existing Sheets in Excel Slows down my VBA code significantly

I've been building a program to create invoices dependent on the number of clients/owners my company is interacting with. For every one client, we potentially have multiple owners, what we do is create an individual invoice for each owner. My problem is that the code is designed to copy a template sheet and then edit it accordingly, this copying process slows down my code to between 10 and 20 seconds (I have a timer in the code).
Is there any other way I could more efficiently do this? I have an image in the sheet which does not copy over well when I simply try to create a new sheet and then copy/paste from the template sheet. Any other ideas?
Thanks!
Edit:
Private Sub CommandButton1_Click()
Dim t As Single
t = Timer
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Sheets("Client Invoice Template").Visible = True
Sheets("Client Invoice Template").Visible = True
Sheets("Client Invoice Template").Copy Before:=Sheets(3)
Sheets("Client Invoice Template (2)").Name = "Client Invoice"
Sheets("Client Invoice Template").Visible = False
Sheets("Select").Select Application.Calculation = xlCalculationAutomatic
MsgBox Timer - t
End Sub
Based on the method in my comment, I did a test with my own (very simple) template that is shown below for full disclosure:
Method 1 (Your Code)
it took 0.09375 seconds to complete.
EDIT: Method 2 (based on Bruce Wayne's Comment)
it took .015625 seconds to complete! That is 6xs as fast!
Sub CommandButton3_Click()
Dim t As Single
t = Timer
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim wsT As Worksheet, ws As Worksheet
Set wsT = Sheets("Client Invoice Template")
wsT.Visible = True 'view template
Set ws = Sheets.Add(Before:=Sheets(3)) 'add new sheet
With wsT
'copy row height and column width
'row height
Dim rng as Range
For each rng in .range("A1:A100")
ws.Rows(rng.Row).RowHeight = rng.Height
Next
'column width
For each rng in .Range("A1:D1")
ws.Columns(rng.Column).ColumnWidth = rng.Width
Next
wsT.Range("A1:D100").Copy 'copy template data (change range accordingly)
With ws
.Range("A1").PasteSpecial xlPasteValues 'past values (change range accordingly)
.Range("A1").PasteSpecial xlPasteFormats 'past formats (change range accordingly)
.Pictures.Insert("C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg").Select
With .Shapes("Picture 1")
.Top = ws.Range("B2").Top 'adjust as needed
.Left = ws.Range("B2").Left 'adjust as needed
.Height = 126.72 'adjust as needed
.Width = 169.2 'adjust as needed
End With
.Name = "Client Invoice"
End With
wsT.Visible = False
Application.Calculation = xlCalculationAutomatic
Debug.Print Timer - t
End Sub
Method 3 (Based on My Comment)
it took 0.03125 seconds to complete! That is 3Xs as fast!
Code is below:
Sub CommandButton2_Click()
Dim t As Single
t = Timer
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim wsT As Worksheet, ws As Worksheet
Set wsT = Sheets("Client Invoice Template")
wsT.Visible = True 'view template
Set ws = Sheets.Add(Before:=Sheets(3)) 'add new sheet
wsT.Range("A1:D100").Copy 'copy template data (change range accordingly)
With ws
.Range("A1").PasteSpecial xlPasteValues 'past values (change range accordingly)
.Range("A1").PasteSpecial xlPasteFormats 'past formats (change range accordingly)
End With
wsT.Shapes("Picture 1").Copy 'change to your picture name accordingly
With ws
.Range("B2").PasteSpecial 'paste to cell (change range accordingly)
.Name = "Client Invoice" 'rename
End With
wsT.Visible = False
Application.Calculation = xlCalculationAutomatic
Debug.Print Timer - t
End Sub