Sorry if this comes across as flippant but I've spent the last 8 hours smashing my head against a wall with this. No matter what variant I try, this code constantly throws up errors of all degrees. I'm competent and I've taken SO MANY EXAMPLES and NONE OF THEM WORK. I'm beginning to think that theres something wrong with where the code is in my workbook. I've put it in Module1, where I normally keep all code.
The actual problem - copy/paste values from one workbook sheet to another after selecting the file from a popup prompt. That's it. The structure of the table is the same but it will need to be moved 5 rows up on the target sheet.
I've tried so many different types of code, which you can see as commented out when I try to iterate to something different. IT WILL NOT REFERENCE THE OPENED WORKBOOK CORRECTLY. Keeps throwing up errors like I'm trying to access some hidden darknet database instead of a file right next to it......
I've tried so many different approaches but they all end up with different errors. the above code gives me 'Runtime error 13. Type, mismatch.' on the line in the loop that tries to copy the code.
I think it all stems from excel not being able to correctly reference the opened file. even though it should.......................
Sub ImportEstimatorData()
Dim xTargetWb As Workbook 'Consolidator
Dim xSourceWb As Workbook 'Estimator
Set xTargetWb = ActiveWorkbook
Dim xTargetRng As Range 'Target row/column in new sheet, changes row starting
Dim xSourceRng As Range 'Source data from Estimator, Never changes
Dim xSourceSt As Worksheet
Dim xTargetSt As Worksheet
Sheets("CR Data").Activate
Set xTargetSt = ThisWorkbook.Sheets("CR Data")
Dim vFile As Variant
'fileToOpen = Application _
' .GetOpenFilename("Text Files (*.txt), *.txt")
'If fileToOpen <> False Then
' MsgBox "Open " & fileToOpen
'End If
'Dim vFile As Variant
'vFile = Application.GetOpenFilename("Excel-files,*.xlsx", 1, "Select One File To Open", , False)
'if the user didn't select a file, exit sub
'If vFile = "" Then Exit Sub
'Set targetworkbook
'Set xSourceWb = Workbooks.Open(vFile)
If Not Application.OperatingSystem Like "*Mac*" Then
' Is Windows.
vFile = Application.GetOpenFilename("Excel-files,*.xlsm", 1, "Select One File To Open", , False)
'if the user didn't select a file, exit sub
If vFile = "" Then
Exit Sub
End If
Else
Exit Sub
End If
' Is a Mac and will test if running Excel 2011 or higher.
' If Val(Application.Version) > 14 Then
' Set xSourceWb = Select_File_Or_Files_Mac
' End If
' End If
'Workbooks.Open (vFile)
Set xSourceWb = Workbooks.Open(vFile)
'Workbooks(xSourceWb).Open
'Workbooks(xSourceWb).Activate
'Set Sheets for both Source & Target Workbooks
'Set xSourceSt = xSourceWb.Sheets("Output data GPE")
'Set xTargetRng = xTargetSt.Range(Cells(4, 2), Cells(80, 16))
Sheets("Output Sheet GPE").Activate 'Range(Cells(1, 1), Cells(2, 2)).Select
Set xSourceWb = ActiveWorkbook
'xSourceWb.Activate
'Set xSourceRng = xSourceSt.Range(Cells(4, 2), Cells(80, 16))
'xSourceRng.Copy xTargetRng
'Workbooks(xSourceWb).Worksheets("Output Sheet GPE").Range(Cells(8, 2), Cells(84, 16)).Copy Workbooks(xTargetWb).Worksheets("CR Data").Range(Cells(4, 2), Cells(80, 16))
For i = 8 To 84
For j = 2 To 16
Workbooks(xSourceWb).Worksheets("Output Sheet GPE").Cells(i, j) = Workbooks(xTargetWb).Worksheets("CR Data").Cells(i - 4, j)
'Debug error here
Next j
Next i
'Workbooks(xWb).Worksheets("CR Data").Range(Cells(4, 2), Cells(80, 16)).Copy Workbooks(xTargetWb).Worksheets("C").Range(Cells(4, 2), Cells(80, 16))
'Workbooks(xTargetWb).Worksheets("CR Data").Range(Cells(4, 2), Cells(80, 16)).PasteSpecial Paste:=xlPasteValues
'Workbooks(xTargetWb).Sheets("CR Data").Range(Cells(4, 2), Cells(80, 16)).Value = Workbooks(xSourceWb).Sheets("Output Sheet GPE").Range(Cells(4, 2), Cells(80, 16))
'xSourceWb.Close
'End If
'End With
End Sub'
Thank you BigBen! That was exactly it! I removed the 'workbooks' encloser and it worked :-)
Copy/paste response below for future perusal:
xSourceWb and xTargetWb are Workbook objects already. Don't enclose them in Workbooks. That said, you don't need a loop for this. – BigBen 16 hours ago
Related
I want to insert data from source files in my excel model by opening the files and copying and pasting the values. I am just updating the values and not inserting formulas, formats or images etc.
The macro works fine and the inputs are pasted in my excel model. The last command is: ActiveWorkbook.Save
However, sometimes the macro cannot save the file (and I cannot see a regularity here - sometimes it works, sometimes it doesn't) and it displays the error message: "Errors were detected while saving. Microsoft Excel may be able to save the file by removing or repairing some features. To make the repairs in a new file, click continue. To cancel saving the file, click cancel."
Does anyone have an idea on how to fix this error? I am also posting the full code below. Thanks a lot in advance!
' Definitions
Dim i As Integer
Dim mapping_sheet, Worksheet_MVP, Dateiname_Input, Name_Worksheet_Input, Pfad_Input, Pfad_Datei, Zelle, Text As String
' Workbooks
Dim MVP, Auszug As Workbook
Pfad_Input = ActiveSheet.Range("B7").Value
Set MVP = ActiveWorkbook
Sheets("Automatisierung Datenupdate").Activate
Workbooks(MVP.Name).Application.Calculation = xlCalculationManual
Workbooks(MVP.Name).Application.CalculateBeforeSave = False
' 1. Updating Macro
' Copy Pasting Data
If ActiveSheet.Range("E11").Value = "Ja" Then
Dateiname_Input = ActiveSheet.Range("M11").Value
Name_Worksheet_Input = ActiveSheet.Range("D11").Value
Worksheet_MVP = ActiveSheet.Range("B11").Value
Pfad_Datei = Pfad_Input & "\" & Dateiname_Input
Sheets(Worksheet_MVP).Activate
Range("B6:ZZ300").Select
Selection.ClearContents
Set Auszug = Workbooks.Open(Filename:=Pfad_Datei)
Workbooks(Auszug.Name).Activate
Sheets(Name_Worksheet_Input).Activate
Range("A4:ZY298").Select
Selection.Copy
Workbooks(MVP.Name).Activate
Sheets(Worksheet_MVP).Activate
Range("B6").Select
Selection.PasteSpecial Paste:=xlPasteValues
' Close and Save
Workbooks(Auszug.Name).Activate
ActiveSheet.Range("A1").Copy
Workbooks(Auszug.Name).Close savechanges:=False
Workbooks(MVP.Name).Activate
Sheets("Automatisierung Datenupdate").Activate
Range("M11").Select
Selection.Copy
Range("C11").Select
Selection.PasteSpecial Paste:=xlPasteValues
End If
' Save
Sheets("Automatisierung Datenupdate").Activate
Application.ScreenUpdating = True
ActiveWorkbook.Save
End Sub
You mix up the concepts in your code which probably leads to the unexpected/irregular errors.
If you don't specify a data type (or object type) when you dim, the variable is Variant by default. e.g. "Dim MVP" is the same as "Dim MVP as variant"
You do assign your workbooks/worksheets to a variable but don't use the magic. Once set you can just refer to the workbook by referencing the varName.
Although variables are very powerfull, when you just want to use cell values it's better to store these in memory (e.g. an array)
Hereunder an alternative approach, only using the named workbooks/worksheets and minimising the interactions with the sheet by using arrays:
Sub ceci()
'dim vars to specific datatype
Dim wb As Workbook, sh As Worksheet, arr
Set wb = ThisWorkbook
Set sh = wb.Sheets("Automatisierung Datenupdate")
'To minimize the interactions with the sheet we store the data in memory, an array
'here we can access each cell by referencing our array(<rowCounter>, <columnCounter>
'e.g. arr(j,i) => if j = 1 and i = 1 we'll have the values of Cell A1
'we can dump these values anywhere in the activesheet, other sheet, other workbook, ..
Dim sh2 As Worksheet, wb2 As Workbook
arr = sh.Range("A1").CurrentRegion.Value2 'assuming you have data as of A1 we store all in the array, you can fine tune if needed though
If arr(11, 5) = "ja" Then 'E11
'source wb
Set sh2 = wb.Sheets(arr(11, 2)) 'b11
sh2.Range("B6:ZZ300").ClearContents
'wb2 - by specifically naming the workbooks and sheets we avoid unexpected errors
Dim sh3 As Worksheet, arr2, Pfad_Datei As String: Pfad_Datei = wb.Path & "\" & arr(11, 13) 'arr(7, 2) & "\" & arr(11, 13) 'b7 & m11
Set wb2 = Workbooks.Open(Filename:=Pfad_Datei)
Set sh3 = wb2.Sheets(arr(11, 4)) 'd11
arr2 = sh3.Range("A4:ZY298").Value2
sh2.Range(sh2.Cells(6, 2), sh2.Cells(UBound(arr2), UBound(arr2, 2))).Value2 = arr2 'dumb to sheet
'wb1
sh.Range("c11").Value = arr(11, 13) 'm11
End If
wb.Save
End Sub
I'm trying to:
Copy data (columns A and B) from one workbook (data.xlsx).
Paste into a new workbook (as values).
Save as CSV with a filename taken from column A in a third workbook (URLs.xlsx).
Process to repeat, taking the same data (which is randomised every time it is pasted) from data.xlsx and pasted into a new CSV - there are 200 rows in URLs.xlsx and so we should end up with 200 files.
I've read lots of topics, here are two I found:
Excel VBA Copy a Range into a New Workbook
https://www.excelcampus.com/vba/copy-paste-another-workbook/
What I've tried
Copying code and replacing the relevant components from various different articles across the web. Some of them work, but when I add the missing bits, I run into errors I don't understand.
Well here is an example avoiding copy pasting in new workbooks:
Expected input like:
Data.xlsx range A1:B200 with RANDBETWEEN() function:
URLs.xlsx range A1:A200 with some URL like so:
Run this code (will take approximately 1 second on my machine, tested with timer):
Dim wbData As Workbook, WBurls As Workbook
Dim CSVFileDir As String, CSVVal As String
Dim A As Long, X As Long, Y As Long, Z As Long
Option Explicit
Sub Transfer2CSV()
Set wbData = Workbooks("data.xlsx") 'Make sure it is open upon running macro
Set WBurls = Workbooks("URLs.xlsx") 'Make sure it is open upon running macro
For X = 1 To 200 'Looping through the 200 rows of WBurls
CSVFileDir = "C:\YourDrive\" & WBurls.Sheets(1).Cells(X, 1).Value & ".csv"
CSVVal = ""
A = FreeFile
Open CSVFileDir For Output As #A
With wbData.Sheets(1).Range("A1:B200") ' or whichever range you using here
.Calculate 'Randomize your range again
For Y = 1 To 200 'or however many rows you have in column A and B.
For Z = 1 To 2
CSVVal = CSVVal & .Cells(Y, Z).Value & ","
Next Z
Print #A, Left(CSVVal, Len(CSVVal) - 2)
CSVVal = ""
Next Y
End With
Close #A
Next X
End Sub
Output:
With each file looking like:
This should work. Make sure your data and URLS workbooks are open.
Sub Macro1()
Dim wsData As Worksheet, wsUrl As Worksheet, wbNew as Workbook
Dim CSVDir as String, rngU As Range
Set wsData = Workbooks("data.xlsx").Worksheets(1)
Set wsUrl = Workbooks("URLs.xlsx").Worksheets(1)
Set rngU = wsUrl.Range("A1", wsUrl.Range("A" & wsUrl.Rows.Count).End(xlUp))
CSVDir = "C:\Users\thomas.mcerlean\Desktop\Work\" 'you gave this as your dir
Set wbNew = Workbooks.Add
For Each cell In rngU
wsData.Range("A1", wsData.Range("B" & wsData.Rows.Count).End(xlUp)).Copy Destination:= wbNew.Worksheets(1).Range("A1")
wbNew.SaveAs Filename:= CSVDir & cell.Value & ".csv", FileFormat:=xlCSV
Next cell
wbNew.Close SaveChanges:=False
End Sub
Using code from the spreadsheet guru to loop through files in a folder and perform a set task on them, seems to be working properly. Where I may have made a mistake is the set task portion of the code.
Using Excel 2010.
sourcewb = ActiveWookbook
sourcefn = ActiveWorkbook.Name
masterwb = ThisWorkbook
masterwb.Activate
lr = ActiveSheet.ListObjects("DataTbl").ListRows.Count
If ActiveSheet.ListObjects("DataTbl").DataBodyRange(lr, 1).Value = "" Then
sourcewb.Activate
ActiveSheet.ListObjects("IntermidateTbl").DataBodyRange.Copy
masterwb.Activate
ActiveSheet.ListObjects("DataTbl").DataBodyRange(lr, 1).Select
Selection.Paste
newlr = ActiveSheet.ListObjects("DataTbl").ListRows.Count
Range(ActiveSheet.ListObjects("DataTbl").DataBodyRange(lr, 8), _
ActiveSheet.ListObjects("DataTbl").DataBodyRange(newlr, 8)) = "" & sourcefn & ""
Else
ActiveSheet.ListObjects("DataTbl").ListRows.Add AlwaysInsert:=True
sourcewb.Activate
ActiveSheet.ListObjects("IntermidateTbl").DataBodyRange.Copy
masterwb.Activate
ActiveSheet.ListObjects("DataTbl").DataBodyRange(lr + 1, 1).Select
Selection.Paste
newlr = ActiveSheet.ListObjects("DataTbl").ListRows.Count
Range(ActiveSheet.ListObjects("DataTbl").DataBodyRange(lr + 1, 8), _
ActiveSheet.ListObjects("DataTbl").DataBodyRange(newlr, 8)) = "" & sourcefn & ""
End If
There are more than a few errors, I'll try to help with a few.
You are trying to set sourcewb, which is a Workbook object, so you need to change:
sourcewb = ActiveWookbook
To:
Set sourcewb = ActiveWookbook
(the same goes for Set masterwb = ThisWorkbook).
Next, masterwb.Activate, you don't need to Activate the workbook, and it's also safer to also set reference to the sheet you want, you can also add the With statement, and use something like:
With masterwb.Worksheets("SheetName")
lr = .ListObjects("DataTbl").ListRows.Count ' number of rows in "DataTbl" table
You can also set an Object to your ListObjects.
Dim DataTbl As ListObject
Set DataTbl = masterwb.Worksheets("SheetName").ListObjects("DataTbl")
So later on, you can access it's properties much easier (and "cleaner").
For example:
lr = DataTbl.ListRows.Count ' <-- get the rows count of the table
and:
If DataTbl.DataBodyRange(lr, 1).Value = "" Then
And so on, you have way too many places where you Activate the 2 workbooks, and later use ActiveSheet and Selection.
If you describe better what you are trying to achieve, we can help you achieve it in a more reliable way.
I wonder whether someone can help me please.
I wanting to use this solution in a script I'm trying to put together, but I'm a little unsure about how to make a change which needs to be made.
You'll see in the solution that the file type which is opened is a Excel and indeed it's saved as such. But I the files I'd like to open and save are a mixture of .docx and .dat (Used by Dragon software) files.
Could someone possible tell me please is there a way by which I can amend the code so it opens and saves the files in file types other than Excel workbooks.
The reason behind this question because I'm currently using a script which creates a list of files in a Excel spreadsheet from a given folder. For each file that is retrieved there is a hyperlink, which I'd like to add fucntionality to which enables the user to copy the file and save it to a location of their choice.
To help this is the code which I use to create the list of files.
Public Sub ListFilesInFolder(SourceFolder As Scripting.folder, IncludeSubfolders As Boolean)
Dim LastRow As Long
Dim fName As String
On Error Resume Next
For Each FileItem In SourceFolder.Files
' display file properties
Cells(iRow, 3).Formula = iRow - 12
Cells(iRow, 4).Formula = FileItem.Name
Cells(iRow, 5).Formula = FileItem.Path
Cells(iRow, 6).Select
Selection.Hyperlinks.Add Anchor:=Selection, Address:= _
FileItem.Path, TextToDisplay:="Click Here to Open"
iRow = iRow + 1 ' next row number
With ActiveSheet
LastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
LastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
End With
For Each Cell In Range("C13:F" & LastRow) ''change range accordingly
If Cell.Row Mod 2 = 1 Then ''highlights row 2,4,6 etc|= 0 highlights 1,3,5
Cell.Interior.Color = RGB(232, 232, 232) ''color to preference
Else
Cell.Interior.Color = RGB(141, 180, 226) 'color to preference or remove
End If
Next Cell
Next FileItem
If IncludeSubfolders Then
For Each SubFolder In SourceFolder.SubFolders
ListFilesInFolder SubFolder, True
Next SubFolder
End If
Set FileItem = Nothing
Set SourceFolder = Nothing
Set FSO = Nothing
End Sub
Many thanks and kind regards
Chris
Miguel provided a fantastic solution which on initial testing appeared to work 100%. But as you will see from the comments at the end of the post there were some issues when the user cancelled the operation, so I made another post at this link where the problems were ironed out. Many thanks and kind regards. Chris
The code below shows how to retrieve the extension of a file, define an array with “allowed” extensions, and match the extension of the file to the array.
This is the outline for file manipulation, you'll just need to tailor it to you needs
Dim MinExtensionX
Dim Arr() As Variant
Dim lngLoc As Variant
'Retrieve extension of file
MinExtensionX = Mid(MyFile.Name, InStrRev(MyFile.Name, ".") + 1)
Arr = Array("xls", "xlsx", "docx", "dat") 'define which extensions you want to allow
On Error Resume Next
lngLoc = Application.WorksheetFunction.Match(MinExtensionX, Arr(), 0)
If Not IsEmpty(lngLoc) Then '
'check which kind of extension you are working with and create proper obj manipulation
If MinExtensionX = "docx" then
Set wApp = CreateObject("Word.Application")
wApp.DisplayAlerts = False
Set wDoc = wApp.Documents.Open (Filename:="C:\Documents\SomeWordTemplate.docx", ReadOnly:=True)
'DO STUFF if it's an authorized file. Then Save file.
With wDoc
.ActiveDocument.SaveAs Filename:="C:\Documents\NewWordDocumentFromTemplate.docx"
End With
wApp.DisplayAlerts = True
End if
End If
For files .Dat its a bit more complex, specially if you need to open/process data from the file, but this might help you out.
Edit:
2: Comments added
Hi IRHM,
I think you want something like this:
'Worksheet_FollowHyperlink' is an on click event that occurs every time you click on an Hyperlink within a Worksheet, You can find more here
Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
'disable events so the user doesn't see the codes selection
Application.EnableEvents = False
Dim FSO
Dim sFile As String
Dim sDFolder As String
Dim thiswb As Workbook ', wb As Workbook
'Define workbooks so we don't lose scope while selecting sFile(thisworkbook = workbook were the code is located).
Set thiswb = thisworkbook
'Set wb = ActiveWorkbook ' This line was commented out because we no longer need to cope with 2 excel workbooks open at the same time.
'Target.Range.Value is the selection of the Hyperlink Path. Due to the address of the Hyperlink being "" we just assign the value to a
'temporary variable which is not used so the Click on event is still triggers
temp = Target.Range.Value
'Activate the wb, and attribute the File.Path located 1 column left of the Hyperlink/ActiveCell
thiswb.Activate
sFile = Cells(ActiveCell.Row, ActiveCell.Column - 1).Value
'Declare a variable as a FileDialog Object
Dim fldr As FileDialog
'Create a FileDialog object as a File Picker dialog box.
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
'Allow only single selection on Folders
fldr.AllowMultiSelect = False
'Show Folder picker dialog box to user and wait for user action
fldr.Show
'add the end slash of the path selected in the dialog box for the copy operation
sDFolder = fldr.SelectedItems(1) & "\"
'FSO System object to copy the file
Set FSO = CreateObject("Scripting.FileSystemObject")
' Copy File from (source = sFile), destination , (Overwrite True = replace file with the same name)
FSO.CopyFile (sFile), sDFolder, True
' check if there's multiple excel workbooks open and close workbook that is not needed
' section commented out because the Hyperlinks no longer Open the selected file
' If Not thiswb.Name = wb.Name Then
' wb.Close
' End If
Application.EnableEvents = True
End Sub
The above code Triggers when you click the Hyperlink and it promps a folder selection window.
You just need to paste the code into the Worksheet code. And you should be good to go.
I am trying to copy the string values(column titles) from another workbook in row 4 as captions for checkboxes in the workbook where I am running the code. This is what I have so far and it is not working because it is showing the error message "Subscript out of range, run time error 9" Here is what I have. After the error message pops up the line marked below is highlighted. Can anybody help me please. Thank you very much.
Function CallFunction(SheetName As Variant) As Long
Dim text As String
Dim titles(200) As String ' Dim titles(200) As String ' Array
Dim nTitles As Integer
Dim wks As Worksheet
Dim myCaption As String
PathName = Range("F22").Value
Filename = Range("F23").Value
TabName = Range("F24").Value
ControlFile = ActiveWorkbook.Name
Workbooks.Open Filename:=PathName & "\" & Filename
ActiveSheet.Name = TabName
Set wks = Workbooks("Filename").Worksheets(SheetName).Activate ' <= Highlights this line ****
For i = 1 To 199
If Trim(wks.Cells(4, i).Value) = "" Then
nTitles = i - 1
Exit For
End If
titles(i - 1) = wks.Cells(4, i).Value
Next
i = 1
For Each cell In Range(Sheets("Sheet1").Cells(4, 1), Sheets("Sheet1").Cells(4, 1 + nTitles))
myCaption = Sheets("Sheet1").Cells(4, i).Value
With Sheets("Sheet1").checkBoxes.Add(cell.Left, _
cell.Top, cell.Width, cell.Height)
.Interior.ColorIndex = 12
.Caption = myCaption
.Characters.text = myCaption
.Border.Weight = xlThin
.Name = myCaption
End With
i = i + 1
Next
End Function
Subscript out-of-range typically indicates that a specified Worksheet does not exist in the workbooks Worksheets collection.
Otherwise, are you sure that the workbook specified by FileName is already open? If not, that will raise the same error.
Ensure that A) the file is already open (or use the Workbooks.Open method to open it), and B) ensure that such a worksheet already exists (if not, you will need to create it before you can reference it by name).
Update
You have Workbooks("FileName") where "Filename" is a string literal. Try changing it to simply Filename (without the quotation marks) (this seems like the OBVIOUS error).
Also worth checking:
I also observe this line:
ActiveSheet.Name = TabName
If the sheet named by SheetName is active when the workbook opens, then that line will effectively rename it, so you will not be able to refer to it by SheetName, but instead you would have to refer to it by Worksheets(TabName). ALternatively, flip the two lines so that you activate prior to renaming:
Set wks = Workbooks(Filename).Worksheets(SheetName).Activate
ActiveSheet.Name = TabName
For further reading: avoid using Activate/Select methods, they are confusing and make your code harder to interpret and maintain:
How to avoid using Select in Excel VBA macros
If that is the case, then you could do simply:
Workbooks(Filename).Worksheets(SheetName).Name = TabName