I'm beginner in VBA, I would like to know if my code is efficient. I'm wondering that is to long, maybe there is some function to save the spreadsheet?
I'm proceeding like this :
I click on the button (the code runs the Userform "Edition Fichier"), the name of this Userforme in my code is uSauvegarde.
I make my choices :
The code is :
Private Sub bParcourir_Click()
With Application.FileDialog(4)
.AllowMultiSelect = False
.Show
uSauvegarde.TextBox1 = .SelectedItems(1)
End With
End Sub
Private Sub bValider_Click()
Dim wb_Saisie As Workbook, wb_Sauv As Workbook
Dim New_Wkb As String, TableDesFeuilles() As String
Dim i As Integer, NumF As Integer
Dim S As Worksheet
Dim obj As Shape
Dim mdCalc As XlCalculation
mdCalc = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
New_Wkb = uSauvegarde.TextBox1 & "\" & uSauvegarde.TextBox2 & ".xlsx"
Set wb_Saisie = ThisWorkbook
wb_Saisie.Activate
i = 0
For Each S In wb_Saisie.Sheets
If S.Visible = True Then
ReDim Preserve TableDesFeuilles(i)
TableDesFeuilles(i) = S.Name
i = i + 1
End If
Next
Application.ScreenUpdating = False
NumF = 0
BlocageModif = True
For Each S In wb_Saisie.Sheets
If S.Visible = True Then
S.Copy
ActiveSheet.Cells.Copy
ActiveSheet.Cells.PasteSpecial xlPasteValues
If NumF = 0 Then
Set wb_Sauv = ActiveWorkbook
NumF = 1
Else
ActiveSheet.Move After:=wb_Sauv.Worksheets(NumF)
NumF = NumF + 1
End If
Range("A1").Select
For i = ActiveSheet.UsedRange.Columns.Count To 1 Step -1
If ActiveSheet.Columns(i).Hidden = True Then ActiveSheet.Columns(i).Delete
Next
For j = ActiveSheet.UsedRange.Rows.Count To 1 Step -1
If ActiveSheet.Rows(j).Hidden = True Then ActiveSheet.Rows(j).Delete
Next
For Each obj In ActiveSheet.Shapes
If obj.OnAction <> "" Then obj.OnAction = ""
Next
End If
Next S
For Each NomLocal In wb_Sauv.Names
If InStr(NomLocal.Name, "Print_") = 0 Then NomLocal.Delete
Next
wb_Sauv.SaveAs Filename:= _
New_Wkb, FileFormat:= _
xlOpenXMLWorkbook, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False,
CreateBackup:=False
wb_Sauv.Close
Application.Calculation = mdCalc
Application.ScreenUpdating = True
MsgBox ("Fichier enregistré")
uSauvegarde.Hide
End Sub
Private Sub OptionButton1_Click()
With ThisWorkbook.Sheets("Feuil1")
uSauvegarde.TextBox2 = "Mon_fichier"
End With
End Sub
Private Sub OptionButton2_Click()
uSauvegarde.TextBox2 = ""
End Sub
Thank you for your help !
Your code looks good to me, but I found some things that didn't make any sense like a With that created more code or turning off Screen updating where it was already turned off. The code was difficult to read because of bad indentation and lack of descriptive variable names. This is really important when coding because is HIGHLY possible you will need to read it again to fix possible bugs or make it more efficient. I made some changes for you to review.
Option Explicit '---- always good to have
Private Sub bParcourir_Click()
With Application.FileDialog(4)
.AllowMultiSelect = False
.Show
uSauvegarde.TextBox1 = .SelectedItems(1)
End With
End Sub
Private Sub bValider_Click()
Dim wb_Saisie As Workbook, wb_Sauv As Workbook
Dim New_Wkb As String, TableDesFeuilles() As String
Dim i As Integer, NumF As Integer
Dim S As Worksheet
Dim obj As Shape
Dim mdCalc As XlCalculation
mdCalc = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
New_Wkb = uSauvegarde.TextBox1 & "\" & uSauvegarde.TextBox2 & ".xlsx"
Set wb_Saisie = ThisWorkbook
wb_Saisie.Activate
i = 0
For Each S In wb_Saisie.Sheets
If S.Visible = True Then
ReDim Preserve TableDesFeuilles(i)
TableDesFeuilles(i) = S.Name
i = i + 1
End If
Next
'Application.ScreenUpdating = False ---- why disable "screen updating" again?
NumF = 0
BlocageModif = True
With ActiveSheet '----- a "With" here is a good idea
For Each S In wb_Saisie.Sheets
'If S.Visible = True Then
If S.Visible Then '------- the if statement above can be written like this
S.Copy
.Cells.Copy
.Cells.PasteSpecial xlPasteValues
If NumF = 0 Then
Set wb_Sauv = ActiveWorkbook
NumF = 1
Else
.Move After:=wb_Sauv.Worksheets(NumF)
NumF = NumF + 1
End If
Range("A1").Select
For i = .UsedRange.Columns.Count To 1 Step -1
If .Columns(i).Hidden Then
t.Columns(i).Delete
End If
Next
For j = .UsedRange.Rows.Count To 1 Step -1
If .Rows(j).Hidden Then
.Rows(j).Delete
End If
Next
For Each obj In .Shapes
If obj.OnAction <> "" Then
obj.OnAction = ""
End If
Next
End If
Next S
End With
For Each NomLocal In wb_Sauv.Names
If InStr(NomLocal.Name, "Print_") = 0 Then NomLocal.Delete
Next
'------ this section of the code has problems.. check it out
wb_Sauv.SaveAs Filename:= _
New_Wkb, FileFormat:= _
xlOpenXMLWorkbook, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False,
CreateBackup:=False
wb_Sauv.Close
Application.Calculation = mdCalc
Application.ScreenUpdating = True
'MsgBox ("Fichier enregistré") '----- parenthesis are nor necessary
MsgBox "Fichier enregistré"
uSauvegarde.Hide
End Sub
Private Sub OptionButton1_Click()
'With ThisWorkbook.Sheets("Feuil1") ---- this "With" creates more code...
'uSauvegarde.TextBox2 = "Mon_fichier"
'End With
ThisWorkbook.Sheets("Feuil1").uSauvegarde.TextBox2 = "Mon_fichier"
End Sub
Private Sub OptionButton2_Click()
uSauvegarde.TextBox2 = ""
End Sub
Related
The parts not working are especially loop parts (marked as --- not working ---). Do I have to “activate” them first somehow?
The part which displays sheet “X” and freezing the screen isn't working too.
I want to display a picture on sheet “X” with a coffee image and the message: “please wait” until the macro is finished.
I tried to avoid the “Select” and “Activate” commands.
'Variables
Dim Destbook As Workbook
Dim Sourcebook As Workbook
Dim DestCell As Range
Dim xFile As String
Dim xFolder As String
Dim xFiles As New Collection
Dim xSheets As Worksheet
Dim xCount As Long
Dim xSheetCount As Long
Dim xRow As Long
Dim A As Integer
Dim I As Integer
Dim Z As Integer
Dim xMax As Double
'On a System Error go to "Troubleshooting" and display the ocurred fault code
On Error GoTo Troubleshooting
'Deactivate Alerts
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.UseSystemSeparators = False
'Display hidden Sheet "X", select cell "A1" and freeze screen
' ------------------------- NOT WORKING ---------------------
ActiveWorkbook.Sheets("X").Visible = xlSheetVisible
With ActiveWorkbook.Sheets("X")
Application.Goto .Range("A1")
ActiveWindow.FreezePanes = True
End With
'Deactivate Alerts
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.UseSystemSeparators = False
'Delete contents for each Sheet containing the name "Data" for the selected range
' ------------------------- NOT WORKING ---------------------
xSheetCount = ActiveWorkbook.Worksheets.Count
For Z = 1 To xSheetCount '
If Left(xSheets.Name, 4) = "Data" Then
With ActiveSheet
.Range("B5:K90000").ClearContents
End With
End If
Next Z
'Select the folder with the desired data to import
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select Folder"
.ButtonName = "Import Data"
.InitialView = msoFileDialogViewList
If .Show = -1 Then xFolder = .SelectedItems(1)
If Right(xFolder, 1) <> "\" Then xFolder = xFolder & "\"
End With
'On error or no files found display the following
If xFolder = "" Then
MsgBox ("No files found or selected!")
Exit Sub
End If
'Get the desired Textfiles in the selected Folder
Set FS = CreateObject("Scripting.FileSystemObject")
Set Folder = FS.Getfolder(xFolder)
For Each File In Folder.Files
If File.Name Like "*####-##-##*" Then
xFile = File.Name
If xFile <> "" Then
xCount = xCount + 1
xFiles.Add xFile, xFile
If xFile = "" Then Resume Next
End If
End If
Next
'File processing
I = 1
Set Destbook = ThisWorkbook
If xFiles.Count > 0 Then
For A = 1 To xFiles.Count
Set Sourcebook = Workbooks.Open(xFolder & xFiles.Item(A), local:=True)
'Skip files with no current values greater than 2 A
xMax = Application.WorksheetFunction.Max(Range("C2:C90000"))
If xMax < 2 Then
GoTo ContinueLoop
End If
If InStr(1, ActiveSheet.Name, "Stufe", vbTextCompare) <> 0 Then
Columns("I:Y").Delete
Rows(1).Insert
Range("D1").Value = ActiveSheet.Name
xRow = Cells(Rows.Count, 1).End(xlUp).Row
ActiveSheet.Range("A1:J" & xRow).Copy
End If
ThisWorkbook.Sheets("Data (" + CStr(I) + ")").Range("B3").PasteSpecial Paste:=xlPasteAll
Application.CutCopyMode = False
On Error Resume Next
On Error GoTo 0
I = I + 1
ContinueLoop: Sourcebook.Close False
Next
End If
'Just some formatting things...
' ------------------------- NOT WORKING ---------------------
xSheetCount = ActiveWorkbook.Worksheets.Count
For I = 1 To xSheetCount
If Left(Worksheet.Name, 4) = "Data" Then
With ActiveSheet.Range("A1:J" & xRow)
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
Range("B3:C3").Merge
Range("B3").Value = "Filename:"
Range("B3:K4").Font.Bold = True
Range("B4:K4").Borders.LineStyle = xlContinuous
End With
End If
Next I
'Delete sheet "Import data", hide sheet "X" and save file
'Sheets("Import data").Delete
ActiveWorkbook.Sheets("X").Visible = xlSheetVeryHidden
Application.DisplayAlerts = True
Application.ScreenUpdating = False
Application.UseSystemSeparators = True
'DestBook.SaveAs Filename:=CStr(Date) + "Analysis", FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
'Display the occured error message and exit program
Troubleshooting: Application.DisplayAlerts = True
Application.ScreenUpdating = True
If Err.Number <> 0 Then MsgBox "Troubleshooting: " & _
Err.Number & vbLf & Err.Description: Err.Clear
Exit Sub
You should add some details about your data and/or your intention.
Using subprocedures could simplify your debugging task.
Avoid "On Error Goto xxx" during development as you need the error details while debugging.
Using "Option Explicit" as a first line simplifies your debugging.
I hope this helps a little! ;-)
Option Explicit
Sub ActivateAlerts_ShowSheetX()
'Activate Alerts
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Application.UseSystemSeparators = True
ActiveWorkbook.Sheets("X").Visible = xlSheetVisible
End Sub
Sub main()
'Variables
Dim Destbook As Workbook
Dim Sourcebook As Workbook
Dim DestCell As Range
Dim xFile As String
Dim xFolder As String
Dim xFiles As New Collection
Dim xSheets As Worksheet
Dim xCount As Long
Dim xSheetCount As Long
Dim xRow As Long
Dim aCt As Integer
Dim iCt As Integer
Dim zCt As Integer
Dim xMax As Double
'On a System Error go to "Troubleshooting" and
'display the ocurred fault code
'On Error GoTo Troubleshooting
'You want to show Sheet("X") first and then
'Deactivate ScreenUpdating
' 'Deactivate Alerts
' Application.DisplayAlerts = False
' Application.ScreenUpdating = False
' Application.UseSystemSeparators = False
'Display hidden Sheet "X", select cell "A1" and freeze screen
' ------------------------- NOT WORKING ---------------------
ActiveWorkbook.Sheets("X").Visible = xlSheetVisible
With ActiveWorkbook.Sheets("X")
Application.Goto .Range("A1")
ActiveWindow.FreezePanes = True
End With
'Deactivate Alerts
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.UseSystemSeparators = False
'Delete contents for each Sheet containing the name "Data"
'for the selected range
' ------------------------- NOT WORKING ---------------------
xSheetCount = ActiveWorkbook.Worksheets.Count
For zCt = 1 To xSheetCount '
If Left(Sheets(zCt).Name, 4) = "Data" Then
With ActiveSheet
.Range("B5:K90000").ClearContents
End With
End If
Next zCt
'Select the folder with the desired data to import
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select Folder"
.ButtonName = "Import Data"
.InitialView = msoFileDialogViewList
If .Show = -1 Then xFolder = .SelectedItems(1)
If Right(xFolder, 1) <> "\" Then xFolder = xFolder & "\"
End With
'On error or no files found display the following
If xFolder = "" Then
MsgBox ("No files found or selected!")
Exit Sub
End If
Dim FS As Object
Dim Folder As Object
Dim myFile As Object
'Get the desired Textfiles in the selected Folder
Set FS = CreateObject("Scripting.FileSystemObject")
Set Folder = FS.Getfolder(xFolder)
For Each myFile In Folder.Files
If myFile.Name Like "*####-##-##*" Then
MsgBox (myFile.Name & " found!")
xFile = myFile.Name
If xFile <> "" Then
xCount = xCount + 1
xFiles.Add xFile, xFile
If xFile = "" Then Resume Next
End If
End If
Next myFile
'File processing
iCt = 1
Set Destbook = ThisWorkbook
MsgBox "xFiles count: " & xFiles.Count
If xFiles.Count > 0 Then
For aCt = 1 To xFiles.Count
Set Sourcebook = Workbooks.Open(xFolder & xFiles.Item(aCt), local:=True)
'Skip files with no current values greater than 2 A
xMax = Application.WorksheetFunction.Max(Range("C2:C90000"))
If xMax < 2 Then
GoTo ContinueLoop
End If
If InStr(1, ActiveSheet.Name, "Stufe", vbTextCompare) <> 0 Then
Columns("I:Y").Delete
Rows(1).Insert
Range("D1").Value = ActiveSheet.Name
xRow = Cells(Rows.Count, 1).End(xlUp).Row
ActiveSheet.Range("A1:J" & xRow).Copy
End If
ThisWorkbook.Sheets("Data (" + CStr(iCt) +")").Range("B3").PasteSpecial Paste:=xlPasteAll
Application.CutCopyMode = False
On Error Resume Next
On Error GoTo 0
iCt = iCt + 1
ContinueLoop:
Sourcebook.Close False
Next aCt
End If
'Just some formatting things...
' ------------------------- NOT WORKING ---------------------
xSheetCount = ActiveWorkbook.Worksheets.Count
For iCt = 1 To xSheetCount
If Left(Worksheets(iCt).Name, 4) = "Data" Then
With ActiveSheet.Range("A1:J" & xRow)
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
Range("B3:C3").Merge
Range("B3").Value = "Filename:"
Range("B3:K4").Font.Bold = True
Range("B4:K4").Borders.LineStyle = xlContinuous
End With
End If
Next iCt
'Delete sheet "Import data", hide sheet "X" and save file
'Sheets("Import data").Delete
ActiveWorkbook.Sheets("X").Visible = xlSheetVeryHidden
Application.DisplayAlerts = True
Application.ScreenUpdating = False
Application.UseSystemSeparators = True
'DestBook.SaveAs Filename:=CStr(Date) + "Analysis", FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
'Display the occured error message and exit program
Troubleshooting:
Application.DisplayAlerts = True
Application.ScreenUpdating = True
If Err.Number <> 0 Then MsgBox "Troubleshooting: " & _
Err.Number & vbLf & Err.Description: Err.Clear
Exit Sub
End Sub
I am trying to load some csv files from a folder to show its contents in a Userform, currently my code looks like this:
Private Sub btnGetData_Click()
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
Dim iIndex As Integer
Dim ws As Excel.Worksheet
Dim wb As Workbook
Dim strPath As String
Dim strFile As String
' Find .csv files in folder
strPath = "C:\mycsvfiles\"
strFile = Dir(strPath & "*.csv")
Do While strFile <> ""
Set wb = Workbooks.Open(FileName:=strPath & strFile, Local:=True)
For iIndex = 1 To wb.Worksheets.Count
Set ws = wb.Worksheets(iIndex)
' Populate UserForm
Me.textbox1.value = Trim(wb.Worksheets(1).Range("A2").value)
Me.textbox2.value = Trim(wb.Worksheets(1).Range("A4").value)
Me.textbox3.value = Trim(wb.Worksheets(1).Range("A6").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A8").value)
Me.textbox5.value = Trim(wb.Worksheets(1).Range("A9").value)
Me.textbox6.value = Trim(wb.Worksheets(1).Range("A11").value) & ", " & Trim(wb.Worksheets(1).Range("A12").value)
' Close csv file
Workbooks(strFile).Close SaveChanges:=False
Next iIndex
strFile = Dir 'This moves the value of strFile to the next file.
Loop
End Sub
So, when clicking button "btnGetData" all CSV files are found. When the loop ends, the fields in userform are populated with the last file found.
What I need is to load the files one by one while interacting with a previous and next file buttons like this:
Private Sub btn_NEXT_Click()
' Read content of next csv file found
End Sub
Private Sub btn_PREV_Click()
' Read content of previous csv file found
End Sub
Any help would be greatly appreciated.
EDIT:
Based on Brian M Stafford reply, I post the code that came up as solution to my problem, hopefully it can be of help to someone else.
Private Sub btnGetData_Click()
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
' Create collection of files
Dim f As String
Dim wb As Workbook
f = Dir("C:\somefolder\*.csv")
Set MyFiles = New Collection
Do While f <> ""
MyFiles.Add "C:\somefolder\" & f
f = Dir
Loop
' Set Index
CurrentIndex = 1
' Open Workbook
Set wb = Workbooks.Open(FileName:=MyFiles(CurrentIndex), Local:=True)
' Populate UserForm
Me.textbox1.value = Trim(wb.Worksheets(1).Range("A2").value)
Me.textbox2 = Trim(wb.Worksheets(1).Range("A4").value)
Me.textbox3.value = Trim(wb.Worksheets(1).Range("A6").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A8").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A9").value)
' Close Workbook
wb.Close SaveChanges:=False
End Sub
Private Sub btn_NEXT_Click()
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
' Set Index
CurrentIndex = CurrentIndex + 1
If CurrentIndex > MyFiles.Count Then CurrentIndex = MyFiles.Count
' Open Workbook
Set wb = Workbooks.Open(FileName:=MyFiles(CurrentIndex), Local:=True)
' Populate UserForm
Me.textbox1.value = Trim(wb.Worksheets(1).Range("A2").value)
Me.textbox2 = Trim(wb.Worksheets(1).Range("A4").value)
Me.textbox3.value = Trim(wb.Worksheets(1).Range("A6").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A8").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A9").value)
' Close Workbook
wb.Close SaveChanges:=False
End Sub
Private Sub btn_PREV_Click()
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
' Set Index
CurrentIndex = CurrentIndex - 1
If CurrentIndex < 1 Then CurrentIndex = 1
' Open Workbook
Set wb = Workbooks.Open(FileName:=MyFiles(CurrentIndex), Local:=True)
' Populate UserForm
Me.textbox1.value = Trim(wb.Worksheets(1).Range("A2").value)
Me.textbox2 = Trim(wb.Worksheets(1).Range("A4").value)
Me.textbox3.value = Trim(wb.Worksheets(1).Range("A6").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A8").value)
Me.textbox4.value = Trim(wb.Worksheets(1).Range("A9").value)
' Close Workbook
wb.Close SaveChanges:=False
End Sub
The challenge is maintaining an index into the files in your folder. Neither Dir nor FileSystemObject allow you to access files by index. One way to accomplish this is to place the files into a Collection which does allow access by index. I stripped the code down to illustrate this idea:
Option Explicit
Private MyFiles As Collection
Private CurrentIndex As Integer
Private Sub btnGetData_Click()
Dim f As String
f = Dir("c:\temp\csv\*.csv")
Set MyFiles = New Collection
Do While f <> ""
MyFiles.Add "c:\temp\csv\" & f
f = Dir
Loop
CurrentIndex = 1
Label1.Caption = MyFiles(CurrentIndex)
End Sub
Private Sub btnNext_Click()
CurrentIndex = CurrentIndex + 1
If CurrentIndex > MyFiles.Count Then CurrentIndex = MyFiles.Count
Label1.Caption = MyFiles(CurrentIndex)
End Sub
Private Sub btnPrevious_Click()
CurrentIndex = CurrentIndex - 1
If CurrentIndex < 1 Then CurrentIndex = 1
Label1.Caption = MyFiles(CurrentIndex)
End Sub
I'm trying to convert each sheet in a workbook to pdf files with "landscape layout", where the paper is laying down. But the paper orientation is definitely not landscape.
Can someone help me out?
It seems to be a general problem, however I can't find any solution which works for me.
Here is the code.
Sub Test()
Application.ScreenUpdating = False
Dim sFile As String
Dim sPath As String
Dim wks As Worksheet
With ActiveWorkbook
sPath = .Path & "\"
For Each wks In .Worksheets
sFile = wks.Name & ".pdf"
wks.ExportAsFixedFormat Type:=xlTypePDF, Filename:=sPath & sFile
Application.PrintCommunication = False
With wks.PageSetup
.Orientation = xlLandscape
.Zoom = False
.CenterHorizontally = True
.CenterVertically = True
.FitToPagesWide = 1
.FitToPagesTall = 1
'.BottomMargin = 0
'.TopMargin = 0
'.RightMargin = 0
'.LeftMargin = 0
End With
Application.PrintCommunication = True
Next wks
End With
Application.ScreenUpdating = True
End Sub
Please, try the next code:
Sub ExportAsPdfLandscape()
Dim wks As Worksheet, Path As String, strPName As String, strShName As String
Path = "Folder path where to be saved\" ' end it in "\", please!
strPName = Application.ActivePrinter 'this records the current printer
For Each wks In ActiveWorkbook.Worksheets
wks.PageSetup.Orientation = xlLandscape
strShName = Path & wks.Name & ".pdf"
wks.PrintOut , , 1, , ActivePrinter:="Microsoft Print to PDF", _
Printtofile:=False, collate:=True, PrToFileName:=strShName, Ignoreprintareas:=True
Next
Application.ActivePrinter = strPName 'return to the former current printer
End Sub
I am still new to VBA, I am just curious if anyone has any recommendations for improving or simplifying this code. The program works fine the way it is, however it has to sort through anywhere from 10 to 30 files and marge them all. It can take a long time depending on the file size. The Excel files range from a few hundred lines to 800,000 each. Thanks for your help!
Option Compare Text
Sub MergeAllFiles()
Dim wb As Workbook
Dim myPath As String, MyFile As String, myExtension As String, Col1 As
String, MyFolder As String, Title As String
Dim i As Integer, j As Integer, WS_Count As Integer, k As Integer
Dim FldrPicker As FileDialog
Dim Mynote As String, Answer As String
Mynote = "Does each file have the same number of export fields?"
Answer = MsgBox(Mynote, vbQuestion + vbYesNo, "Confirmation Needed")
If Answer = vbNo Then
MsgBox "Cancelled"
GoTo ResetSettings
End If
j = 1
i = 1
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
'Retrieve Target Folder Path From User
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select A Target Folder"
.AllowMultiSelect = False
.Show
MyFolder = .SelectedItems(1)
Err.Clear
End With
Set NewBook = Workbooks.Add
With NewBook
.Title = "MasterList"
ActiveWorkbook.SaveAs Filename:="Mastersheet.xlsx"
End With
'Loop through each Excel file in folder
MyFile = Dir(MyFolder & "\", vbReadOnly)
If MyFile = "Batch.xlsx" Then GoTo NextLoop
Do While MyFile <> ""
DoEvents
Workbooks.Open Filename:=MyFolder & "\" & MyFile, UpdateLinks:=False
Title = ActiveWorkbook.Name
ActiveWorkbook.Sheets(i).Select
With ActiveWorkbook.Sheets(i)
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode)
Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
End If
End With
k = 1
l = 1
If j = 1 Then
k = 0
l = 0
End If
With Range("A1:AB1000000")
Set rFind = .Find(What:="Total Rate (Linehaul + Acc)",
LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
ActiveSheet.Range("A1:ABC1000000").AutoFilter
Field:=rFind.Column, Criteria1:="="
ActiveSheet.Range("A1:ABC1000000").Offset(1,
0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
ActiveSheet.AutoFilterMode = False
End With
ActiveSheet.UsedRange.Offset(l).Copy
Workbooks("Mastersheet.xlsx").Activate
Range("A" & Rows.Count).End(xlUp).Offset(k).Select
Selection.PasteSpecial Paste:=xlPasteAllExceptBorders,
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Workbooks(Title).Activate
Application.CutCopyMode = False
Workbooks(MyFile).Close SaveChanges:=True
j = j + 1
If j = 50 Then Exit Do
NextLoop:
MyFile = Dir
Loop
ResetSettings:
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Not sure if my code does exactly what yours does (had no sample data/input to check the output against), but maybe something like this:
Option Explicit
Private Sub MergeAllFiles()
If MsgBox("Does each file have the same number of export fields?", vbQuestion + vbYesNo, "Confirmation Needed") = vbNo Then
MsgBox "Files do not have same number of export fields. Code will stop running now."
Exit Sub
End If
'Retrieve Target Folder Path From User
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select A Target Folder"
.AllowMultiSelect = False
.Show
If .SelectedItems.Count = 0 Then
MsgBox "Folder selection cancelled. Code will stop running now."
Exit Sub
End If
Dim folderPath As String
folderPath = .SelectedItems(1)
If VBA.Strings.StrComp(VBA.Strings.Right$(folderPath, 1), "\", vbBinaryCompare) <> 0 Then
folderPath = folderPath & "\"
End If
End With
Dim masterWorksheet As Worksheet
With Workbooks.Add
.SaveAs Filename:=ThisWorkbook.Path & "\Mastersheet.xlsx"
Set masterWorksheet = .Worksheets(1)
End With
' If you're only interested in .xlsx files, then maybe specify the file extension upfront
' when using dir(). This ensures you only loop through files with the given file extension.
' But if you do want multiple file extensions, you could remove extension from the dir()
' and just check file extension inside the loop.
Dim Filename As String
Filename = VBA.FileSystem.Dir$(folderPath & "*.xlsx", vbReadOnly)
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim workbookToCopyFrom As Workbook
Dim fileCount As Long
Dim cellFound As Range
Dim blankRowsToDelete As Range
Dim lastRow As Long
Do While Len(Filename) <> 0
If VBA.Strings.StrComp(Filename, "Batch.xlsx", vbBinaryCompare) <> 0 Then
fileCount = fileCount + 1
Set workbookToCopyFrom = Application.Workbooks.Open(Filename:=folderPath & Filename, UpdateLinks:=False)
' Did you want to copy-paste from all worksheets
' or just the worksheet at the first index?
With workbookToCopyFrom.Worksheets(1)
If .AutoFilterMode Then .AutoFilter.ShowAllData
With .Range("A1:AB1000000")
' Presume this check is done because you want to include headers the first time,
' but exclude headers for any subsequent files.
If fileCount = 1 Then
.Rows(1).Copy masterWorksheet.Rows(1)
End If
Set cellFound = .Find(What:="Total Rate (Linehaul + Acc)", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
' It's worth checking if the previous line found anything
' If it didn't, you will get an error below when accessing the 'column' property
.AutoFilter Field:=cellFound.Column, Criteria1:="="
Set blankRowsToDelete = Application.Intersect(.EntireRow, .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow)
If Not (blankRowsToDelete Is Nothing) Then
blankRowsToDelete.Delete
End If
.Parent.AutoFilterMode = False
End With
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
If lastRow > 1 Then
.Range("A2:AB" & lastRow).Copy
masterWorksheet.Range("A" & .Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteAllExceptBorders, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
workbookToCopyFrom.Close SaveChanges:=False
End If
End With
If fileCount = 50 Then Exit Do
End If
DoEvents
Filename = Dir$()
Loop
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Everything in this code works fine, except at the very end when I go to close the workbook that I am performing some operations on. I'm inserting some code into ThisWorkbook of the workbook that I'm opening from a text file and also copying a few tabs in my master spreadsheet to each workbook that I open in this loop. At the end of the loop it crashes when I try to close and move on to the next workbook.
Sub AddSht_AddCode()
Dim wb As Workbook
Dim xPro As VBIDE.VBProject
Dim xCom As Variant
Dim xMod As VBIDE.CodeModule
Dim xLine As Long
Dim strFolderPath As String
Dim strFolderPathTo As String
Dim strCodePath As String
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim mergearea As Range
Dim c As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
strFolderPath = Sheets("Master - DO NOT MOVE").Range("B2").Value
strCodePath = Sheets("Master - DO NOT MOVE").Range("b18").Value
If IsNull(strFolderPath) Or strFolderPath = "" Then
MsgBox "Please make sure you have a valid DFF path entered in Cell B2 on the Master worksheet.", vbOKOnly
Exit Sub
End If
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Dir(strFolderPath, vbDirectory) = "" Then
MsgBox "The DFF folder path entered is not a valid path. Please edit and try again.", vbOKOnly
Exit Sub
Else
Set objFolder = objFSO.GetFolder(strFolderPath)
End If
'create_projid_array
'create_projid_new
For Each objFile In objFolder.Files
'If (InStr(objFile.Name, ".xlsm") > 0 Or InStr(objFile.Name, ".xlsx") > 0) And check_var_array(Left(objFile.Name, InStr(1, objFile.Name, ".") - 1), projarray) = 1 Then
'If (InStr(objFile.Name, ".xlsx") > 0 Or InStr(objFile.Name, ".xlsb") > 0) And check_var_array(Left(objFile.Name, InStr(1, objFile.Name, ".") - 1), projarray) = 1 Then
If (InStr(objFile.Name, ".xlsm") > 0) Then
'If check_var_array(objFile.Name, projarray) = 1 Then
Application.AutomationSecurity = msoAutomationSecurityLow
Set wb = Workbooks.Open(objFile, False)
'Application.AutomationSecurity = msoAutomationSecurityByUI
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Right(objFile.Name, 5) = ".xlsx" Then
Sheets(Array("Template", "Log")).Copy After:=wb.Sheets(1)
If Sheets("Master - DO NOT MOVE").Range("B4") = True Then
wb.Activate
wb.Sheets("Data").UsedRange.Clear
wb.Sheets("Data").Range("A1").Value = 0
Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Data").Range("B1:BO2400").Copy Destination:=wb.Sheets("Data").Range("B1")
End If
End If
wb.Activate
wb.Sheets(1).Visible = xlSheetVisible
wb.Sheets(1).Unprotect Password:="xxxxxxxxx"
Set mergearea = wb.Sheets(1).Range("i5:l6")
For Each c In mergearea
If c.MergeCells Then
c.UnMerge
End If
Next
wb.Sheets(1).Range("J5").ClearContents
wb.Sheets(1).Range("j6").ClearContents
'Selection.UnMerge
'Selection.ClearContents
If Right(objFile.Name, 5) = ".xlsm" Then
wb.Sheets("Template").Visible = xlSheetVisible
wb.Sheets("Data").Visible = xlSheetVisible
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Sheets("Master - DO NOT MOVE").Range("B4") = True Then
wb.Activate
wb.Sheets("Data").UsedRange.Clear
wb.Sheets("Data").Range("A1").Value = 0
Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Data").Range("B1:BO2400").Copy Destination:=wb.Sheets("Data").Range("B1")
End If
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Sheets("Master - DO NOT MOVE").Range("B6") = True Then
wb.Activate
wb.Sheets("Template").UsedRange.Clear
Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Template").Range("A1:G524").Copy Destination:=wb.Sheets("Template").Range("A1")
If Left(wb.Sheets(1).Range("I7"), 3) = "PO " Or Left(wb.Sheets(1).Range("I7"), 3) = "PO#" Then
wb.Sheets(1).Range("I7").Copy Destination:=wb.Sheets("Template").Range("F3")
End If
End If
End If
wb.Activate
Call update_dropdowns
Call update_ga_formula(wb.Name)
wb.Sheets(Array("Template", "Data")).Select
ActiveWindow.SelectedSheets.Visible = False
wb.Activate
With wb
Set xPro = .VBProject
Set xCom = xPro.VBComponents("ThisWorkbook")
Set xMod = xCom.CodeModule
xMod.DeleteLines 1, _
xMod.CountOfLines
xMod.AddFromFile strCodePath
End With
wb.Activate
With wb.Sheets(1)
.Protect Password:="xxxxxxx", UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, DrawingObjects:=False, Contents:=True, Scenarios:=True, AllowFiltering:=True
.EnableOutlining = True
End With
wb.Save
wb.Close <<<<<EXCEL CRASHES HERE>>>>>>>
End If
Next
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Just to finalize:
In my specific situation I was adding a BeforeClose Event to the target workbook ThisWorkbook object. In the code that is performing this operation, it was crashing after the BeforeClose code was inserted in the target workbook and upon having the source code try to close the workbook with wb.Close.
I changed:
wb.Close
to
Application.EnableEvents = False
wb.Close
Application.EnableEvents = True
So, bypassed the target workbook events altogether and it's fixed.
Check the code in the wb close / save events for any invalid actions:
BeforeClose()
BeforeSave()
SheetDeactivate()
WindowDeactivate(), etc
Not related, but remove the .Activate statements and qualify the objects if needed
For example:
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Sheets("Master - DO NOT MOVE").Range("B4") = True Then
should be replaced with
If Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Master - DO NOT MOVE").Range("B4") = True Then
Statements .Select and .Activate are not needed and have poor performance