I am trying to merge 4 models into one. All models have a common part of the code as well as a model specific parts. I have created a user form, which identifies what model to run based on the criteria selected by user. So the user form has 4 criteria and produces 12 different outcomes. So I want to create a sub which will run the commons parts of the code for all outcomes and then outcome specific parts.
Currently the user form code displays message boxes depending on the selection. I want to connect this code (see it below) to the code in the VBA model and use in the IF structure. For example, if a user select Template 1, Private data type and Tier 2, No Wipe Out then the model will run the common part, then the parts for Template 1 with Private data type, Tier 2 and No Wipe Out and then again a common part.
For example, the Wipe Out/No Wipe Out part is similar for all models. Other parts have a lot of similarities.
Here is the User Form code:
Private Sub modelrun_btn_Click()
If radiotempl1.Value = True Then
If datatype.Value = "Public" Then
If wipe_format.Value = True Then
MsgBox "Template 1 Public Model Wipe Out"
Else
MsgBox "Template 1 Public Model No Wipe Out"
End If
ElseIf datatype.Value = "Private" Then
If radiotier1.Value = True Then
If wipe_format.Value = True Then
MsgBox "Template 1 Private Model Tier 1 Wipe Out"
Else
MsgBox "Template 1 Private Model Tier 1 No Wipe Out"
End If
Else
If wipe_format.Value = True Then
MsgBox "Template 1 Private Model Tier 2 Wipe Out"
Else
MsgBox "Template 1 Private Model Tier 2 No Wipe Out"
End If
End If
Else
MsgBox "Please select a data type"
End If
ElseIf radiotempl2.Value = True Then
If datatype.Value = "Public" Then
If wipe_format.Value = True Then
MsgBox "Template 2 Public Model Wipe Out"
Else
MsgBox "Template 2 Public Model No Wipe Out"
End If
ElseIf datatype.Value = "Private" Then
If radiotier1.Value = True Then
If wipe_format.Value = True Then
MsgBox "Template 2 Private Model Tier 1 Wipe Out"
Else
MsgBox "Template 2 Private Model Tier 1 No Wipe Out"
End If
ElseIf radiotier2.Value = True Then
If wipe_format.Value = True Then
MsgBox "Template 2 Private Model Tier 2 Wipe Out"
Else
MsgBox "Template 2 Private Model Tier 2 No Wipe Out"
End If
Else
MsgBox "Please select a tier"
End If
Else
MsgBox "Please select a data type"
End If
Else
MsgBox "Please select a template"
End If
End Sub
And this is an example of one of the models. Basically it opens an Excel file generated by a different programme, copies one or two worksheets into the model (depending on template), there are worksheets in teh model with commented out formulas, so the macro uncomments them, hides those which are not needed and does some formatting.
Sub UploadData()
Dim FileOpenDial As Variant
Dim FileSaveAs As Variant
Dim wb As Workbook
Dim activeWB As Workbook
Dim bFileSaveAs As Boolean
Dim finstart As Range
Dim endcell As Range, startcell As Range
Dim yearsno As Range
Dim numrowsadj As Integer
Dim cfyearsno As Range
Dim numrows As Integer
Dim numrowscf As Integer
Dim c As Range
Dim decimaltab As Range
Dim d As Range
Dim MySheets As Variant
Dim r As Range
'Import the data
'Optimize Code
Application.ScreenUpdating = False
EventState = Application.EnableEvents
Application.EnableEvents = False
CalcState = Application.Calculation
Application.Calculation = xlCalculationManual
PageBreakState = ActiveSheet.DisplayPageBreaks
ActiveSheet.DisplayPageBreaks = False
Application.DisplayAlerts = False
Set activeWB = Application.ActiveWorkbook
FileOpenDial = Application.GetOpenFilename(FileFilter:="Excel Files (*.XML), *.XML", Title:="Select File To Be Opened")
If FileOpenDial = False Then Exit Sub
Set wb = Workbooks.Open(FileOpenDial)
Sheets(Array("Accounts", "Types")).Select
Sheets(Array("Accounts", "Types")).Copy Before:=activeWB.Sheets(1)
wb.Close savechanges:=False 'or True
'Save a file
FileSaveAs = Application.GetSaveAsFilename(FileFilter:="Exel Files (*.xlsx), *.xlsx", Title:="Select Name To Save The File")
If FileSaveAs <> False Then
ActiveWorkbook.SaveAs Filename:=FileSaveAs, _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
End If
'Unhide sheets
For Each MySheets In Array("FS", "CF", "tables", "Calcs", "tables_for_output", "Tier_I", "Tier_II")
Worksheets(MySheets).Visible = True
Next
'Build tables from the data
Sheets("FS").Select
'Remove apostrophe from the formulas
For Each c In Range("D1:D250").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
'FillRight Formulas
Set yearsno = ThisWorkbook.Sheets("Accounts").Range("F2:Z2")
numrows = Application.WorksheetFunction.CountA(yearsno)
If 5 - numrows >= 0 Then
numrowsadj = 0
Else: numrowsadj = 5 - numrows
End If
With ThisWorkbook.Sheets("FS")
Set startcell = .Range("D1")
Set endcell = Cells(Range("D" & Rows.Count).End(xlUp).Row, 3 + numrows + numrowsadj)
Set finstart = .Range(startcell.Address & ":" & endcell.Address)
finstart.FillRight
End With
ThisWorkbook.Sheets("FS").Range("C1").Select
'Build CF
Sheets("CF").Select
'Remove apostrophe from the formulas
For Each c In Range("F1:F160").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
'FillRight Formulas
Set cfyearsno = ThisWorkbook.Sheets("FS").Range("C1:XFD1")
numrowscf = Application.WorksheetFunction.CountA(cfyearsno)
With ThisWorkbook.Sheets("CF")
Set startcell = .Range("F1")
If numrowscf = 3 Then
Set endcell = Range("F" & Rows.Count).End(xlUp).Offset(, 1)
Set finstart = .Range(startcell.Address & ":" & endcell.Address)
finstart.FillRight
ElseIf numrowscf > 3 Then
Set endcell = Range("F" & Rows.Count).End(xlUp).Offset(, 2)
Set finstart = .Range(startcell.Address & ":" & endcell.Address)
finstart.FillRight
Else
End If
End With
ThisWorkbook.Sheets("CF").Range("E1").Select
'Activite the Summary tables
Sheets("tables").Select
For Each c In Range("C1:G88").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
Sheets("tables").Range("B1").Select
'Activate Calcs
Sheets("Calcs").Select
'Remove apostrophe from the formulas
For Each c In Range("B1:H22").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
'Activate tables_for_output
Sheets("tables_for_output").Select
For Each c In Range("B2:O43").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
'Activate Tier_I
Sheets("Tier_I").Select
For Each c In Range("D6:I15").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
'Activate Tier_II
Sheets("Tier_II").Select
For Each c In Range("D6:I15").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
'Hide the working worksheets
Sheets(Array("Model", "Calcs")).Visible = False
'Stop Optimize Code
'Call OptimizeCode_End
'ActiveSheet.DisplayPageBreaks = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
'Replace Conditional formating with normal based on a checkbox
If Sheets("Model").Shapes("Check Box 7").ControlFormat.Value = 1 Then
Sheets("tables_for_output").Select
Range("F4:O4").Select
For Each r In Selection
r.Interior.Color = r.DisplayFormat.Interior.Color
Next r
Selection.FormatConditions.Delete
'Tier_I
Sheets("Tier_I").Select
Range("F6:H15").Select
For Each r In Selection
r.Interior.Color = r.DisplayFormat.Interior.Color
Next r
Selection.FormatConditions.Delete
Sheets("Tier_I").Range("C2").Select
'Tier_II
Sheets("Tier_II").Select
Range("F6:H15").Select
For Each r In Selection
r.Interior.Color = r.DisplayFormat.Interior.Color
Next r
Selection.FormatConditions.Delete
End If
ThisWorkbook.Sheets("tables_for_output").Select
Sheets("tables_for_output").Range("A1").Select
ThisWorkbook.Sheets("Tier_II").Select
Sheets("Tier_II").Range("C2").Select
'Hide a Tier sheet based on the selection
If Sheets("Calcs").Range("B24").Value = 1 Then
Sheets("Tier_II").Visible = False
ElseIf Sheets("Calcs").Range("B24").Value = 2 Then
Sheets("Tier_I").Visible = False
End If
'Formatting
'Columns Width
ThisWorkbook.Sheets("FS").Cells.SpecialCells(xlCellTypeVisible).EntireColumn.AutoFit
ThisWorkbook.Sheets("CF").Cells.SpecialCells(xlCellTypeVisible).EntireColumn.AutoFit
'Decimal Formatting
'tables
Sheets("tables").Select
Set decimaltab = [C2:E16,C25:E49,C62:E69,C71:E75,C77:E83]
For Each d In decimaltab.SpecialCells(xlCellTypeFormulas, xlNumbers)
If Abs(d.Value) < 20 And Round(d.Value, 0) <> 0 Then
d.NumberFormat = "0.0;(0.0)"
Else
d.NumberFormat = "#,##0;(#,##0)"
End If
Next d
'tables_for_output
Sheets("tables_for_output").Select
Set decimaltab = [B2:B3,B11:D15,B17:D18,B20:D23,B33:D34,B37:D39,B43:D43]
For Each d In decimaltab.SpecialCells(xlCellTypeFormulas, xlNumbers)
If Abs(d.Value) < 101 And Round(d.Value, 0) <> 0 Then
d.NumberFormat = "0.0;(0.0)"
Else
d.NumberFormat = "#,##0;(#,##0)"
End If
Next d
Application.ScreenUpdating = True
ActiveWorkbook.Save
End Sub
I just cannot figure out a good way to integrate the user form into the existing code. I guess I need to get the output of the user form in a form of variable and them to build an algorithm. But I do not know how to start.
Basically I need to achieve the following algorithm:
Fill User Form
If any of the options are not selected ask user to do it
Run Upload Data sub
Optimise
Open external Excel file
If Template 1 Selected Then
Import Accounts and Types sheets
Else
Import Accounts sheet
End If
Save file under a different name
Unhide hiden templates
If Template 1 Then
If datatype Private Then
Unhide FS_1, CF_1, tables, calcs, tables_for_output, Tier 1, Tier 2
Rename FS_1 and CF_1 to FS and CF
Else
Unhide FS_1, CF_1, tables
Rename FS_1 and CF_1 to FS and CF
Else
If datatype Private Then
Unhide FS_2, CF_2, tables, calcs, tables_for_output, Tier 1, Tier 2
Rename FS_2 and CF_2 to FS and CF
Else
Unhide FS_2, CF_2
Rename FS_2 and CF_2 to FS and CF
End If
End If
Activite Templates
Activate FS
Activate CF
Activate tables
If datatype Private
Activate calcs
Acivate tables_for_output
Activate Tier 1
Activate Tier 2
Otimisation ends
Tidying up
Hide unneeded sheets
If datatype Private Then
If Tier 1 Then
Hide Model, cacls, Tier 2
Else
Hide Model, calcs, Tier 1
Else
Hide Model
End If
If datatype Private replace conditional formatting with normal
If Tier 1
In tables_for_otput, Tier 1
Else
in tables_for_output, Tier 2
End If
Additional Formattng
If datatype Public
Format FS, CF, tables
Else
Format FS, CF, table, tables for output
End If
Workbook Save
Sub End
I've worked on it last weekend but got interrupted rather early on. Apologies for the delay.
The ByVal wasn't really needed here, I may have worded myself incorrectly. Here's the documentation in case you'd like to read up on it: Byval & ByRef
As for the code, I tried to get it done the way you mentioned but wipe_out was not included in your Sub? So couldn't implement it either.
Hope the code works and was the way you specified:
Option Explicit
Sub UploadData()
Dim FileOpenDial As Variant
Dim FileSaveAs As Variant
Dim wb As Workbook, activeWB As Workbook
Dim bFileSaveAs As Boolean
Dim finstart As Range, endcell As Range, startcell As Range
Dim yearsno As Range, cfyearsno As Range
Dim numrows As Long, numrowscf As Long, numrowsadj As Long 'I prefer to not have number rows in Integer due to limitations of size
Dim c As Range, d As Range, r As Range, decimaltab As Range
Dim MySheets As String, tier As String
Dim templ As Integer, dType As Integer, wipe As Integer
'Checking user form
If radiotempl1.Value Then templ = 1
ElseIf radiotempl2.Value Then templ = 2
Else
MsgBox "Please select a template"
End If
If dataType.Value = "Public" Then
dType = 1
ElseIf dataType.Value = "Private" Then
dType = 2
Else
MsgBox "Please select a data type"
End If
If wipe_format.Value Then wipe = 1
If radiotier1.Value Then tier = "Tier_1"
If radiotier2.Value Then tier = "Tier_2"
Else
If dType = 2 Then
MsgBox "Please select a tier"
Exit Sub
End If
End If
If templ + dType < 2 Then Exit Sub
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
ActiveSheet.DisplayPageBreaks = False
Application.DisplayAlerts = False
Set activeWB = Application.ActiveWorkbook
FileOpenDial = Application.GetOpenFilename(FileFilter:="Excel Files (*.XML), *.XML", Title:="Select File To Be Opened")
If FileOpenDial = False Then Exit Sub
Set wb = Workbooks.Open(FileOpenDial)
'you mentioned "copies one or two worksheets into the model (depending on the template) but I'm not sure which way you wanted this
Sheets(Array("Accounts", "Types")).Copy Before:=activeWB.Sheets(1) 'avoid select as much as possible
wb.Close savechanges:=False 'or True
'Save a file
FileSaveAs = Application.GetSaveAsFilename(FileFilter:="Exel Files (*.xlsx), *.xlsx", Title:="Select Name To Save The File")
If FileSaveAs <> False Then
ActiveWorkbook.SaveAs Filename:=FileSaveAs, _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
End If
copySheet "FS", templ 'this is to copy the right sheet and delete the FS if it alreasdy existed from a previous time you ran the code
copySheet "CF", templ
Set yearsno = ThisWorkbook.Sheets("Accounts").Range("F2:Z2")
With Sheets("FS")
'Remove apostrophe from the formulas
For Each c In .Range("D1:D250").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
numrows = Application.WorksheetFunction.CountA(yearsno)
If 5 - numrows >= 0 Then
numrowsadj = 0
Else: numrowsadj = 5 - numrows
End If
Set startcell = .Range("D1")
Set endcell = Cells(Range("D" & Rows.Count).End(xlUp).Row, 3 + numrows + numrowsadj)
Set finstart = .Range(startcell.Address & ":" & endcell.Address)
finstart.FillRight
Set cfyearsno = .Range("C1:XFD1")
numrowscf = Application.WorksheetFunction.CountA(cfyearsno)
End With
With Sheets("CF")
'Remove apostrophe from the formulas
For Each c In Range("F1:F160").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
Set startcell = .Range("F1")
If numrowscf = 3 Then
Set endcell = Range("F" & Rows.Count).End(xlUp).Offset(, 1)
Set finstart = .Range(startcell.Address & ":" & endcell.Address)
finstart.FillRight
ElseIf numrowscf > 3 Then
Set endcell = Range("F" & Rows.Count).End(xlUp).Offset(, 2)
Set finstart = .Range(startcell.Address & ":" & endcell.Address)
finstart.FillRight
Else
End If
End With
With Sheets("tables")
For Each c In .Range("C1:G88").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
End With
With Sheets("Calcs")
For Each c In Range("B1:H22").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
End With
With Sheets("tables_for_output")
For Each c In Range("B2:O43").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
End With
'no need to hide sheets if you keep them hidden :)
Calculate
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
With Sheets("tables_for_output")
For Each r In Range("F4:O4")
r.Interior.Color = r.DisplayFormat.Interior.Color
Next r
Range("F4:O4").FormatConditions.Delete
End With
If dType = 2 Then
With Sheets(tier) 'same here as last time with tier
For Each c In .Range("D6:I15").SpecialCells(xlCellTypeConstants)
c.Formula = Replace(c.Formula, "'", "")
Next c
For Each r In Range("F6:H15")
r.Interior.Color = r.DisplayFormat.Interior.Color
Next r
Range("F6:H15").FormatConditions.Delete
.Visible = True
End With
End With
'Formatting
'Columns Width
ThisWorkbook.Sheets("FS").Cells.SpecialCells(xlCellTypeVisible).EntireColumn.AutoFit
ThisWorkbook.Sheets("CF").Cells.SpecialCells(xlCellTypeVisible).EntireColumn.AutoFit
'Decimal Formatting
'tables
With Sheets("tables")
Set decimaltab = Union(.Range("C2:E16"), .Range("C25:E49"), .Range("C62:E69"), .Range("C71:E75"), .Range("C77:E83"))
For Each d In decimaltab.SpecialCells(xlCellTypeFormulas, xlNumbers)
If Abs(d.Value) < 20 And Round(d.Value, 0) <> 0 Then
d.NumberFormat = "0.0;(0.0)"
Else
d.NumberFormat = "#,##0;(#,##0)"
End If
Next d
'tables_for_output
With Sheets("tables_for_output")
Set decimaltab = Union(.Range("B2:B3"), .Range("B11:D15"), .Range("B17:D18"), .Range("B20:D23"), .Range("B33:D34"), .Range("B37:D39"), .Range("B43:D43"))
For Each d In decimaltab.SpecialCells(xlCellTypeFormulas, xlNumbers)
If Abs(d.Value) < 101 And Round(d.Value, 0) <> 0 Then
d.NumberFormat = "0.0;(0.0)"
Else
d.NumberFormat = "#,##0;(#,##0)"
End If
Next d
.Activate
'You will have to decide which sheet you actually want to be presented first but I got rid of the copious use of .Select
'For now it's this one
End With
Application.ScreenUpdating = True
ActiveWorkbook.Save
End Sub
Sub copySheet(shtName As String, templNo As Integer)
If WorksheetExists(shtName) Then ActiveWorkbook.Sheets(shtName).Delete
shtName = shtName & "_" & templNo
Sheets(shtName).Copy After:=Worksheets(Worksheets.Count)
With ActiveSheet
.Name = Left(shtName, 2)
.Visible = True
End With
End Sub
Function WorksheetExists(shtName As String, Optional wb As Workbook) As Boolean
Dim sht As Worksheet
If wb Is Nothing Then Set wb = ActiveWorkbook
On Error Resume Next
Set sht = wb.Sheets(shtName)
On Error GoTo 0
WorksheetExists = Not sht Is Nothing
End Function
If you have any more questions, feel free to ask
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 have a workbook with 2 sheets (one to place the data and another for options).
The one with the data it has some buttons (at row 1), some textBox and DropBox (at row 2) and at row 3 are the headers of the table with all the data below.
The sheet with the options for the moment has only one button to recreate the menu (the TextBox and DropBox at row 2 in the data sheet)
However when pressing the button to run the macro it gives error 400 with no description and a red x signal. Sometimes it gives error when re-creating and first textBox, sometimes the second or third as well (never the fourth or the fifth).
Why does such 400 error happen ? What causing it ?
When trying debug the code i placed some Debug.Print in some places and after running 3 times (after clicking in button 3 times this is the output in the immediate window.
-----------Running createMenu-----------
TextBox5 DIM done
TextBox5 Set done
TextBox6 Delete
-----------Running createMenu-----------
TextBox5 Delete
TextBox5 DIM done
TextBox5 Set done
TextBox6 DIM done
TextBox6 Set done
TextBox7 Delete
-----------Running createMenu-----------
TextBox5 Delete
The code below (the one to recreate the menus) is placed in the data worksheet.
Sub createMenu()
Debug.Print "-----------Running createMenu-----------"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Dados1")
With ws
.Range("A2").NumberFormat = "0"
.Range("B2").NumberFormat = "dd-mm-yyyy"
.Range("C2:D2").Merge
.Range("C2:D2").NumberFormat = "hh:mm:ss"
Call newTextBox(.Range("E2"))
Application.Wait (Now + TimeValue("0:00:02"))
Call newTextBox(.Range("F2"))
Application.Wait (Now + TimeValue("0:00:02"))
Call newTextBox(.Range("G2"))
Application.Wait (Now + TimeValue("0:00:02"))
Call newTextBox(.Range("H2"))
Application.Wait (Now + TimeValue("0:00:02"))
Call newTextBox(.Range("I2"))
Call newDropBox(.Range("J2"), "=Opções!A1:A14")
Call newDropBox(.Range("K2"), "=Opções!B1:B2")
.Range("A2:N2").HorizontalAlignment = xlCenter
End With
End Sub
Sub newDropBox(t As Range, list As String)
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Dados1")
With ws.Range(t.Address).Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=list
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End Sub
Sub newTextBox(t As Range)
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Dados1")
With ws
Dim OLEObj As OLEObjects
If .OLEObjects.Count > 0 Then
Dim x As Integer
For x = 1 To .OLEObjects.Count
If .OLEObjects(x).Name = "TextBox" & t.Column Then
.OLEObjects(x).Delete
Debug.Print "TextBox" & t.Column & " Delete"
End If
Next x
End If
Dim myTextBox As OLEObject
Debug.Print "TextBox" & t.Column; " DIM done"
Set myTextBox = .OLEObjects.Add("Forms.TextBox.1")
Debug.Print "TextBox" & t.Column; " Set done"
With myTextBox
.Name = "TextBox" & t.Column
.LinkedCell = t.Address
.Left = t.Cells.Left
.Top = t.Cells.Top
.Width = t.Cells.Width
.Height = t.Cells.Height
.Object.BackColor = 16777152
.Object.BorderStyle = 1
.Object.BorderColor = 0
End With
End With
End Sub
So i find out the reason ...
So when i am doing the for loop he started by finding (lets say 2 OLEObjects).
If the in the first cycle of the loop the wanted object is found he delete one of the objects making it the total OLEObjects count to less 1.
There for when cycling to the second OLEObjects he will not find it, and throw such 400 error.
So the fix i done was exit the loop when the target OLEObjects is found.
Sub newTextBox(t As Range)
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Dados1")
With ws
Dim OLEObj As OLEObjects
If .OLEObjects.Count > 0 Then
Dim x As Integer
For x = 1 To .OLEObjects.Count
If .OLEObjects(x).Name = "TextBox" & t.Column Then
.OLEObjects(x).Delete
Exit For
End If
Next x
End If
Dim myTextBox As OLEObject
Set myTextBox = .OLEObjects.Add("Forms.TextBox.1")
With myTextBox
.Name = "TextBox" & t.Column
.LinkedCell = t.Address
.Left = t.Cells.Left
.Top = t.Cells.Top
.Width = t.Cells.Width
.Height = t.Cells.Height
.Object.BackColor = 16777152
.Object.BorderStyle = 1
.Object.BorderColor = 0
End With
End With
End Sub
I've been wrestling with using Excel to create PowerPoint slide using a .potx file as the powerpoint template.
The problem I have is that I am not able to figure out how to duplicate the slidemaster so I can use custom layouts.
I want a new presentation created that uses the layouts defined in the .potx file?
I'm brand new to VBA so my code is a little rough on the edges.
Sub ExcelRangeToPowerPoint()
'PURPOSE: Copy/Paste An Excel Range Into a New PowerPoint Presentation
'SOURCE: www.TheSpreadsheetGuru.com
Dim PowerPointApp As Object
Dim myPresentation As Object
Dim mySlide As Object
Dim myShape As Object
Dim mytextbox As Object
Dim Ws As Worksheet
Dim trueranges As New Collection 'Store the ranges to be used in master excel file
Dim start_counting_from_this_row_number As Integer 'starting value of rows to search for TRUE/FALSE
Dim worksheetnames As New Collection 'collect all worksheet names if TRUE
Dim rg As Range
Const PXLtoINCH As Single = 72# 'PP uses pixels not inches, this is the conversion factor
Dim SQPOSITION As Double
Dim SQHeight As Double
Dim range_shape As New WSOrgDisplayAttributes
Dim all_data As New Collection
'*******************************************************************************************************************
'Check to see if Master Data Sheet Spreadsheet is in same directory and if so, open it.
Dim FilePath As String
Dim FileNameOnly As String
FileNameOnly = "WS Asset Availability Master Data Spreadsheet.xlsx"
FilePath = ActiveWorkbook.Path & "\" & FileNameOnly
If IsFile(FilePath) = True Then 'ENDIF is near the end of the SUB
If CheckFileIsOpen(FileNameOnly) = False Then
Workbooks.Open (FileName)
MsgBox ("A small time Delay...(This ensures file is open and ready for use")
Application.Wait (Now + TimeValue("00:00:10")) 'this allows time to open before other parts of macro run
End If
'*******************************************************************************************************************
'*******************************************************************************************************************
'Create an Instance of PowerPoint
On Error Resume Next
'Is PowerPoint already opened?
Set PowerPointApp = GetObject(Class:="PowerPoint.Application")
'Clear the error between errors
Err.Clear
'If PowerPoint is not already open then open PowerPoint
If PowerPointApp Is Nothing Then Set PowerPointApp = CreateObject(Class:="PowerPoint.Application")
'Handle if the PowerPoint Application is not found
If Err.Number = 429 Then
MsgBox "PowerPoint could not be found, aborting."
Exit Sub
End If
On Error GoTo 0
'Optimize Code
Application.ScreenUpdating = False
'Create a New Presentation
Set myPresentation = PowerPointApp.Presentations.Add
myPresentation.ApplyTemplate (ThisWorkbook.Path & "\" & "SRR Template.potx")
'myPresentation.ApplyTemplate (FilePath & "\" & "SRR Template.potx")
'*******************************************************************************************************************
'*******************************************************************************************************************
'Initialize variables
start_counting_from_this_row_number = 3 'Find row where first TRUE/FALSE is under column "D"
Set rg = ThisWorkbook.Sheets("SRR Helper").Range("D1").CurrentRegion 'count the max rows
SQPOSITION = 6 'inches
SQHeight = 0.18 'inches
'*******************************************************************************************************************
'*******************************************************************************************************************
'Push all TRUE's to collections
'ADD HEADER INFO LATER
For x = start_counting_from_this_row_number To rg.Rows.Count
If ThisWorkbook.Sheets("SRR Helper").Range("D" & x).Value = True Then
Set range_shape = Nothing
range_shape.let_range_check = True
range_shape.let_shape_range = ThisWorkbook.Sheets("SRR Helper").Range("C" & x).Value
range_shape.let_sheet_name = ThisWorkbook.Sheets("SRR Helper").Range("E" & x).Value
all_data.Add range_shape
End If
Next x
'*******************************************************************************************************************
'*******************************************************************************************************************
'Iterate through collections to push Master File to PP presenation
Dim iterator As New WSOrgDisplayAttributes
Dim iterator2 As New WSOrgDisplayAttributes
Set mySlide = myPresentation.Slides.Add(1, 1) 'Always create at least one slide myPresentation.Designs(1).SlideMaster.CustomLayouts (GetLayoutIndexFromName("SRRLayout", myPresentation.Designs(1)))
myPresentation.PageSetup.SlideSize = ppSlideSizeOnScreen 'Set slide orientation and size
Dim sheet_counter As Integer
sheet_counter = 1
Dim updateslide As Boolean
Dim temp As Double
temp = (SQPOSITION) * PXLtoINCH
For i = 1 To all_data.Count
'Set Worksheet
Set iterator = all_data(i)
Set iterator2 = Nothing
If all_data.Count = 1 Then
updateslide = False 'only one sheet so no need for new slide, they are equal
Else
If i = all_data.Count Then ' last element can't be compared with the next, but can be compared to previous
Set iterator2 = all_data(i - 1)
If iterator2.get_sheet_name = iterator.get_sheet_name Then
updateslide = False
Else
updateslide = True
sheet_counter = sheet_counter + 1
End If
Else
Set iterator2 = all_data(i + 1)
If iterator2.get_sheet_name = iterator.get_sheet_name Then
updateslide = False
Else
updateslide = True
sheet_counter = sheet_counter + 1
End If
End If
End If
Set Ws = Workbooks("WS Asset Availability Master Data Spreadsheet.xlsx").Sheets(iterator.get_sheet_name)
'Copy Range from Excel
Set rg = Ws.Range(iterator.get_shape_range)
'Set myShape = mySlide.Shapes(mySlide.Shapes.Count)
Application.Wait (Now + TimeValue("00:00:1"))
'Copy Excel Range
rg.Copy
'Paste to PowerPoint and position
mySlide.Shapes.PasteSpecial DataType:=2 '2 = ppPasteEnhancedMetafile
Set myShape = mySlide.Shapes(mySlide.Shapes.Count) 'Control the latest shape to be pasted
'Set position:
myShape.LockAspectRatio = msoTrue
myShape.Height = 0.62 * PXLtoINCH
myShape.Width = 9.74 * PXLtoINCH
myShape.Left = 0.14 * PXLtoINCH
myShape.Top = temp
temp = myShape.Top + myShape.Height
If updateslide = True Then
temp = (SQPOSITION) * PXLtoINCH ' reset temp back to starting position.
End If
'Add a slide to the Presentation - only if new sheetname
If updateslide = True Then
Set mySlide = myPresentation.Slides.Add(sheet_counter, 2) '11 = ppLayoutTitleOnly
updateslide = False
temp = (SQPOSITION) * PXLtoINCH
End If
Next i
'*******************************************************************************************************************
'*******************************************************************************************************************
'Make PowerPoint Visible and Active
PowerPointApp.Visible = True
PowerPointApp.Activate
'Clear The Clipboard
Application.CutCopyMode = False
'*******************************************************************************************************************
'*******************************************************************************************************************
Else
MsgBox ("File Does not Exist in local directory - WS Asset Availability Master Data Spreadsheet.xlsx")
End If
End Sub
Function IsFile(ByVal fName As String) As Boolean
'Returns TRUE if the provided name points to an existing file.
'Returns FALSE if not existing, or if it's a folder
On Error Resume Next
IsFile = ((GetAttr(fName) And vbDirectory) <> vbDirectory)
End Function
Function CheckFileIsOpen(chkSumfile As String) As Boolean
On Error Resume Next
CheckFileIsOpen = (Workbooks(chkSumfile).Name = chkSumfile)
On Error GoTo 0
End Function
Function GetLayoutIndexFromName(sLayoutName As String, oDes As Design) As Long
Dim x As Long
For x = 1 To oDes.SlideMaster.CustomLayouts.Count
If oDes.SlideMaster.CustomLayouts(x).Name = sLayoutName Then
GetLayoutIndexFromName = x
Exit Function
End If
Next
End Function
I wrote this Access/VBA program. It works but only when I am not running other applications or few users are in the database. I need some ideas on streamlining the code. So it is not so system intensive. The program basically allows a user to pick a folder and then combines all worksheets in that folder in one excel document. My current idea is just to tell users to close all excel files when trying to run the program. Please Help:
Sub Excel_open()
Dim myXL As Excel.Application
Dim myXLS As Excel.Workbook
Const errExcelNotRunning = 429
On Error GoTo HandleIt
Set myXL = GetObject(, "Excel.application")
myXL.Visible = True
Set myXLS = myXL.Workbooks.Add
Call CombineWorkbooks(myXL)
HandleIt:
If Err.Number = errExcelNotRunning Then
Set myXL = CreateObject("Excel.Application")
Err.Clear
Resume Next
End If
End Sub
Sub CombineWorkbooks(myXL)
'Macro that combines the files into one folder
myXL.AskToUpdateLinks = False
myXL.DisplayAlerts = False
Dim CurFile As String, dirloc As String, strNamesheet As String
Dim DestWB As Workbook
Dim ws As Object ' allows for diffrent sheet types
'Add select the director function
dirloc = GetFolderName & "\" 'location of files not working want to select the file only
CurFile = Dir(dirloc & "*.xls*")
myXL.ScreenUpdating = False
myXL.EnableEvents = False
Set DestWB = Workbooks.Add(xlWorksheet)
Do While CurFile <> vbNullString
Dim OrigWB As Workbook
Set OrigWB = Workbooks.Open(FileName:=dirloc & CurFile, ReadOnly:=True)
'need to change a name active name is not doing it
CurFile = Left(CurFile, 4) ' This is no longer 29
'CurFile = Left(Left(CurFile, Len(CurFile) - 5), 29)
For Each ws In OrigWB.Sheets
ws.Copy After:=DestWB.Sheets(DestWB.Sheets.Count)
' Use the name to give the sheet a name
strNamesheet = Left((ws.Name), 25) & ";"
If OrigWB.Sheets.Count > 1 Then
DestWB.Sheets(DestWB.Sheets.Count).Name = strNamesheet & CurFile ' & ws.Index
Else
DestWB.Sheets(DestWB.Sheets.Count).Name = CurFile
End If
Next
OrigWB.Close SaveChanges:=False
CurFile = Dir
Loop
myXL.DisplayAlerts = False
DestWB.Sheets(1).Delete
myXL.DisplayAlerts = True
myXL.ScreenUpdating = True
myXL.EnableEvents = True
Set DestWB = Nothing
Call Delete_empty_Sheets(myXL)
Call Sort_Active_Book
MsgBox "Done"
'Call Xcombine_the_Matching
End Sub
Sub Delete_empty_Sheets(myXL)
'goes through all sheets and deletes
Reset_the_search:
For Each wsElement In Worksheets
If wsElement.Range("A2") = "" And wsElement.Range("B2") = "" Then
myXL.DisplayAlerts = False
wsElement.Delete
GoTo Reset_the_search
myXL.DisplayAlerts = True
End If
Next wsElement
End Sub
Sub Xcombine_the_Matching()
'I think I can make the order work
'change and transpose the array
Dim varStart As Variant
Dim wsCompare As Worksheet
Dim strMatch As String
'Dim varCompare As Variant
Dim strVareince As String
Dim strCurrentName As String
'you need to build a loop to solve this problem
For Each wsCompare In Worksheets
strVareince = Add_Array(Application.Transpose(wsCompare.Range("A1:Z1")))
For Each wsNompare In Worksheets
If wsNompare.Name <> strCurrentName Then
If strVareince = Add_Array(Application.Transpose(wsNompare.Range("A1:Z1"))) Then
MsgBox ("Matched with worksheet " & wsNompare.Name)
End If
End If
Next
Next
End Sub
Function array_to_string(x) As String
For Z = 1 To 26
array_to_string = array_to_string & x(Z, 1) & ";"
Next Z
End Function
Function GetFolderName(Optional OpenAt As String) As String
'Allows you to select the folder director that you want to combine
Dim lCount As Long
GetFolderName = vbNullString
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = OpenAt
.Show
For lCount = 1 To .SelectedItems.Count
GetFolderName = .SelectedItems(lCount)
Next lCount
End With
End Function
Function Add_Array(x) As String
'turns an excel document
For d = 1 To UBound(x)
Add_Array = Add_Array & x(d, 1)
Next d
End Function
Sub Read_data()
'this the
End Sub
Sub Sort_Active_Book()
Dim i As Integer
Dim j As Integer
Dim iAnswer As VbMsgBoxResult
'
' Prompt the user as which direction they wish to
' sort the worksheets.
'
iAnswer = MsgBox("Sort Sheets in Ascending Order?" & Chr(10) _
& "Clicking No will sort in Descending Order", _
vbYesNoCancel + vbQuestion + vbDefaultButton1, "Sort Worksheets")
For i = 1 To Sheets.Count
For j = 1 To Sheets.Count - 1
'
' If the answer is Yes, then sort in ascending order.
'
If iAnswer = vbYes Then
If UCase$(Sheets(j).Name) > UCase$(Sheets(j + 1).Name) Then
Sheets(j).Move After:=Sheets(j + 1)
End If
'
' If the answer is No, then sort in descending order.
'
ElseIf iAnswer = vbNo Then
If UCase$(Sheets(j).Name) < UCase$(Sheets(j + 1).Name) Then
Sheets(j).Move After:=Sheets(j + 1)
End If
End If
Next j
Next i
End Sub
You are passing your Excel Application object into your subroutines, but not using it fully, neither are you explicitly referencing the libraries:
Sub CombineWorkbooks(myXL)
Dim DestWB As Excel.Workbook ' <<<
Set DestWB = myXL.Workbooks.Add(xlWorksheet) ' <<<
End Sub
Run through your code and fix all of these first, then test & supply more feedback on what the precise symptoms of the problems are.