Statistical Quality Control Macro Changing parameters to a determined std.dev - vba

I found a macro online that creates a Statistical Quality Control chart online. So I have a .Csv file that looks like an excel sheet. I use the macro, so I have to select the data points. Then I have to select the labels, and then it gets plotted.
So instead of calculating the standard deviation from the selected data as my macro does, I want it to calculate the Upper limits and Lower limits from a set Standard deviation. Which is in the cell "F3". I have tried creating a variant where "stddev=Range("F3").value" But when I included it in my macro, the data was scattered and my labels on the right were not showing up as they were before. I will specify , where in the code that I think the problem is lying.
Here is the full code for creating the Quality control chart:
Option Explicit
Public Function GetRange(box_message As String) As Range
Set GetRange = Nothing
On Error Resume Next
Set GetRange = Application.InputBox(box_message, "Select Range", Selection.Address, , , , , 8)
End Function
Public Function IsNotOk(ByVal rng As Range) As Boolean 'TO CHECK IF A GIVEN RANGE IS BLANK
IsNotOk = True
On Error GoTo if_error_occured:
If rng.Rows.Count > 0 And rng.Columns.Count = 1 Then IsNotOk = False
if_error_occured:
If Err.Number Then IsNotOk = True
End Function
Public Function check_if_numeric(rng As Range) As Boolean
Dim cel As Range
check_if_numeric = True
For Each cel In rng.Cells
If Not (Application.WorksheetFunction.IsNumber(cel.Value)) Then check_if_numeric = False
Next cel
End Function
Sub Make_Control_Chart()
Dim data_values As Range
Dim chart_labels As Range
Dim range_selected_before As Range
Dim got_label_range As Boolean
Dim got_value_range As Boolean
Dim bActivate As Boolean
Dim myChtObj As ChartObject
Dim plot_series, MyNewSrs As Series
Dim series_label As String
Dim number_of_control_limits As Integer
Dim standard_deviation As Integer
Dim data_str As String
Dim avg_str As String
Dim stddev As Variant
On Error GoTo if_error_occured: 'GOTO THE END OF THE PROGRAM
stddev = Range("F3").Value
'GET RANGE FOR DATA VALUES
bActivate = False ' True to re-activate the input range
Set data_values = GetRange("Please select the range containing the DATA POINTS" & Chr(13) & "(press select a single column)")
If IsNotOk(data_values) Then
MsgBox "Incorrect Input Data !"
End
ElseIf Not (check_if_numeric(data_values)) Then
MsgBox "Incorrect Input Data !"
End
End If
'GET RANGE FOR CHART X-AXIS LABELS
got_label_range = True ' True to re-activate the input range
Set chart_labels = GetRange("Please select the range containing the LABELS" & Chr(13) & "(press ESC if no labels available)")
If IsNotOk(chart_labels) Then
got_label_range = False
End If
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'LETS CREATE THE CHART NOW
Set myChtObj = ActiveSheet.ChartObjects.Add(Left:=300, Width:=450, Top:=25, Height:=300)
myChtObj.Chart.ChartType = xlLineMarkers
'REMOVE ALL UNWANTED SERIES FROM CHART, IF ANY
For Each MyNewSrs In myChtObj.Chart.SeriesCollection ' myChtObj.Chart.SeriesCollection
MyNewSrs.Delete
Next MyNewSrs
Set MyNewSrs = Nothing
If got_label_range Then 'IF WE HAVE THE LABEL RANGE
'ADD NEW SERIES
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "PLOT"
.Values = data_values
.XValues = chart_labels.Value
End With
Else
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "PLOT"
.Values = data_values
End With
End If
'FORMAT THE PLOT SERIES
Set plot_series = MyNewSrs
With MyNewSrs
.Border.ColorIndex = 1
.MarkerBackgroundColorIndex = 2
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlCircle
.Smooth = False
.MarkerSize = 5
.Shadow = False
End With
Set MyNewSrs = Nothing
'CREATE NAMED RANGE FOR THE DATA VALUES, AVERAGE, LOWER AND UPPER CONTROL LIMITS
data_str = Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_data_values"
avg_str = "roundup(average(" & Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_data_values" & "),2)"
'HERE THE LIMITS ARE SET AND THE ORIGINAL CODE IS SET IN THERE WHERE IT WORKS ON A SET OF DATA POINTS, HOWEVER WHEN I TRY TO CHANGE IT TO JUST "1*stddev,3" the data gets all scattered. I'M WONDERING WHY THE DATA IS BEING SCATTERED?
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_data_values", RefersToR1C1:=data_values
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_AVG", RefersToR1C1:="=" & avg_str & ""
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_LCL1", RefersToR1C1:="=" & avg_str & "- roundup(1*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_LCL2", RefersToR1C1:="=" & avg_str & "- roundup(2*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_LCL3", RefersToR1C1:="=" & avg_str & "- roundup(3*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_UCL1", RefersToR1C1:="=" & avg_str & "+ roundup(1*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_UCL2", RefersToR1C1:="=" & avg_str & "+ roundup(2*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_UCL3", RefersToR1C1:="=" & avg_str & "+ roundup(3*stdev(" & data_str & "),3)"
The code for formatting and creating the lines on the chart:
'ADD THE LINE FOR AVERAGE
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "AVG = "
.Values = "='" & ActiveSheet.Name & "'!" & Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_AVG"
.ChartType = xlXYScatter
'.ErrorBar Direction:=xlX, Include:=xlNone, Type:=xlFixedValue, Amount:=10000
'.ErrorBar Direction:=xlX, Include:=xlUp, Type:=xlFixedValue, Amount:=20
.ErrorBar Direction:=xlX, Include:=xlPlusValues, Type:=xlFixedValue, Amount:=data_values.Rows.Count
.MarkerBackgroundColorIndex = xlAutomatic
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlNone
.Smooth = False
.MarkerSize = 5
.Shadow = False
With .Border
.Weight = xlHairline
.LineStyle = xlNone
End With
'With .ErrorBars.Border
' .LineStyle = xlContinuous
' .ColorIndex = 3
' .Weight = xlThin
'End With
End With
Set MyNewSrs = Nothing
'ADD UPPER AND LOWER CONTROL LIMITS
For number_of_control_limits = 1 To 3
For standard_deviation = -1 To 1 Step 2
Select Case standard_deviation:
Case -1: series_label = "LCL"
Case 1: series_label = "UCL"
End Select
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = series_label & number_of_control_limits & " ="
.Values = "='" & ActiveSheet.Name & "'!" & Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_" & series_label & number_of_control_limits
.ChartType = xlXYScatter
.ErrorBar Direction:=xlX, Include:=xlPlusValues, Type:=xlFixedValue, Amount:=data_values.Rows.Count
End With
MyNewSrs.ErrorBar Direction:=xlX, Include:=xlPlusValues, Type:=xlFixedValue, Amount:=data_values.Rows.Count
Select Case number_of_control_limits:
Case 1:
With MyNewSrs.ErrorBars.Border
.LineStyle = xlGray25
.ColorIndex = 15
.Weight = xlHairline
End With
Case 2:
With MyNewSrs.ErrorBars.Border
.LineStyle = xlGray25
.ColorIndex = 57
.Weight = xlHairline
End With
Case 3:
With MyNewSrs.ErrorBars.Border
.LineStyle = xlGray75
.ColorIndex = 3
.Weight = xlHairline
End With
End Select
MyNewSrs.ErrorBars.EndStyle = xlNoCap
With MyNewSrs
With .Border
.Weight = xlHairline
.LineStyle = xlNone
End With
.MarkerBackgroundColorIndex = xlAutomatic
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlNone
.Smooth = False
.MarkerSize = 5
.Shadow = False
End With
Set MyNewSrs = Nothing
Next standard_deviation
Next number_of_control_limits
myChtObj.Chart.ApplyDataLabels AutoText:=True, LegendKey:=False, _
HasLeaderLines:=False, ShowSeriesName:=True, ShowCategoryName:=False, _
ShowValue:=True, ShowPercentage:=False, ShowBubbleSize:=False, Separator:=" "
'OFFSET THE LABELS
For Each MyNewSrs In myChtObj.Chart.SeriesCollection
With MyNewSrs.Points(1).DataLabel
.Left = 400
End With
Next MyNewSrs
'LETS FORMAT THE CHART
With myChtObj
With .Chart.Axes(xlCategory)
.MajorTickMark = xlNone
.MinorTickMark = xlNone
.TickLabelPosition = xlNextToAxis
End With
With .Chart.Axes(xlValue)
.MajorTickMark = xlOutside
.MinorTickMark = xlNone
.TickLabelPosition = xlNextToAxis
End With
With .Chart.ChartArea.Border
.Weight = 1
.LineStyle = 0
End With
With .Chart.PlotArea.Border
.ColorIndex = 1
.Weight = xlThin
.LineStyle = xlContinuous
End With
With .Chart.PlotArea.Interior
.ColorIndex = 2
.PatternColorIndex = 1
.Pattern = xlSolid
End With
With .Chart.ChartArea.Font
.Name = "Arial"
.Size = 8
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
.Background = xlAutomatic
End With
With .Chart
.HasTitle = False
.Axes(xlCategory, xlPrimary).HasTitle = False
.Axes(xlValue, xlPrimary).HasTitle = True
.HasTitle = True
.ChartTitle.Characters.Text = "Control Chart"
.ChartTitle.Left = 134
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Observations"
End With
With .Chart.Axes(xlCategory).TickLabels
.Alignment = xlCenter
.Offset = 100
.ReadingOrder = xlContext
.Orientation = xlHorizontal
End With
End With
myChtObj.Chart.Legend.Delete
myChtObj.Chart.PlotArea.Width = 310
myChtObj.Chart.Axes(xlValue).MajorGridlines.Delete
myChtObj.Chart.Axes(xlValue).CrossesAt = myChtObj.Chart.Axes(xlValue).MinimumScale
myChtObj.Chart.ChartArea.Interior.ColorIndex = xlAutomatic
myChtObj.Chart.ChartArea.AutoScaleFont = True
'DELETE THE LABELS FOR THE ACTUAL DATA SERIES
plot_series.DataLabels.Delete
Set plot_series = Nothing
if_error_occured:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
If Err.Number Then z_delete_all_named_range
End Sub
Sub z_delete_all_named_range()
Dim nam As Name
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
For Each nam In ActiveWorkbook.Names
nam.Delete
Next nam
End Sub

Compiled but not tested:
Sub Make_Control_Chart()
Dim data_values As Range
Dim chart_labels As Range
Dim range_selected_before As Range
Dim got_label_range As Boolean
Dim got_value_range As Boolean
Dim bActivate As Boolean
Dim myChtObj As ChartObject
Dim plot_series, MyNewSrs As Series
Dim series_label As String
Dim number_of_control_limits As Integer
Dim standard_deviation As Integer
Dim data_str As String
Dim avg_str As String
Dim stddev As Variant
Dim wb As Workbook, sCht As String, i As Long
Set wb = ActiveWorkbook
'On Error GoTo if_error_occured: 'GOTO THE END OF THE PROGRAM
stddev = Range("F3").Value
'GET RANGE FOR DATA VALUES
bActivate = False ' True to re-activate the input range
Set data_values = GetRange("Please select the range containing the DATA POINTS" & _
Chr(13) & "(press select a single column)")
If IsNotOk(data_values) Then
MsgBox "Incorrect Input Data !"
Exit Sub 'not End!
ElseIf Not (check_if_numeric(data_values)) Then
MsgBox "Incorrect Input Data !"
Exit Sub 'not End!
End If
'GET RANGE FOR CHART X-AXIS LABELS
got_label_range = True ' True to re-activate the input range
Set chart_labels = GetRange("Please select the range containing the LABELS" & _
Chr(13) & "(press ESC if no labels available)")
If IsNotOk(chart_labels) Then
got_label_range = False
End If
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'LETS CREATE THE CHART NOW
Set myChtObj = ActiveSheet.ChartObjects.Add(Left:=300, Width:=450, _
Top:=25, Height:=300)
myChtObj.Chart.ChartType = xlLineMarkers
'REMOVE ALL UNWANTED SERIES FROM CHART, IF ANY
For Each MyNewSrs In myChtObj.Chart.SeriesCollection
MyNewSrs.Delete
Next MyNewSrs
Set MyNewSrs = Nothing
'IF WE HAVE THE LABEL RANGE
'ADD NEW SERIES
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "PLOT"
.Values = data_values
If got_label_range Then
.XValues = chart_labels.Value
End If
End With
'FORMAT THE PLOT SERIES
Set plot_series = MyNewSrs
With MyNewSrs
.Border.ColorIndex = 1
.MarkerBackgroundColorIndex = 2
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlCircle
.Smooth = False
.MarkerSize = 5
.Shadow = False
End With
Set MyNewSrs = Nothing
'CREATE NAMED RANGE FOR THE DATA VALUES, AVERAGE, LOWER AND UPPER CONTROL LIMITS
sCht = sCht
data_str = sCht & "_data_values"
avg_str = "roundup(average(" & sCht & "_data_values" & "),2)"
wb.Names.Add Name:=sCht & "_data_values", RefersToR1C1:=data_values
wb.Names.Add Name:=sCht & "_AVG", RefersToR1C1:="=" & avg_str & ""
For i = 1 To 3
wb.Names.Add Name:=sCht & "_LCL" & i, _
RefersToR1C1:="=" & avg_str & "- roundup(" & i & "*" & stddev & ",3)"
wb.Names.Add Name:=sCht & "_UCL" & i, _
RefersToR1C1:="=" & avg_str & "+ roundup(" & i & "*" & stddev & ",3)"
Next i
End Sub
Public Function GetRange(box_message As String) As Range
On Error Resume Next
Set GetRange = Application.InputBox(box_message, "Select Range", Selection.Address, , , , , 8)
End Function
Public Function IsNotOk(ByVal rng As Range) As Boolean 'TO CHECK IF A GIVEN RANGE IS BLANK
IsNotOk = True
On Error GoTo if_error_occured:
If rng.Rows.Count > 0 And rng.Columns.Count = 1 Then IsNotOk = False
if_error_occured:
If Err.Number Then IsNotOk = True
End Function
Public Function check_if_numeric(rng As Range) As Boolean
Dim cel As Range, rv As Boolean
rv = True
For Each cel In rng.Cells
If Not (Application.WorksheetFunction.IsNumber(cel.Value)) Then
rv = False
Exit For
End If
Next cel
check_if_numeric = rv
End Function

Related

Hyperlink with spaces

I have a worksheets for my projects.
the first sheet is the main one the containing all the name of the projects.
the author sheets are for every project.
in the main sheet the name of the project has hyperlink to his sheet.
when running the code I got a pop msgbox that I write the new project name (look for "project_name").
the code does stuff.
but near the end there is the hyperlink code. (look for ActiveSheet.Hyperlinks.Add....)
so my problem is:
when I choose a project name like "abcd" everything works ok. But when I choose name like "ab cd". the code runs but the hyperlink doesn't work.
I realized that having a space in the project name makes the code not work.
thanks for the help.
p.s.
The notes are in Hebrew.
Sub New_project()
'--------------------------------------------------------------------------------------------------תחילת ריצת קוד
Dim Start, Finish, TotalTime As Date
Start = Timer
'--------------------------------------------------------------------------------------------------ביטול חישובים ועדכוני מסך והתראות
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.AskToUpdateLinks = False
'--------------------------------------------------------------------------------------------------החזרת חישובים ועדכוני מסך והתראות
'Application.Calculation = xlCalculationAutomatic
'Application.ScreenUpdating = True
'Application.DisplayAlerts = True
'Application.AskToUpdateLinks = True
'--------------------------------------------------------------------------------------------------פתיחת חלונית והקלדת שם הפרויקט
'--------------------------------------------------------------------------------------------------אם לחצו cancel אז יציאה מהקוד
Dim project_name As String
project_name = InputBox("נא להקליד את שם הפרויקט החדש")
If Len(project_name) < 1 Then
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
MsgBox ("יציאה מהקוד")
Exit Sub
End If
'--------------------------------------------------------------------------------------------------בדיקה האם שם הגיליון לפרויקט החדש כבר קיים
Dim curSheet As Worksheet
Dim ArraySheets() As String
Dim x As Variant
Dim sheet_existing As Integer
x = 0
sheet_existing = 0
For Each curSheet In ActiveWorkbook.Worksheets
If curSheet.Name Like project_name Then
Worksheets(project_name).Activate
sheet_existing = 1
Finish = Timer
TotalTime = Format((Finish - Start) / 86400, "hh:mm:ss")
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
MsgBox ("שם הפרויקט כבר קיים" & vbNewLine & "זמן ריצת קוד: " & TotalTime)
Exit Sub
End If
Next curSheet
'iComp = StrComp(str1, str2, vbBinaryCompare)
'--------------------------------------------------------------------------------------------------הוספת גיליון חדש בסוף הקובץ
If sheet_existing = 0 Then
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = project_name
End If
'--------------------------------------------------------------------------------------------------הוספת כותרות
Range("A1") = "#"
Range("B1") = "תאריך"
Range("C1") = "שלב"
Range("D1") = "איש קשר"
Range("E1") = "הערות"
Range("F1") = "מסמכים"
Range("G1") = "ימים"
Range("H1") = "צבירה"
'--------------------------------------------------------------------------------------------------רוחב עמודה
Columns("A").ColumnWidth = 9
Columns("B").ColumnWidth = 11
Columns("C").ColumnWidth = 30
Columns("D").ColumnWidth = 16
Columns("E").ColumnWidth = 17
Columns("F").ColumnWidth = 9
Columns("G").ColumnWidth = 6
Columns("H").ColumnWidth = 10
'--------------------------------------------------------------------------------------------------הוספת מסגרת לתאים
Dim rng1 As Range
Set rng1 = Range(Cells(1, 1), Cells(27, 8))
With rng1.Borders
.LineStyle = xlContinuous
.Color = vbBlack
.Weight = xlThin
End With
Range("A:H").HorizontalAlignment = xlCenter
Range("A:H").VerticalAlignment = xlCenter
Rows(1).Font.Bold = True
Columns(1).Font.Bold = True
Range("A1:H1").Interior.Color = RGB(0, 176, 240)
Range("A2") = 1
Range("B2") = Date
'Range("C2") = "רשום כאן את השלב הראשון"
Range("G2") = 0
Range("H2") = 0
Range("N1:Q1").Merge
Range("N2:Q12").Merge
Range("N1:Q1").Interior.Color = RGB(0, 176, 240)
Range("N1:Q1") = "הערות"
'--------------------------------------------------------------------------------------------------הוספת מסגרת לתאים
Dim rng2 As Range
Set rng2 = Range(Cells(1, 14), Cells(12, 17))
With rng2.Borders
.LineStyle = xlContinuous
.Color = vbBlack
.Weight = xlThin
End With
Range("N:Q").HorizontalAlignment = xlCenter
Range("N:Q").VerticalAlignment = xlCenter
'--------------------------------------------------------------------------------------------------ספירת גיליונות בקובץ
Dim SheetCountA As Integer
SheetCountA = Application.Sheets.Count
'--------------------------------------------------------------------------------------------------העתקת כפתור חזרה לגיליון החדש
Sheets(SheetCountA - 1).Select
ActiveSheet.Shapes.Range(Array("Rectangle 1")).Select
Selection.Copy
Sheets(SheetCountA).Select
ActiveSheet.Paste Destination:=Worksheets(SheetCountA).Range("K1")
Sheets(SheetCountA - 1).Select
Range("B1").Copy
Sheets(SheetCountA).Select
Range("B1").PasteSpecial Paste:=xlPasteFormats
Application.CutCopyMode = False
Range("A1").Select
Sheets(SheetCountA - 1).Select
Range("A1").Select
Sheets("סיכום").Select
Dim LastRowA As Integer
LastRowA = Application.CountA(Range("B:B"))
'--------------------------------------------------------------------------------------------------הוספת מספור לפרויקט החדש
Cells(LastRowA + 1, 1) = Cells(LastRowA, 1) + 1
'--------------------------------------------------------------------------------------------------הוספת היפר-לינק
ActiveSheet.Hyperlinks.Add Anchor:=Cells(LastRowA + 1, 2), Address:="", SubAddress:= _
project_name & "!A1", TextToDisplay:=project_name
Cells(LastRowA + 1, 2).HorizontalAlignment = xlCenter
Cells(LastRowA + 1, 2).VerticalAlignment = xlCenter
Range("A1").Select
'--------------------------------------------------------------------------------------------------זמן סיום ריצת קוד וחישוב
Finish = Timer
TotalTime = Format((Finish - Start) / 86400, "hh:mm:ss")
MsgBox ("הדו''ח מוכן" & vbNewLine & "זמן ריצת קוד: " & TotalTime)
'--------------------------------------------------------------------------------------------------שאלה האם לעבור לקוד שמרענן את הקובץ
Dim answer2 As Integer
answer2 = MsgBox("?האם לרענן את הקובץ", vbYesNo + vbQuestion, "מעבר לקוד הבא")
If answer2 = vbYes Then
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
Call Refresh_file
End If
'--------------------------------------------------------------------------------------------------שמירת הקובץ
ThisWorkbook.Save
'--------------------------------------------------------------------------------------------------החזרת חישובים ועדכוני מסך והתראות
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
End Sub
To make the hyperlink valid, you just need to wrap the sheet name in quotes, so:
ActiveSheet.Hyperlinks.Add Anchor:=Cells(LastRowA + 1, 2), Address:="", SubAddress:= _
project_name & "!A1", TextToDisplay:=project_name
becomes
ActiveSheet.Hyperlinks.Add Anchor:=Cells(LastRowA + 1, 2), Address:="", SubAddress:="'" & _
project_name & "'" & "!A1", TextToDisplay:=project_name

Excel VBA - Save changes to "Book16" error

I have some data in my excel file and based on that data I'm using a macro for generating the report which should be saved in the place specified by path provided by the user. On my laptop, with Win10 everything is working fine, but on PC there is an error when we try to generate a report. Instead of saving the report in provided place excel is asking me to save data in "Book16" as shows the screenshot below. Do I have no idea why?
Here is the code of macro responsible for creating the report:
Sub Nationalreports()
Dim sh1 As Worksheet, N As Long
Dim st As String
Dim wbUnSaved As Workbook
Dim wbSaved As Workbook
Dim RedemptiontypeIncHdgs As Range
Dim RedemptiontypeExcHdgs As Range
Dim Fr As Long, LR As Long
Dim vaFiles As Variant
Dim i As Long
Dim wbkToCopy As Workbook
Dim ws As Worksheet, strFile As String
Dim File_path As String
Dim qry As QueryTable
Dim FilNams As Variant
Dim FilNamCntr As Long
Dim strQryName As String
Dim lastrow As Long
Application.ScreenUpdating = False
If Range("E8").Value = 0 Then
MsgBox "Please Specify FilePath", vbExclamation, "Please Specify
FilePath"
Range("E8").Activate
Exit Sub
End If
File_path = Sheets("Control").Range("E8").Value
Set wbksaved = ActiveWorkbook
MsgBox "Please Select MVRT Reports", vbInformation, "Select Files"
FilNams = Application.GetOpenFilename(FileFilter:="CSV Files
(*.csv),*.csv", _
Title:="Select Textfile to
Import", _
MultiSelect:=True)
If TypeName(FilNams) = "Boolean" Then
MsgBox "No Files Selected", vbExclamation, "No Files Selected"
Exit Sub
Else
End If
For FilNamCntr = LBound(FilNams) To UBound(FilNams)
FilNams(FilNamCntr) = "TEXT;" & FilNams(FilNamCntr)
Next FilNamCntr
For FilNamCntr = LBound(FilNams) To UBound(FilNams)
Sheets("Data").Cells.NumberFormat = "#"
Set wbkToCopy = Workbooks.Add
With ActiveSheet
If .Range("A" & Rows.Count).End(xlUp).Row = 1 Then
lastrow = 1
Else
lastrow = .Range("A" & Rows.Count).End(xlUp).Row + 1
End If
Set qry = .QueryTables.Add(Connection:=FilNams(FilNamCntr), _
Destination:=.Range("A" & lastrow))
With qry
.Name = "Filename"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 850
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End With
'-------------------------------------------------------------------------------------------
'NEW CODE:
'-------------------------------------------------------------------------------------------
'progress
'Rows("1:1").Delete
'ActiveSheet.UsedRange.Columns("A:T").SpecialCells(xlCellTypeVisible).Copy
'wbksaved.Sheets("Data").Cells(Rows.Count, "A").End(xlUp).Offset(0).PasteSpecial Paste:=xlPasteValues
ActiveSheet.UsedRange.Columns("A:T").SpecialCells(xlCellTypeVisible).Select
Selection.Copy
'wbksaved.Sheets("Data").Activate
'Range("A1").Select
'ActiveSheet.Paste
wbksaved.Sheets("Data").Paste
'ERROR IS HERE ^^^^^^^^^^^^^
'-------------------------------
'new:
Application.CutCopyMode = False
'-------------------------------
Application.DisplayAlerts = False
ActiveWorkbook.Close False
Application.DisplayAlerts = True
Next FilNamCntr
Set wbkToCopy = Workbooks.Add
wbkToCopy.Sheets(1).Name = "Duplicates,Invalid"
wbkToCopy.Worksheets.Add().Name = "Breakdown"
wbkToCopy.Worksheets.Add().Name = "Summary"
wbksaved.Sheets("Redemption").UsedRange.Columns("C:D").Copy
Sheets("Duplicates,Invalid").Range("A1").PasteSpecial Paste:=xlPasteValues
'-------------------------------
'new:
Application.CutCopyMode = False
'-------------------------------
' Duplicates & Invalids Sheet
Sheets("Duplicates,Invalid").Activate
Columns("B").Cut Destination:=Columns("F")
Columns("A").Cut Destination:=Columns("B")
Range("B1").Value = "Duplicate Codes"
Range("F1").Value = "Invalid Codes"
Range("A2").Value = "1"
Range("A3").Value = "2"
On Error Resume Next
Cells(2, 1).AutoFill Destination:=Range("A2:A" & Range("B" & Rows.Count).End(xlUp).Row), Type:=xlFillSeries
Range("E2").Value = "1"
Range("E3").Value = "2"
On Error Resume Next
Cells(2, 5).AutoFill Destination:=Range("E2:E" & Range("F" & Rows.Count).End(xlUp).Row), Type:=xlFillSeries
Range("A1").Value = "Nr."
Range("E1").Value = "Nr."
Columns("A:F").EntireColumn.AutoFit
Columns("A:F").HorizontalAlignment = xlCenter
Cells.Interior.Pattern = xlSolid
Cells.Interior.TintAndShade = -0.0499893185216834
Range("A1:B1,E1:F1").Interior.ThemeColor = xlThemeColorLight1
Range("A:B,E:F").Borders.LineStyle = xlContinuous
Range("A1:B1,E1:F1").Font.ThemeColor = xlThemeColorDark1
Range("A1:B1,E1:F1").Font.Bold = True
Application.Goto Reference:=Range("A1"), Scroll:=True
' Breakdown Sheet
Sheets("Breakdown").Activate
Cells.NumberFormat = "#"
wbksaved.Sheets("MVRT").UsedRange.Columns("A:D").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "A").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("F:F").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "E").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("H:H").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "F").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("N:N").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "G").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("S:S").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "H").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("K:K").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "I").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("J:J").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "J").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("M:M").SpecialCells(xlCellTypeVisible).Copy
wbkToCopy.Sheets("Breakdown").Cells(Rows.Count, "K").End(xlUp).Offset(0).PasteSpecial xlPasteValues
wbksaved.Sheets("MVRT").UsedRange.Columns("Q:Q").SpecialCells(xlCellTypeVisible).Copy
ActiveSheet.Paste Destination:=Worksheets("Breakdown").Range("L:L")
'-------------------------------
'new:
Application.CutCopyMode = False
'-------------------------------
'Range("O:P").Delete
Range("A1").Value = "UUID"
Range("B1").Value = "Security Code"
Range("C1").Value = "Customer Code"
Range("D1").Value = "Country Code"
Range("E1").Value = "Salesforce Id"
Range("F1").Value = "Merchant Name"
Range("G1").Value = "Unit Status"
Range("H1").Value = "Redemption Status"
Range("I1").Value = "Expires At"
Range("J1").Value = "Expired"
Range("K1").Value = "Suspended"
Range("L1").Value = "Redemption Date"
'Range("M:M").Replace What:="Invalid Rights", Replacement:="Other Country"
Range("B:L").Sort Key1:=Range("I:I"), Order1:=xlAscending, Header:=xlYes
Range("A:L").EntireColumn.AutoFit
Range("A1:L1").HorizontalAlignment = xlCenter
Cells.Interior.Pattern = xlSolid
Cells.Interior.TintAndShade = -0.0499893185216834
Range("A1:L1").Interior.ThemeColor = xlThemeColorLight1
Range("A:L").Borders.LineStyle = xlContinuous
Range("A1:L1").Font.ThemeColor = xlThemeColorDark1
Rows("1:1").Font.Bold = True
Application.Goto Reference:=Range("A1"), Scroll:=True
'Summary Sheet
Sheets("Summary").Activate
Range("C9").Value = "Country"
Range("C10").Value = "Merchant Name"
Range("C11").Value = "Type"
Range("C16").Value = "Redemption Type"
Range("C17").Value = "Invalid"
Range("C18").Value = "Duplicates"
Range("C19").Value = "Suspended"
Range("C20").Value = "Voucher Expired"
Range("C21").Value = "Payment Invalid"
Range("C22").Value = "Payment Refunded"
Range("C23").Value = "Redeemed"
Range("C24").Value = "Total Codes Sent In"
Range("D9").FormulaR1C1 = "=Breakdown!R[-7]C[0]"
Range("D10").FormulaR1C1 = "=Breakdown!R[-8]C[2]"
Range("D11").FormulaR1C1 = "Offsite Redemptions"
Range("D16").FormulaR1C1 = "No."
Range("D17").FormulaR1C1 = "=COUNTA('Duplicates,Invalid'!C[2])-1"
Range("D18").FormulaR1C1 = "=COUNTA('Duplicates,Invalid'!C[-2])-1"
Range("D19").Formula = "=COUNTIFS(Breakdown!K:K,""*true*"",Breakdown!H:H,""*Forced redeemable*"")"
'Range("D19").AutoFill Destination:=Range("D19:D25"), Type:=xlFillCopy
Range("D20").Formula = "=COUNTIFS(Breakdown!J:J,""*true*"",Breakdown!K:K,""*false*"",Breakdown!G:G,""*collected*"",Breakdown!H:H,""*Forced redeemable*"")"
'payment not received:
Range("D21").Formula = "=COUNTIFS(Breakdown!K:K,""*false*"",Breakdown!G:G,""*resigned*"",Breakdown!H:H,""*Forced redeemable*"") + COUNTIFS(Breakdown!K:K,""*false*"",Breakdown!G:G,""*pending*"",Breakdown!H:H,""*Forced redeemable*"")"
'payment refunded:
Range("D22").Formula = "=COUNTIFS(Breakdown!G:G,""*deleted*"",Breakdown!K:K,""*false*"",Breakdown!H:H,""*Forced redeemable*"")"
Range("D23").Formula = "=COUNTIF(Breakdown!H:H,""*redeemed*"")"
'sum-formula:
Range("D24").Formula = "=COUNTA(Breakdown!A:A)-1 + SUM(D17:D18)"
Range("C:D").Copy
Range("C:C").PasteSpecial xlPasteValues
Application.CutCopyMode = False
Range("A:B,E:F").ColumnWidth = 26
Range("C:D").ColumnWidth = 63.29
Range("C:D").HorizontalAlignment = xlCenter
Cells.Interior.Pattern = xlSolid
Cells.Interior.TintAndShade = -0.0499893185216834
Range("C1:D5,C9:C11,C16:D16,C24:D24").Interior.ThemeColor =
xlThemeColorLight1
Range("D9:D11,C16:D24").Borders.LineStyle = xlContinuous
Range("C9:C11,C16:D16,C24:D24").Font.ThemeColor = xlThemeColorDark1
Range("C9:D11,C16:D24").Font.Bold = True
Range("C3:D3").Merge True
Dim myR As Range
Set myR = Range("C3:D3")
wbksaved.Sheets("Control").Shapes("Groupon Logo").Copy
Range("C3:D3").PasteSpecial xlPasteFormats
'-------------------------------
'new:
Application.CutCopyMode = False
'-------------------------------
Selection.ShapeRange.ScaleWidth 1, msoFalse, msoScaleFromTopLeft
Selection.ShapeRange.ScaleHeight 1, msoFalse, msoScaleFromTopLeft
Selection.ShapeRange.IncrementLeft (myR.Width - Selection.ShapeRange.Width) / 2
Application.Goto Reference:=Range("A1"), Scroll:=True
Country = Range("D9").Value
'Merchant_ID = Range("D10").Value This was DELETED on Lorene request
Merchant_Name = Range("D10").Value
dt = Format(CStr(Now), "dd_mm_yyyy_hh_mm_ss")
File_Name = File_path & "\" & "Report" & " " & Merchant_Name & " " &
Merchant_ID & " " & dt & ".xlsx"
ActiveWorkbook.SaveAs Filename:=File_Name, FileFormat:=51
ActiveWorkbook.Close
Application.DisplayAlerts = False
Sheets("Data").Cells.Delete
Application.DisplayAlerts = True
Sheets("Control").Select
MsgBox "Report Created", vbInformation, "Report Created"
Application.ScreenUpdating = True
End Sub
Can you try instead of this:
ActiveSheet.UsedRange.Columns("A:T").SpecialCells(xlCellTypeVisible).Select
Selection.Copy
wbksaved.Sheets("Data").Paste
To write this:
ActiveSheet.Columns("A:T").SpecialCells(xlCellTypeVisible).Copy
wbksaved.Sheets("Data").Range("A1").Paste
And to see whether the "error" would still exist? In general, Selection.Copy and ActiveSheet, ActiveCell should be avoided whenever possible - How to avoid using Select in Excel VBA

