I want to be able to select a workbook and then copy the content from that workbook (sheet 1) into my current active workbook where I run the macro. I've been looking at some answers here on StackOverflow to similar questions and got the following code (see below).
The selection of a file is currently working fine, but when I run the macro it throws an error
Runtime error "438": Object does not support that method or property`
(please note, that the error comes in my native language and is just translated by me)
Sadly no object is marked that he relates to, so I can't really make out what problem he has. Yet, I guess it is a problem with the PasteSpecial in the last line of function GetTemplateData, but that code should be alright (what is it supposed to do? Save the data into the first sheet of the give workbook activeWorkbook) and pass the reference back go GeneratedValues-routine.
Option Explicit
Private Sub GenerateValues()
'Application.ScreenUpdating = False
'Application.DisplayAlerts = False
Dim activeWorkbook As Workbook
Dim activeWorksheet As Worksheet
Set activeWorkbook = Application.activeWorkbook
Set activeWorksheet = GetTemplateData(activeWorkbook)
activeWorkbook.Save
End Sub
'Get The Template Data
Private Function GetTemplateData(activeWorkbook As Workbook) As Worksheet
Dim templateWorkbook As Workbook
'Grab the Template Worksheet
Set templateWorkbook = UseFileDialogOpen
'Select all Content
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Copy
'activeWorkbook.Sheets(activeWorkbook.Sheets.Count).Range("A1", Cells.End(xlDown) & Cells.End(xlRight)).PasteSpecial xlPasteValues
activeWorkbook.Sheets(1).Range("A1", Cells.End(xlDown) & Cells.End(xlRight)).PasteSpecial xlPasteValues
End Function
'From https://learn.microsoft.com/de-de/office/vba/api/excel.application.filedialog
'Select the Workbook containing the Exported Template-Stories by User Selection
Function UseFileDialogOpen() As Workbook
Dim lngCount As Long
Dim filePath As String
Dim templateBook As Workbook
' Open the file dialog
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = False
.Show
Set templateBook = Workbooks.Open(.SelectedItems(1))
' Display paths of each file selected
'For lngCount = 1 To .SelectedItems.Count
' MsgBox .SelectedItems(lngCount)
'Next lngCount
End With
templateBook
End Function
I believe all of your problems originate here:
Private Sub GenerateValues()
'Application.ScreenUpdating = False
'Application.DisplayAlerts = False
Dim activeWorkbook As Workbook
Dim activeWorksheet As Worksheet
Set activeWorkbook = Application.activeWorkbook
Set activeWorksheet = GetTemplateData(activeWorkbook)
activeWorkbook.Save
End Sub
ActiveWorkbook is a defined "variable" in VBA, so it is confused as to why you are trying to reassign it. Try using a different variable name instead.
Note: although ActiveWorksheet is not a defined variable in VBA, it is close in name to ActiveSheet, so I would also change that variable name to something different just so to not confuse you when writing future code.
You could try something similar to this:
Sub CopyContentsFromOtherWorkbook()
Dim wb As Workbook
Dim twb As Workbook
filePath = "C:\File.xlsx"
Set wb = Workbooks.Open(filePath)
wb.Sheets(1).Range("A1:Z10000").Copy
Set twb = ThisWorkbook
twb.Sheets(1).Range("C1").PasteSpecial xlPasteValues
wb.Close
twb.Save
End Sub
Related
I have a number of scripts that are in a module in my Personal.xlsb file. It's kept hidden, but in this script, the idea is that you run it from within a different workbook each time. It opens a separate workbook (source.xlsx), copies a range from it, pastes into the original workbook, and then closes source.xlsx.
When it comes to the "ThisWorkbook.ActiveSheet.Paste" part, it's pasting it into the Personal.xlsb workbook instead of the target workbook that is actually open and visible. How can I make sure it's being pasted in the right workbook? The workbook's filename will always be different, so I can't specify a path or anything like that.
Sub CopyData()
Application.DisplayAlerts = False
Dim wbSource As Workbook
Set wbSource = Workbooks.Open(Filename:="source.xlsx", UpdateLinks:=3)
wbSource.Sheets(1).Range("A1:X105").Copy
ThisWorkbook.ActiveSheet.Paste
wbSource.Close
Application.DisplayAlerts = True
Call CopyCFormat
End Sub
Don't use ThisWorkbook in most cases, as it references the workbook that the macro is stored in (in this case, personal.xlsb).
Instead, you can use ActiveWorkbook to refer to whichever workbook has focus at the time the macro is run. You can also assign ActiveWorkbook to a variable for easier reference.
Sub CopyData()
Application.DisplayAlerts = False
Dim wbSource As Workbook
Dim wbTarget as Workbook
Set wbTarget = ActiveWorkbook
Set wbSource = Workbooks.Open(Filename:="source.xlsx", UpdateLinks:=3)
wbSource.Sheets(1).Range("A1:X105").Copy
wbTarget.ActiveSheet.Paste
wbSource.Close
Application.DisplayAlerts = True
Call CopyCFormat
End Sub
You could also reference the active sheet without specifying which workbook it's in, as:
Dim wbSource As Workbook
Dim shtTarget as Worksheet
Set shtTarget = ActiveSheet
Set wbSource = Workbooks.Open(Filename:="source.xlsx", UpdateLinks:=3)
wbSource.Sheets(1).Range("A1:X105").Copy
shtTarget.ActiveSheet.Paste
Luck!
If I understand it, you should just add another workbook variable.
Sub CopyData()
Dim mainWB As Workbook
Dim mainWS As Worksheet
Set mainWB = ActiveWorkbook
Set mainWS = mainWB.Sheets(1) ' Change this to whatever you need it to be
Application.DisplayAlerts = False
Dim wbSource As Workbook
Set wbSource = Workbooks.Open(Filename:="source.xlsx", UpdateLinks:=3)
wbSource.Sheets(1).Range("A1:X105").Copy
mainWS.Paste
wbSource.Close
Application.DisplayAlerts = True
Call CopyCFormat
End Sub
I have an Excel-File in which the user can click on a button to save a version without formulas and only with values.
So far I use this VBA for it:
Sub Create_version_with_values_only()
Dim b As Worksheet
For Each b In Worksheets
b.Cells.Copy
b.Cells.Cells.PasteSpecial Paste:=xlPasteValues
Next b
Application.CutCopyMode = False
ActiveWorkbook.SaveCopyAs "G:\Folder\test.xlsm"
ThisWorkbook.Close SaveChanges:=False
End Sub
This VBA itself worsk fine.
However, the issue is that I have to close the file after the value-version of the file is created because the original version will not be available anymore.
Therefore, I am wondering if there is an alternative way to create the value-version of the file that makes it possible to go back to the original file afterwards.
Something like this:
Step 1) Change all formulas to values.
Step 2) Save the version with the values in the folder.
Step 3) Undo the value-replacements in original sheet without closing it.
Do you have any idea how to solve it?
There might be a more simple way to get there, but here's how you'd create a new workbook, transfer the values over and save.
Public Sub SaveValues()
Dim newWb As Workbook
Set newWb = Workbooks.Add 'create a new workbook for the values
Dim ws As Worksheet, newWs As Worksheet
For Each ws In ThisWorkbook.Worksheets
With newWb 'create worksheets and name them in new workbook
If ws.Index = 1 Then
Set newWs = .Worksheets(1)
Else
Set newWs = .Worksheets.Add(After:=.Worksheets(.Worksheets.Count))
End If
newWs.Name = ws.Name
End With
With ws.UsedRange 'move values to new worksheet
newWs.Range("A1").Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
Next
'save new workbook. If the current workbook is a .xlsb, change the .xlsm in the code below
newWb.SaveAs Replace(ThisWorkbook.FullName, ".xlsm", "_hardcoded.xlsm"), xlOpenXMLWorkbookMacroEnabled
newWb.Close
End Sub
Updated for alternatives below:
Alternative
An alternative is to use ThisWorkbook.Worksheets.Copy to copying all worksheets in one go. Unfortunately, to use this code, we have to use ActiveWorkbook to make a reference to the new workbook. (I hoped it might return a Workbook or Worksheets object)
Public Sub SaveValues2()
Dim newWB As Workbook
ThisWorkbook.Worksheets.Copy
Set newWB = ActiveWorkbook 'not great practice
Dim ws As Worksheet
For Each ws In newWB.Worksheets
With ws.UsedRange 'hardcode values
.Value = .Value
End With
Next
newWB.SaveAs Replace(ThisWorkbook.FullName, ".xlsm", "_hardcoded.xlsm"), xlOpenXMLWorkbookMacroEnabled
newWB.Close
End Sub
trying to do in another focus with the window from the workbook from first trying to do in another focus with the window from the workbook from first
Sub Update_DHL()
Workbooks.Open Filename:=trk
Workbooks.Open Filename:=stp
Workbooks.Open Filename:=dhl
Windows(stp).Activate
Workbooks(stpfile).Activate
Range("B2").Select
ActiveCell.Formula = _
"Hi"
Range(Cells(2, 2), Cells(2, 2)).Copy
'Range(Cells(3, 2), Cells(65536, 45)).Select
'Selection.ClearContents
'Range(Cells(3, 47), Cells(65536, 74)).Select
'Selection.ClearContents
' Set wb = Workbooks("VMW Macro.xlsm") 'Name of the workbook you are copying from
' Set ws = wb.Sheets("Extract") 'Name of sheet you are copying
' DateStamp = Format(Now(), "mm-dd-yyyy hhmmss")
End Sub
Make sure you define variables for your workbooks and worksheets properly. You can then use them for your Range and Cells objects to specify in which workbook and worksheet they are. This way you don't need .Activate or .Select because the code even works if the workbook has no focus.
Make sure in your entire code there is no Range and Cells object without a workbook and worksheet specified. Either by using a variable like shown below. Or directly like ThisWorkbook.Worksheets("Sheet1").Range(…).
You only need to .Activate or .Select if you want to focus it for the user. You never need to do this to make VBA work properly (VBA can work with non-focused workbooks/worksheets).
Option Explicit
Sub Update_DHL()
'open your workbooks
On Error GoTo ERR_WB_OPEN
Dim wbTrk As Workbook
Set wbTrk = Workbooks.Open(Filename:=[truckfilePath])
Dim wbStp As Workbook
Set wbStp = Workbooks.Open(Filename:=[stopfilePath])
Dim wbDhl As Workbook
Set wbDhl = Workbooks.Open(Filename:=[dhlfilePath])
On Error GoTo 0
'define in which worksheet in those workbooks you want to work
Dim wsTrk As Worksheet
Set wsTrk = wbTrk.Worksheets("SheetName")
Dim wsStp As Worksheet
Set wsStp = wsStp.Worksheets("SheetName")
Dim wsDhl As Worksheet
Set wsDhl = wsDhl.Worksheets("SheetName")
'now work with those worksheets directly (no activate or select needed!)
wsStp.Range("B2").Formula = "=IF(SUMIF('Route Master.xls'!$C$7:$C$65536,$A2,'Route Master.xls'!$Q$7:$Q$65536)>0,TRUE,FALSE)"
wsStp.Range("B2").Copy
wsStp.Range(wsStp.Cells(2, 2), wsStp.Cells(EndRow2, 2)).PasteSpecial Paste:=xlPasteFormulas, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
' note this code does not work because `EndRow2` is nod defined
'select and activate a specific workbook/worksheet
'you do this ONLY if you want to focus it for the USER. Never do this for VBA instead work directly with the worksheets as shown above.
wbDhl.Activate
wsDhl.Select
Exit Sub
ERR_WB_OPEN:
MsgBox "One of the files could not be loaded.", vbCritical
End Sub
Don't forget to close your workbooks wbDhl.Close SaveChanges:=True/False otherwise they stay open.
See below. You can reference the workbook directly as pointed out by BigBen. In code, you never need to select ranges or activate workbooks/worksheets. You just need to reference them directly.
Notice I also added explicit declaration of types.
Dim a, b As Long
The line above will declare a as a variant and b as long
Sub Update_DHL()
Dim trk As Workbook, stp As Workbook, dhl As Workbook, wb As Workbook, wbNew As Workbook
Dim ws As Worksheet
Dim stpfile As String, DateStamp As String, strFolderpath As String
Dim EndRowTrk As Long, EndRowStp As Long, EndRowDHL As Long
Dim fileExplorer As FileDialog
Set dhl = [dhlfilePath]
Set trk = [truckfilePath]
Set stp = [stopfilePath]
stpfile = stp
Workbooks.Open Filename:=trk
Workbooks.Open Filename:=stp
Workbooks.Open Filename:=dhl
With Workbooks(stpfile).Worksheets(1)
.Range("B2").Formula = "Hi"
End With
End Sub
I'm having an issue with the above: I am using the answer provided, but still hitting an object error. Can you see what i'm missing? I hit the errror at "Cash_Sheet.Range("C8").PasteSpecial xlPasteValues"
`Sub Refresh_Cash()
Dim Morning_Export As Workbook
Dim Cash_Sheet As Worksheet
'Open MorningExport cash workbook
Set Morning_Export = Workbooks.Open(Range("varMornExpPath"))
'Copy cash from Morning_Export_Settlement_Cas tab:
Morning_Export.Sheets("Morning_Export_Settlement Cas").Range("A1:AR5000").Copy
'Set the sheet in this file to paste to:
Set Cash_Sheet = ThisWorkbook.Worksheets("Cash")
'Clear prior data from EOD_Check
Cash_Sheet.Range("rngRefreshPFMExp").ClearContents
'EVERYTHING WORKS UP UNTIL THIS POINT BUT THEN FAILS HERE
Cash_Sheet.Range("C8").PasteSpecial xlPasteValues
'Close MorningExport book:
Morning_Export.Close
End Sub
Sub Refresh_Cash()
Dim wb As Workbook: Set wb = Workbooks.Open(Range("varMornExpPath"))
Dim cs As Worksheet: Set cs = ThisWorkbook.Sheets("Cash")
cs.Range("rngRefreshPFMExp").ClearContents
wb.Sheets("Morning_Export_Settlement Cas").Range("A1:AR5000").Copy
cs.Range("C8").PasteSpecial xlPasteValues
wb.Close
End Sub
Instead of using copy\paste you can directly write the values from one range in to another. This works much faster on large data sets because it doesn't have to copy twice. It also results in cleaner code.
Public Sub Refresh_Cash()
Dim Morning_Export As Workbook
Dim Cash_Sheet As Worksheet
'Open MorningExport cash workbook
Set Morning_Export = Workbooks.Open(ActiveSheet.Range("varMornExpPath"))
'Set the sheet in this file to paste to:
Set Cash_Sheet = ThisWorkbook.Worksheets("Cash")
' Set the values directly
Cash_Sheet.Range("C8") = Morning_Export.Sheets("Morning_Export_Settlement Cas").Range("A1:AR5000")
'Close MorningExport book:
Morning_Export.Close
End Sub
SEE: Copy/PasteSpecial vs Range.Value = Range.Value
I have written VBA code that opens up a destination workbook, copies one of the worksheets, and pastes it into the current workbook.
When I run it a second or third time etc... instead of overwriting the current worksheet, it creates a completely new one.
Ex: Worksheet is called "data", first time it transfers "data", second time "data(2)".
I have another worksheet that uses VLOOKUP function to look at some cells of this data worksheet, so it is crucial that it has correct name "data".
I thought about deleting the current (data) file before running the macro, but what if something crashes and I lose my worksheet? Is there a better solution?
NOTE: I am running the macro from the main workbook to get the sheet to be copied from the external workbook.
Sub UpdateT()
Dim wb As Workbook
Dim aw As Workbook
'Open 2nd Workbook
Set aw = Application.ActiveWorkbook
Set wb = Workbooks.Open(Filename:="C:\Users\yilmadu00\Desktop\T.xlsx")
'Copy To Different Workbook
wb.Sheets("data").Copy After:=aw.Sheets("Data1")
'Close 2nd Workbook
aw.Save
wb.Close
aw.Sheets("data").Visible = False
ActiveWorkbook.Protect ("Password")
End Sub
Function to check whether worksheet exists (credits to #ScottCrainer):
Function SheetExists(ws As String)
SheetExists = Not IsError(Application.Evaluate(ws & "!A1"))
End Function
NOTE:
It does have the issue: if A1 on the sheet contains an error it will return a false negative.
ActiveWorkbook vs ThisWorkbook, Sheets vs Worksheets
You have used 'Activeworkbook' and 'Sheet(s)' in the code so I played along.
But
Although you can have a third workbook to run the code from, I'm guessing you are running the code from a module in the 'ActiveWorkbook'. If this is true, it would be more correct to use 'ThisWorkbook' instead which always refers to the workbook that contains the code (module), to avoid accidentally running the code on a third workbook.
Sheet(s) refers to Worksheet(s) and Chartsheet(s), again I'm guessing there are no chartsheets involved in this code, therefore it would be more correct to use 'Worksheet(s)' instead of 'Sheet(s)'.
Sub UpdateT()
Const cStrPath As String = "C:\Users\yilmadu00\Desktop\T.xlsx"
Const cStrAfter As String = "Data1"
Const cStrName As String = "data"
Const cStrOld As String = "data_old"
Dim aw As Workbook '1st workbook, 'ActiveWorkbook'
Dim wb As Workbook '2nd workbook
Dim oWs As Sheet 'Each sheet in workbook 'aw'
Dim blnFound As Boolean 'True if sheet(cStrName) was found
Set aw = ActiveWorkbook 'Create a reference to the ActiveWorkbook
Set wb = Workbooks.Open(Filename:=cStrPath) 'Open 2nd Workbook
With aw
' .UnProtect ("Password")
'Check each sheet in workbook 'aw'.
For Each oWs In aw.Sheets
With oWs
'Check if there already is a sheet with the name 'cStrName'.
If .Name = cStrName Then
.Name = cStrOld 'Rename the sheet.
blnFound = True 'Sheet(cStrName) was found.
Exit For 'Immediately stop checking, there can only be one.
End If
End With
Next
End With
With wb
'Copy sheet from 2nd workbook ('wb') to workbook 'wa'.
.Sheets(cStrName).Copy After:=aw.Sheets(cStrAfter)
.Close 'Close 2nd workbook ('wb').
End With
With aw
With Application
If blnFound = True Then 'Sheet(cStrName) was found.
.DisplayAlerts = False 'Disable showing delete message.
aw.Sheets(cStrOld).Delete 'Delete old version of sheet.
.DisplayAlerts = True
End If
End With
.Sheets(cStrName).Visible = False 'Hide sheet named 'cStrName'
.Protect ("Password")
.Save 'Save workbook 'aw'.
End With
End Sub
The next time you want to do something with the sheet you have to unprotect it or the code will fail. Hidden sheets can be deleted with no problems.