Copying range to new workbook - vba

I have come across some code to copy a range to a new workbook, but I'm not sure why it works.
Worksheets("Short Form").Copy
Set wb = ActiveWorkbook
How does this copy the worksheet 'Short Form' to a new workbook when all that the code says is assign the active workbook to the reference 'wb'? It doesn't even employ the .add method. Right now I want to paste values only to this new workbook, but not quite sure how to do so because I don't understand this block of code.

Try this - as the following manual steps are the same as your code snippet:
1.Open a blank workbook
2.Press record macro
3.Right click the Sheet1 workbook tab
4.Select "Move or Copy"
5.In the "To book" combo select (new book)
6.Check the "Create a copy" box so that the window now looks like this:
7.Stop the recorder
8.Go and find your recorded code ...and voila....mine looks like this
Option Explicit
Sub Macro1()
'
' Macro1 Macro
'
'
Sheets("Sheet1").Select
Sheets("Sheet1").Copy
End Sub
Your code is the same as what these manual steps describe.
You must have a line Dim wb as workbook somewhere or it would not run.
This line Set wb = ActiveWorkbook will then make the object wb equal to the new workbook that you have copied into, as it is active, so you can do further operations on it. You can easily switch the workbook that wb is pointed at:
Sub Macro1()
Dim wb As Workbook
ThisWorkbook.Sheets("Sheet1").Copy
Set wb = ActiveWorkbook
MsgBox wb.Name
ThisWorkbook.Activate
Set wb = ActiveWorkbook
MsgBox wb.Name
End Sub
BUT
In my production code I generally never use Set x To ActiveWorkbook I always name the workbook and then use Set x To Workbooks("DefiniteName")
WITHOUT USING CLIPBOARD
If you want to avoid using the clip board then the following example shows how to move values-only data without using paste:
Sub WithoutPastespecial()
Dim firstRange As Range
Set firstRange = ThisWorkbook.Worksheets("Short Form").Range("S4:S2000") 'can change S4:S2000 to the range you want to copy
Dim newBk As Workbook
Dim secondRange As Range
Set newBk = Workbooks.Add
Set secondRange = newBk.Worksheets("Sheet1").Range("A1")
With firstRange
Set secondRange = secondRange.Resize(.Rows.Count, .Columns.Count)
End With
secondRange.Value = firstRange.Value
End Sub

Note this is not copying a Range rather the entire worskheet :)
If you use the method:
Worksheets("Short Form").Cells.Copy
Then you will copy only the cells, not the entire worksheet, and this method will NOT create a new workbook. You can tell it to add a workbook when necessary.
Here is an example:
Option Explicit
Sub CopyNew()
Dim wbNew As Workbook
Dim wb As Workbook
Set wb = ThisWorkbook 'It is a good idea to explicitly control workbooks using either a defined variable like "wb" or the "ThisWorkbook" object, instead of using "ActiveWorkbook" or referring to files by name.
Application.CutCopyMode = False
wb.Sheets("Short Form").Cells.Copy
'Add a new workbook for the values:
Set wbNew = Workbooks.Add
wbNew.Sheets(1).Cells.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub

Related

Excel synchronize workbooks with vba