Save image of range in next column excel vba

On the activesheet in column A, I have text of which I want to save image and place it in column B.
I can't figure out how to remove the lines and axis etc and just get a image of the range. Currently it's showing lines and axis in the image.
Sub Generate_Images()
Dim wK As Worksheet
Dim oCht As Chart
Dim i As Long, fI As Long
Dim fName As String
Application.DisplayAlerts = False
Set wK = ActiveSheet
fI = wK.Range("A" & wK.Rows.Count).End(xlUp).Row
wK.Columns("B:B").ColumnWidth = wK.Columns("A:A").ColumnWidth
For i = 1 To fI
wK.Range("A" & i).CopyPicture xlScreen, xlBitmap
Set oCht = ThisWorkbook.Charts.Add
With oCht
.ChartArea.Border.LineStyle = xlNone
.Paste
fName = ThisWorkbook.Path & "\" & Format(Now(), "DDMMYYHHMMSS") & ".png"
.Export Filename:=fName, Filtername:="PNG"
.Delete
End With
With wK.Pictures.Insert(fName)
With .ShapeRange
.LockAspectRatio = msoTrue
.Width = wK.Range("A" & i).Width
.Height = wK.Range("A" & i).Height
End With
.Left = wK.Range("B" & i).Left
.Top = wK.Range("B" & i).Top
.Placement = 1
.PrintObject = True
End With
Application.Wait Now + TimeValue("00:00:01")
Next i
Application.DisplayAlerts = True
End Sub
Why export and then re-import the image when you can just paste it straight into the sheet?
Sub Generate_Images()
Dim wK As Worksheet
Dim oCht As Chart
Dim i As Long, fI As Long
Dim fName As String
Application.DisplayAlerts = False
Set wK = ActiveSheet
fI = wK.Range("A" & wK.Rows.Count).End(xlUp).Row
wK.Columns("B:B").ColumnWidth = wK.Columns("A:A").ColumnWidth
For i = 1 To fI
wK.Range("A" & i).CopyPicture xlScreen, xlBitmap
wK.Paste
With wK.Pictures(wK.Pictures.Count)
.Left = wK.Range("B" & i).Left
.Top = wK.Range("B" & i).Top
.Placement = 1
.PrintObject = True
End With
Application.Wait Now + TimeValue("00:00:01")
Next i
Application.DisplayAlerts = True
End Sub
If you save image to picture file, then try this.
Instead Chart, use chartobject. It is possible to change chart's size.
And if your active cell is not empty, Excell automatically create chart base on data.
So, you must delete chart's seriescollecton.
Sub Generate_Images()
Dim wK As Worksheet
Dim oCht As Chart
Dim i As Long, fI As Long, j As Long
Dim fName As String
Dim obj As ChartObject
Dim n As Long
Dim w As Single, h As Single
Application.DisplayAlerts = False
Set wK = ActiveSheet
wK.Pictures.Delete
fI = wK.Range("A" & wK.Rows.Count).End(xlUp).Row
wK.Columns("B:B").ColumnWidth = wK.Columns("A:A").ColumnWidth
For i = 1 To fI
w = wK.Range("A" & i).Width
h = wK.Range("A" & i).Height
wK.Range("A" & i).CopyPicture xlScreen, xlBitmap
Set obj = wK.ChartObjects.Add(Range("c1").Left, 0, w, h)
Set oCht = obj.Chart
With oCht
n = .SeriesCollection.Count
For j = n To 1 Step -1
.SeriesCollection(j).Delete
Next j
.ChartArea.Border.LineStyle = xlNone
.Paste
fName = ThisWorkbook.Path & "\" & Format(Now(), "DDMMYYHHMMSS") & ".png"
.Export Filename:=fName, Filtername:="PNG"
obj.Delete
End With
With wK.Pictures.Insert(fName)
.Left = wK.Range("B" & i).Left
.Top = wK.Range("B" & i).Top
.Placement = 1
.PrintObject = True
End With
Application.Wait Now + TimeValue("00:00:01")
Next i
Application.DisplayAlerts = True
End Sub

How to find duplicates in a column, looping through multiple sheets

I have been trying to write a piece of vba code, so that I can find all of the duplicates in a column, highlight them in red and bring up a message box listing all those duplicated;
and I want the code to do this for column C across multiple sheets. This is essentially to replace conditional formatting, as it was slowing down the workbook about 8 seconds.
This is what I have so far, but it isn't really working.
Sub FindDuplicates()
Sheetcounter = 0
Set MyData = Worksheets("Sheet1").Range("C1:C" & Cells(Rows.Count, "C").End(xlUp).Row)
Do Until Sheetcounter = 3
Set MyUniqueList = CreateObject("Scripting.Dictionary")
MyUniqueList.RemoveAll
Range(Cells(1, 1), Cells(5000, 1)).Interior.Color = xlNone
Application.ScreenUpdating = False
MyDupList = "": MyCounter = 0
For Each Cell In MyData
If Evaluate("COUNTIF(" & MyData.Address & "," & Cell.Address & ")") > 1 Then
If Cell.Value <> "" Then
Cell.Interior.Color = RGB(255, 80, 80)
If MyUniqueList.exists(CStr(Cell)) = False Then
MyCounter = MyCounter + 1
MyUniqueList.Add CStr(Cell), MyCounter
If MyDupList = "" Then
MyDupList = Cell
Else
MyDupList = MyDupList & vbNewLine & Cell
End If
End If
End If
Else
Cell.Interior.ColorIndex = xlNone
End If
Next Cell
Application.ScreenUpdating = True
If MyDupList <> "" Then
MsgBox "The following entries have been used more than once:" & vbNewLine & MyDupList
Else
MsgBox "There were no duplicates found in " & MyData.Address
End If
Sheetcounter = Sheetcounter + 1
If Sheetcounter = 1 Then
Set MyData = Worksheets("Sheet2").Range("C1:C" & Cells(Rows.Count, "C").End(xlUp).Row)
End If
If Sheetcounter = 2 Then
Set MyData = Worksheets("Sheet3").Range("C1:C" & Cells(Rows.Count, "C").End(xlUp).Row)
End If
Loop
End Sub
you can simplify your sub like follows:
Option Explicit
Sub FindDuplicates()
Dim sheetCounter As Long
Dim myData As Range, cell As Range
Dim myUniqueList As Scripting.Dictionary
Set myUniqueList = CreateObject("Scripting.Dictionary")
For sheetCounter = 1 To 3
myUniqueList.RemoveAll
With Worksheets("Sheet00" & sheetCounter)
Set myData = .Range("C1", .Cells(.Rows.Count, "C").End(xlUp))
End With
myData.Interior.Color = xlNone
For Each cell In myData.SpecialCells(xlCellTypeConstants)
If WorksheetFunction.CountIf(myData, cell) > 1 Then
cell.Interior.Color = RGB(255, 80, 80)
If Not myUniqueList.Exists(CStr(cell)) Then myUniqueList.Add CStr(cell), myUniqueList.Count + 1
End If
Next cell
If myUniqueList.Count > 0 Then
MsgBox "The following entries have been used more than once:" & vbNewLine & Join(myUniqueList.Keys, vbNewLine)
Else
MsgBox "There were no duplicates found in " & myData.Address
End If
Next sheetCounter
End Sub