I'd like to ask if you could help me with copying some worksheet data from workbook A into my active workbook (workbook B)
I have the following code in the main workbook to copy the data from workbook A
Public Sub Worksheet_Activate()
test
End Sub
Sub test()
Dim Wb1 As Workbook
Dim MainBook As Workbook
'Open All workbooks first:
Set Wb1 = Workbooks.Open("Z:\Folder\WorkbookA.xlsm")
'Set MainBook = Workbooks.Open(Application.ActiveWorkbook.FullName)
Set MainBook = Application.ActiveWorkbook
'Now, copy what you want from wb1:
Wb1.Sheets("Projekte").Cells.Copy
'Now, paste to Main worksheet:
MainBook.Worksheets("Projekte").Range("A1").PasteSpecial xlPasteAll
Application.CutCopyMode = False
'Close Wb's:
Wb1.Close SaveChanges:=False
End Sub
I know, that it opens worksheet A and that it highlights and copys the data.
The script wont paste it into worksheet B (where the script is executed from)
Anybody know what i did wrong?
Kindest regards, and thanks for any help !
You should set the Mainbook (destination) first before the origin (if you're going to use ActiveWorkbook).
'Set MainBook First
Set MainBook = ThisWorkbook
'Open All workbook:
Set Wb1 = Workbooks.Open("Z:\Folder\WorkbookA.xlsm")
Just for clarity, it's just me being OC on this one.
you have to properly reference your workbook and worksheet objects
if you have to paste the whole content of range (including formatting, comments, ...), then you want to code like follows (explanations in comments):
Option Explicit
Sub test()
Dim targetSheet As Worksheet
Set targetSheet = ActiveSheet 'store currently active sheet
Workbooks.Open("Z:\Folder\WorkbookA.xlsm").Sheets("Projekte").UsedRange.Copy Destination:=targetSheet.Range("A1") ' open the wanted workbook and copy its "Projekte" sheet used range to 'targetSheet (i.e.: the sheet in the workbook where it all started) from its cell A1
ActiveWorkbook.Close SaveChanges:=False ' close the currently active workbook (i.e. the just opened one)
End Sub
if you only need to paste values, then this is the way to go (much faster!):
Option Explicit
Sub test()
Dim targetSheet As Worksheet
Set targetSheet = ActiveSheet 'store currently active sheet
With Workbooks.Open("Z:\Folder\WorkbookA.xlsm").Sheets("Projekte").UsedRange ' open the wanted workbook and reference its sheet "Projekte" used range
targetSheet.Range("A1").Resize(.Rows.Count, .Columns.Count).Value = .Value
.Parent.Parent.Close SaveChanges:=False 'close the parent workbook of referenced range (i.e., the newly opened workbook)
End With
End Sub
My recommendation is never to use ActiveWorkbook.
In most cases when people use ActiveWorkbook they actually meant to use ThisWorkbook. The difference is:
ActiveWorkbook is the currently selected one which is "on top of the screen" in exact that moment when your code runs. That can be any workbook the user just clicked on while your code runs. So you never can be 100% sure to get the right workbook.
ThisWorkbook is the actual workbook your code runs at the moment. And this doesn't change ever. So this is a well defined reference and no gamble about which workbook is on top at the moment.
About why your approach did not work
Set Wb1 = Workbooks.Open("Z:\Folder\WorkbookA.xlsm") 'this line makes WorkbookA the active one
Set MainBook = Application.ActiveWorkbook 'this makes MainBook = WorkbookA
Therefore a simple Set MainBook = Application.ThisWorkbook should work here.
Another recommendation
Sheets and Worksheets is not the same. Make sure you never use Sheets when you can use Worksheets.
Sheets contains worksheets and charts
Worksheets contain only worksheets
An example Sheets(1).Range("A1") fails if it is a chart.

Problems with ThisWorkbook when using Excel Add In

I have the following lines of code that essentially copy and paste a sheet from one workbook into another:
Dim wb As Workbook, CopyFromWbk As Workbook, CopyToWbk As Workbook
Dim ShToCopy As Worksheet, targetSheet As Worksheet, sht As Worksheet
Dim Answer As VbMsgBoxResult
Answer = MsgBox("OPEN", vbOKCancel, "OPEN")
If Answer = vbCancel Then Exit Sub
Set wb = FileDialog_Open()
If wb Is Nothing Then End
Call Sheet_Selector
Set CopyFromWbk = wb
Set ShToCopy = CopyFromWbk.ActiveSheet
Set CopyToWbk = ThisWorkbook
ShToCopy.Cells.Copy
Set targetSheet =
CopyToWbk.Sheets.Add(After:=CopyToWbk.Sheets(CopyToWbk.Sheets.Count))
targetSheet.Range("A1").PasteSpecial Paste:=xlPasteValues,
Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
targetSheet.Name = "Sheet2"
CopyFromWbk.Close False
The problem is that when you use an Excel Add-In you have to be careful about using ThisWorkbook as it is actually addressing the Add In and not my workbook. I can't use "ActiveWorkbook" as it addresses the workbook I am copying from not copying to.
So I am struggling to figure out how to fix this. Note this code works perfectly when not used in the Excel Add In (due to the fact that I am using ThisWorkbook).
EDIT: All I had to do was move Set CopyToWbk = ActiveWorkbook to the top of the code and it worked of course.

Excel Macro: Setting a variable for a workbooks location?

I need to write a macro script that will copy data from one xml workbook and paste the values to another workbook. I've written the below macro that works fine, but i need to run this every week for several different documents so it means i have to replace the document name for each run.
Here's what i have so far:
Sub copying()
''''''Section 1''''''
Workbooks("Results_2561").Activate 'workbook i'm copying from
Range("B27:B41").Select
Selection.Copy
Workbooks("Overall_Results").Activate 'workbook i'm pasting to
Range("G2").PasteSpecial
''''''Section 2''''''
Workbooks("Results_2561").Activate
Range("C27:C41").Select
Selection.Copy
Workbooks("Overall_Results").Activate
Range("C2").PasteSpecial
''''''Section 3''''''
Workbooks("Results_2561").Activate
Range("I28:I40").Select
Selection.Copy
Workbooks("Overall_Results").Activate
Range("G17").PasteSpecial
''''''Section 4''''''
Workbooks("Results_2561").Activate
Range("J28:J40").Select
Selection.Copy
Workbooks("Overall_Results").Activate
Range("C17").PasteSpecial
End Sub
...
and that's only half the script. Is there a way i can declare a variable at the start and set it as the Workbooks file path so i can call that instead of typing and retyping it over and over again?
Preferably without using something like
Dim book1 as Workbook
Set book1 = Workbooks.Open("C://Results_2561.xlsm")
..as this keeps opening and closing the document when i run the script.
Thanks
since you're only interested in copying values you could use this helper Sub
Sub CopyValues(rngToCopyFrom As Range, rngToCopyTo As Range)
With rngToCopyFrom
rngToCopyTo.Resize(.Rows.COUNT, .Columns.COUNT).Value = .Value
End With
End Sub
to be exploited in your main code like follows:
Sub main()
Dim wsTo As Worksheet
Set wsTo = Workbooks("Overall_Results").ActiveSheet '<--| set the worksheet to paste values to
With Workbooks("Results_2561").ActiveSheet '<--| reference the worksheet to copy values from
CopyValues .Range("B27:B41"), wsTo.Range("G2")
CopyValues .Range("C27:C41"), wsTo.Range("C2")
CopyValues .Range("I28:I40"), wsTo.Range("G17")
CopyValues .Range("J28:J40"), wsTo.Range("C17")
End With
End Sub
should your relevant workbooks have more than one sheet, then just substitute
ActiveSheet
with
Worksheets("myRelevantShetName") '<--|change "myRelevantShetName" to the actual name of the relevant worksheet in each workbook
First of all, you don't have to Activate workbook every time when you want to copy/paste something. Just declare it in Range() property, for example:
''''''Section 1''''''
Workbooks("Results_2561").Sheets(1).Range("B27:B41").Copy
Workbooks("Overall_Results").Sheets(1).Range("G2").PasteSpecial
You can set Workbook as variable like:
Sub copying()
Dim wb1 As Workbook, wb2 As Workbook
Set wb1 = Workbooks("Results_2561")
Set wb2 = Workbooks("Overall_Results")
''''''Section 1''''''
wb1.Sheets(1).Range("B27:B41").Copy
wb2.Sheets(1).Range("G2").PasteSpecial
End Sub
Finally, as #A.S.H suggested, you can add a file dialog where you point which files you want to use. I have put it in some function (don't forget to put it in the same project as your copying macro):
Function strPath() As String
Dim intResult As Integer
Application.FileDialog(msoFileDialogFilePicker).Title = "Select file"
intResult = Application.FileDialog(msoFileDialogFilePicker).Show
If intResult <> 0 Then
strPath = Application.FileDialog(msoFileDialogFilePicker).SelectedItems(1)
End If
End Function
So your final code for Section 1 would look like:
Sub copying()
Dim wb1 As Workbook, wb2 As Workbook
MsgBox "Show file to copy form."
Set wb1 = Workbooks.Open(strPath())
MsgBox "Show file to paste in."
Set wb2 = Workbooks.Open(strPath())
''''''Section 1''''''
wb1.Sheets(1).Range("B27:B41").Copy
wb2.Sheets(1).Range("G2").PasteSpecial
End Sub

VBA Error 'Subscript out of Range'

I am trying to create a copy of a large macro enabled (xlsm) file in xlsx format.
Sub Button1_Click()
Dim wb As Workbook
Set wb = Workbooks.Open("C:\original.xlsm")
Dim mySheetList() As String
ReDim mySheetList(0 To (ThisWorkbook.Sheets.Count) - 1)
Dim a As Integer
a = 0
For Each ws In ActiveWorkbook.Worksheets
mySheetList(a) = ws.Name
a = a + 1
Next ws
'actually save
Worksheets(mySheetList).Copy
ActiveWorkbook.SaveAs Filename:="ORIGINAL_COPY.xlsx" 'default ext
wb.Close
End Sub
I am getting subscript out of range error at following line:
mySheetList(a) = ws.Name
You are sizing the array with ThisWorkbook.Sheets but the loop use ActiveWorkbook.Worksheets. You need the same reference to avoid issues when multiple workbooks are opened.
You're using 4 different references to workbooks:
wb, ThisWorkbook and ActiveWorkbook are not necessarily the same thing. Furthermore, when you use Worksheets without prefixing it with a workbook reference, you're implicitly referencing the Activeworkbook. And, when you use Worksheets.Copy without any arguments, you're implictly creating a new workbook.
Currently, if ThisWorkbook has fewer sheets than original.xlsm, then your array will not be large enough to accommodate indexes larger than the count of sheets in ThisWorkbook. That is what is causing your out of bounds error.
I've adjusted the code. This will open the XLSM, copy the sheets, save the new XLSX workbook, and close the original XLSM, leaving the new XLSX workbook open.
Sub Button1_Click()
Dim wbOriginal As Workbook
Dim wbOutput As Workbook
Set wbOriginal = Workbooks.Open("C:\original.xlsm")
Dim mySheetList() As String
ReDim mySheetList(0 To (wbOriginal.Sheets.Count) - 1)
Dim a As Integer
a = 0
For Each ws In wbOriginal.Worksheets
mySheetList(a) = ws.Name
a = a + 1
Next ws
'Unfortunately, Worksheets.Copy isn't a function, so it doesn't
'return the workbook that it creates, so we have to execute the
'copy, then find the activeworkbook
Worksheets(mySheetList).Copy
Set wbOutput = ActiveWorkbook
'actually save
wbOutput.SaveAs Filename:="ORIGINAL_COPY.xlsx" 'default ext
wbOriginal.Close
End Sub
Why bother with all that looping?
Sub MM()
Dim sourceWB As Excel.Workbook
Set sourceWB = Workbooks.Open("C:\Original.xlsm")
sourceWB.SaveAs "C:\ORIGINAL_COPY.xlsx", FileFormat:=xlOpenXMLWorkook
sourceWB.Close False '// Optional
End Sub
The .SaveAs() method would be far more effective.
As mentioned in other answers, your issue seems to be with wb, ActiveWorkbook and ThisWorkbook being used interchangeably when they are actually different things.
wb is a workbook object that has been set to "C:\original.xlsm". It will always refer to that workbook unless you close the workbook, empty the object, or assign a new object to it.
ActiveWorkbook refers to the workbook that is currently active in Excel's forefront window. (i.e. The workbook you can see on your screen)
ThisWorkbook refers to the workbook in which the currently executing code belongs to. To quickly explain the difference:
Workbook A is the only workbook open, and has some code in to open another workbook (let's call it Workbook B).
At the moment, Workbook A is the ActiveWorkbook.
The code in workbook A starts running, workbook A is now the ActiveWorkbook and ThisWorkbook (because the running codes resides in this workbook)
The code opens Workbook B, which naturally opens in the forefront of Excel. Now Workbook B is the ActiveWorkbook and Workbook A is still the ThisWorkbook
Hopefully that clears it up a bit for you...

Make macro run in specific workbook

This seems like such a simple request, but I can't seem to find any answers online.
I have two open workbooks (lets say A and B). All I want to do is run a macro that I have created in Workbook B and run it (by click a shape that I've assigned a macro to) through Workbook A, but the macro running in Workbook B
The macro I created for Workbook B is...
Sub HistoricalDataShift()
Dim ws As Worksheet
For Each ws In Sheets
ws.Activate'
Rows("18:1000").Select
Selection.Copy
Range("A19").Select
ActiveSheet.Paste
Rows("15:15").Select
Selection.Copy
Range("A18").Select
ActiveSheet.Paste
Next ws
End Sub
Then I created a second macro in Workbook B that has...
Sub ApplicationRun()
Application.Run ("WorkbookB.xlsm!HistoricalDataShift")
End Sub
But each time I try the macro keeps running in Workbook A.
If I could get a helping hand that would be appreciated.
All you need to do is rewrite HistoricalDataShift to operate on itself. It should work just fine then.
Sub HistoricalDataShift()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
For Each ws In wb.Worksheets
ws.Activate '
ws.Rows("18:1000").Select
Selection.Copy
ws.Range("A19").Select
ActiveSheet.Paste
ws.Rows("15:15").Select
Selection.Copy
ws.Range("A18").Select
ActiveSheet.Paste
Next ws
End Sub
Also to make your code work better, you can do this:
Sub HistoricalDataShift()
Dim wb As Workbook
Set wb = ThisWorkbook
wb.Activate
Dim ws As Worksheet
For Each ws In wb.Worksheets
Call ws.Rows("18:1000").Copy(ws.Range("A19"))
Call ws.Rows("15:15").Copy(ws.Range("A18"))
Next ws
End Sub
Try declaring your workbook object?
Dim wkbkA as workbook
set wkbkA = 'directory here
then run your code in a With... End With
With wkbkA
.range('etc.........
End With
In this short example, we assume that WorkbookB.xlsm is initially the only open workbook and hosts this macro:
Sub HistoricalDataShift()
Dim wkbB As Workbook
Dim wkbA As Workbook
Set wkbB = ThisWorkbook
Workbooks.Open Filename:="WorkbookA"
Set wkbA = ActiveWorkbook
wkbA.Sheets(1).Range("B9").Value = "whatever"
End Sub
You can use Worksheets("<worksheetname>")
e.g. Worksheets("A").Activate
or cv = Worksheets(Worksheet).Cells(DataSeriesEnd, rc_index)
where Worksheet holds the sheet name.
etc.
This snippet will go through the entire collection of worksheets, where w is the current worksheet name :-
For Each w In Worksheets
.......
Next w