Macro to consolidate data from 2 different worksheets of each wkbook inside subfolders and show result in separate worksheets for each subfolder

I'm doing an office project where i need to create a macro.
I have a folder with 30 subfolders each named after our branches. For example- Chicago branch, New York branch etc. Each subfolder contains a number of workbooks and each workbook has a number of worksheet full of data.
I made a macro to extract a number of cells from the worksheet called "Menu" and one cell from the worksheet called "score" and paste it in a new workbook.
I have researched online and made two separate macros to get the data from the two seperate worksheets. But it only works if I select all the files I want inside a subfolder.
I also found some code to access folders inside subfolders but I couldn't compile it with my current code. In addition, I couldn't join the two macros I made, so it'd require only one button instead of two.
Now, I need a macro which will ask me to select a folder and go to the subfolders and folders inside the subfolders by itself and consolidate the data in a new workbook BUT in separate worksheets based on the Subfolders( the branch named ones, not the folders inside subfolders.
The data extracted from workbooks in the folders inside subfolders need to be in the worksheet named after the subfolder.) The idea is to have to press the command button once to get all the data extracted from that folder and subfolders inside at once as its too hectic to use my code 30 times for 30 subfolders to get data of 30 branches.
"Macro for extracting data from the worksheet MENU of each workbook"
Private Sub CommandButton1_Click()
Dim FileNameXls As Variant
Dim SummWks As Worksheet
Dim ColNum As Integer
Dim myCell As Range, Rng As Range
Dim RwNum As Long, FNum As Long, FinalSlash As Long
Dim ShName As String, PathStr As String
Dim SheetCheck As String, JustFileName As String
Dim JustFolder As String
Dim aCell As Range, bCell As Range
Dim lastRow As Long, i As Long
Dim ExitLoop As Boolean
ShName = "Menu" '<---- Change
Set Rng = Range("B9:b13") '<---- Change
'Select the files with GetOpenFilename
FileNameXls = Application.GetOpenFilename(filefilter:="Excel Files, *.xl*", _
MultiSelect:=True)
If IsArray(FileNameXls) = False Then
'do nothing
Else
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Add a new workbook with one sheet for the Summary
Set SummWks = Sheets("Sheet1")
'The links to the first workbook will start in row 2
RwNum = 2
For FNum = LBound(FileNameXls) To UBound(FileNameXls)
ColNum = 1
RwNum = RwNum + 1
FinalSlash = InStrRev(FileNameXls(FNum), "\")
JustFileName = Mid(FileNameXls(FNum), FinalSlash + 1)
JustFolder = Left(FileNameXls(FNum), FinalSlash - 1)
'build the formula string
JustFileName = WorksheetFunction.Substitute(JustFileName, "'", "''")
PathStr = "'" & JustFolder & "\[" & JustFileName & "]" & ShName & "'!"
On Error Resume Next
SheetCheck = ExecuteExcel4Macro(PathStr & Range("A1").Address(, , xlR1C1))
If Err.Number <> 0 Then
'If the sheet not exist in the workbook the row color will be Yellow.
SummWks.Cells(RwNum, 1).Resize(1, Rng.Cells.Count + 1) _
.Interior.Color = vbYellow
Else
For Each myCell In Rng.Cells
ColNum = ColNum + 1
SummWks.Cells(RwNum, ColNum).Formula = _
"=" & PathStr & myCell.Address
Next myCell
End If
On Error GoTo 0
Next FNum
' Use AutoFit to set the column width in the new workbook
SummWks.UsedRange.Columns.AutoFit
Range("b2").Select
ActiveCell.FormulaR1C1 = "Client Name"
Range("C2").Select
ActiveCell.FormulaR1C1 = "Occupation"
Range("D2").Select
ActiveCell.FormulaR1C1 = "Date"
Range("E2").Select
ActiveCell.FormulaR1C1 = "Insured Location"
Range("F2").Select
ActiveCell.FormulaR1C1 = "Serveyed by"
Range("B1").Select
ActiveCell.FormulaR1C1 = "=""Property Risk Scores Updated as at """
Rows("1:1").RowHeight = 27.75
Range("B1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("C1").Select
ActiveCell.FormulaR1C1 = "=TODAY()"
Range("c1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("b2:f2").Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
Selection.Font.Bold = True
Application.ScreenUpdating = True
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Date", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
Next
End Sub
"Macro for extracting data from the worksheet SCORE of each workbook"
Private Sub CommandButton2_Click()
Dim FileNameXls As Variant
Dim SummWks As Worksheet
Dim ColNum As Integer
Dim myCell As Range, Rng As Range
Dim RwNum As Long, FNum As Long, FinalSlash As Long
Dim ShName As String, PathStr As String
Dim SheetCheck As String, JustFileName As String
Dim JustFolder As String
Dim aCell As Range, bCell As Range
Dim lastRow As Long, i As Long
Dim ExitLoop As Boolean
ShName = "score" '<---- Change
Set Rng = Range("f65") '<---- Change
'Select the files with GetOpenFilename
FileNameXls = Application.GetOpenFilename(filefilter:="Excel Files, *.xl*", _
MultiSelect:=True)
If IsArray(FileNameXls) = False Then
'do nothing
Else
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Add a new workbook with one sheet for the Summary
Set SummWks = Sheets("Sheet1")
'The links to the first workbook will start in row 2
RwNum = 2
For FNum = LBound(FileNameXls) To UBound(FileNameXls)
ColNum = 6
RwNum = RwNum + 1
FinalSlash = InStrRev(FileNameXls(FNum), "\")
JustFileName = Mid(FileNameXls(FNum), FinalSlash + 1)
JustFolder = Left(FileNameXls(FNum), FinalSlash - 1)
'build the formula string
JustFileName = WorksheetFunction.Substitute(JustFileName, "'", "''")
PathStr = "'" & JustFolder & "\[" & JustFileName & "]" & ShName & "'!"
On Error Resume Next
SheetCheck = ExecuteExcel4Macro(PathStr & Range("A1").Address(, , xlR1C1))
If Err.Number <> 0 Then
'If the sheet not exist in the workbook the row color will be Yellow.
SummWks.Cells(RwNum, 1).Resize(1, Rng.Cells.Count + 1) _
.Interior.Color = vbYellow
Else
For Each myCell In Rng.Cells
ColNum = ColNum + 1
SummWks.Cells(RwNum, ColNum).Formula = _
"=" & PathStr & myCell.Address
Next myCell
End If
On Error GoTo 0
Next FNum
' Use AutoFit to set the column width in the new workbook
SummWks.UsedRange.Columns.AutoFit
Range("g2").Select
ActiveCell.FormulaR1C1 = "Score"
Range("g2").Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
Selection.Font.Bold = True
Application.ScreenUpdating = True
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Score", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
Next
End Sub
#dave I'm posting this as an answer because it's too long to post as a comment. Can you please check which parts need correction? Thanks a lot!
Also I needed a code that will put the branch data in different worksheets. For example in sheet 1 will contain all the info I extracted from X branch folder,sheet 2 will contain all the info I extracted from Y branch folder.
Private Sub CommandButton1_Click()
Dim FileNameXls As Variant
Dim SummWks As Worksheet
Dim ColNum As Integer
Dim myCell As Range, Rng As Range
Dim RwNum As Long, FNum As Long, FinalSlash As Long
Dim ShName As String, PathStr As String
Dim SheetCheck As String, JustFileName As String
Dim JustFolder As String
Dim aCell As Range, bCell As Range
Dim lastRow As Long, i As Long
Dim ExitLoop As Boolean
Dim oSheet: Set oSheet = ThisWorkbook.Worksheets("Sheet to copy to in here")
Dim oFso: Set oFso = CreateObject("Scripting.FileSystemObject")
Dim oFolder: Set oFolder = oFso.GetFolder("Path to Desktop Branch Data folder in here")
Dim oSubFolder, oBranchWorkbook, oWorksheet
For Each oSubFolder In oFolder.SubFolders
Debug.Print "Looking inside " & oSubFolder.Name
Set oBranchWorkbook = Workbooks.Open(oSubFolder.Path & "*.xl*")
' Now you have the Info.xls from whichever branch folder we are in open
Set oWorksheet = oBranchWorkbook.Worksheets("Menu")
' Extract whatever you need from Menu to the current workbook, e.g.
oSheet.Range("B2").Value = oWorksheet.Range("B9:b13").Value
' Once you complete the Menu extract, change oWorksheet to point at Score
Set oWorksheet = oBranchWorkbook.Worksheets("Score")
' Extract whatever you need from Score to the current workbook, e.g.
oSheet.Range("G2").Value = oWorksheet.Range("F65").Value
'Once you have completed all the extracts you need, close the branch workbook
oBranchWorkbook.Close
Next ' Move onto next subfolder and repeat the process...
If IsArray(FileNameXls) = False Then
'do nothing
Else
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'Add a new workbook with one sheet for the Summary
Set SummWks = Sheets("Sheet1")
'The links to the first workbook will start in row 2
RwNum = 2
For FNum = LBound(FileNameXls) To UBound(FileNameXls)
ColNum = 1
RwNum = RwNum + 1
FinalSlash = InStrRev(FileNameXls(FNum), "\")
JustFileName = Mid(FileNameXls(FNum), FinalSlash + 1)
JustFolder = Left(FileNameXls(FNum), FinalSlash - 1)
'build the formula string
JustFileName = WorksheetFunction.Substitute(JustFileName, "'", "''")
PathStr = "'" & JustFolder & "\[" & JustFileName & "]" & ShName & "'!"
On Error Resume Next
SheetCheck = ExecuteExcel4Macro(PathStr & Range("A1").Address(, , xlR1C1))
If Err.Number <> 0 Then
'If the sheet not exist in the workbook the row color will be Yellow.
SummWks.Cells(RwNum, 1).Resize(1, Rng.Cells.Count + 1) _
.Interior.Color = vbYellow
Else
For Each myCell In Rng.Cells
ColNum = ColNum + 1
SummWks.Cells(RwNum, ColNum).Formula = _
"=" & PathStr & myCell.Address
Next myCell
End If
On Error GoTo 0
Next FNum
' Use AutoFit to set the column width in the new workbook
SummWks.UsedRange.Columns.AutoFit
Range("b2").Select
ActiveCell.FormulaR1C1 = "Client Name"
Range("C2").Select
ActiveCell.FormulaR1C1 = "Occupation"
Range("D2").Select
ActiveCell.FormulaR1C1 = "Date"
Range("E2").Select
ActiveCell.FormulaR1C1 = "Insured Location"
Range("F2").Select
ActiveCell.FormulaR1C1 = "Serveyed by"
Range("g2").Select
ActiveCell.FormulaR1C1 = "Score"
Range("B1").Select
ActiveCell.FormulaR1C1 = "=""Property Risk Scores Updated as at """
Rows("1:1").RowHeight = 27.75
Range("B1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("C1").Select
ActiveCell.FormulaR1C1 = "=TODAY()"
Range("c1").Select
With Selection.Font
.Name = "Calibri"
.Size = 16
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
Range("b2:g2").Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
Selection.Font.Bold = True
Application.ScreenUpdating = True
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Date", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "dd/mm/yyyy;#"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End If
For Each SummWks In ThisWorkbook.Sheets
Set aCell = SummWks.Rows(2).Find(what:="Score", LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
With SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i)
.FormulaR1C1 = .Value
End With
Next i
SummWks.Columns(aCell.Column).AutoFit
Do While ExitLoop = False
Set aCell = SummWks.Rows(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
SummWks.Columns(aCell.Column).NumberFormat = "0%"
lastRow = SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & _
SummWks.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).FormulaR1C1 = _
SummWks.Range(Split(SummWks.Cells(, aCell.Column).Address, "$")(1) & i).Value
Next i
Else
ExitLoop = True
End If
Loop
End If
Next
Next
End Sub
Okay, I think I understand the requirement. Try something along these lines?
Dim oSheet
Dim oFso : Set oFso = CreateObject("Scripting.FileSystemObject")
Dim oFolder : Set oFolder = oFso.GetFolder("Path to Desktop Branch Data folder in here")
Dim oSubFolder, oBranchWorkbook, oWorksheet, iSheet
iSheet = 1
For Each oSubFolder in oFolder.SubFolders
Debug.Print "Looking inside " & oSubFolder.Name
' Set the sheet to copy to (1 on the first, 2 on the second etc)
' this would be better if the sheets were named for each branch folder
' as then instead of iSheet you could use oSubFolder.Name and it wouldn't matter if things were out of order for some reason...
Set oSheet = ThisWorkbook.Worksheets(iSheet)
For Each oFile in oSubFolder.Files
If Right(oFile.Name,3) = "xls" or Right(oFile.Name, 4) = "xlsx" Then
Set oBranchWorkbook = Workbooks.Open(oSubFolder.Path & oFile.Name)
' Now you have the Info.xls from whichever branch folder we are in open
Set oWorksheet = oBranchWorkbook.Worksheets("Menu")
' Extract whatever you need from Menu to the current workbook, e.g.
oSheet.Range("A1").Value = oWorksheet.Range("B1").Value
' Once you complete the Menu extract, change oWorksheet to point at Score
Set oWorksheet = oBranchWorkbook.Worksheets("Score")
' Extract whatever you need from Score to the current workbook, e.g.
oSheet.Range("A1").Value = oWorksheet.Range("B1").Value
'Once you have completed all the extracts you need, close the branch workbook
oBranchWorkbook.Close
End If
Next
iSheet = iSheet + 1 ' increment sheet counter
Next ' Move onto next subfolder and repeat the process...