VBA Selecting a range for multiple sheets - vba

I am trying to use a sub routine to run through 10 team names in a sheet called Parameter. Each of the team names has its own sheet. I am trying to get the user to select the range and then have my sub run through and create charts for the 10 teams based on the range selected.
Sub test()
Dim rng As Range
Dim r As String
Application.ScreenUpdating = False
Dim TeamName As String
Set rng = Application.InputBox( _
Prompt:="Select a range.", _
Title:="Obtain Range Object", Type:=8)
r = "'" & TeamName & "'!" & rng.CurrentRegion.Address(ReferenceStyle:=xlR1C1)
For i = 1 To 10
TeamName = Sheets("Parameter").Range("E" & i).Value 'identify the location
Call charts(TeamName) ' Call subroutine
Next i
Application.ScreenUpdating = True
End Sub
Sub charts(TeamName As String)
Dim strTitle As Integer
Dim chtObj As ChartObject
Dim i As Integer
For Each chtObj In ActiveSheet.ChartObjects
chtObj.Delete
Next
For i = 1 To 42 Step 4
j = j + 1
Endrow = Range("A1").End(xlUp).Row - 1
Set Range1 = r.Offset(Endrow, i + 1)
Sheets(TeamName).Select
strTitle = j
MyFunction = ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlLineMarkers
ActiveChart.HasLegend = False
ActiveChart.HasTitle = True
ActiveChart.ChartTitle.Text = "PC " & j
ActiveChart.SetSourceData Source:=Range1
Dim MyWidth As Single, MyHeight As Single
Dim NumWide As Long
Dim iChtIx As Long, iChtCt As Long
MyWidth = 300
MyHeight = 200
NumWide = 5
iChtCt = ActiveSheet.ChartObjects.Count
For iChtIx = 1 To iChtCt
With ActiveSheet.ChartObjects(iChtIx)
.Width = MyWidth
.Height = MyHeight
.Left = ((iChtIx - 1) Mod NumWide) * MyWidth
.Top = Int((iChtIx - 1) / NumWide) * MyHeight
End With
Next
ActiveChart.SetElement (msoElementPrimaryCategoryAxisNone)
ActiveChart.SetElement (msoElementPrimaryValueGridLinesNone)
Next i
End Sub

Related

How to create a chart on the same worksheet using a for loop statement?

Name Progress
Student1 93
Student2 80
Student3 51
Student4 91
Student5 65
Student6 45
student7 33
I am still new to VBA programming. Above is my data set example and below is my code which is able to populate columns C to E to the right without giving any error. Below is my chart code which gives me a bad chart when I run it. Please advise on how to go about plotting these populated values on columns C to E on a bar chart on the same worksheet, where a green bar shows progress >= 90, amber bar shows 50 <= Progress And Progress < 90 and red bar shows progress <50.
Sub ClassCategories()
Dim startRow As Long, lastRow As Long, n As Integer
startRow = 2
n = 8
Dim i As Long, Progress As Long
Dim sClass1 As String
Dim sClass2 As String
Dim sClass3 As String
For i = startRow To n
Progress = ThisWorkbook.Worksheets("sheet1").Range("B" & i).Value
' Check progress and classify accordingly
If Progress >= 90 Then
sClass3 = Progress
Else
sClass3 = " "
End If
If 50 <= Progress And Progress < 90 Then
sClass2 = Progress
Else
sClass2 = " "
End If
If Progress < 50 Then
sClass1 = Progress
Else
sClass1 = " "
End If
' Write out the class to column C to E
Worksheets("sheet1").Range("C" & i).Value = sClass1
Worksheets("sheet1").Range("D" & i).Value = sClass2
Worksheets("sheet1").Range("E" & i).Value = sClass3
Next
End Sub
Private Sub Createachart()
Dim oChObj As ChartObject, rngSourceData As Range, ws As Worksheet
Set ws = Sheets("Sheet1")
Set rngSourceData = ws.Range("C3:E8")
Set oChObj = ws.ChartObjects.Add(Left:=ws.Columns("A").Left,
Width:=290, Top:=ws.Rows(8).Top, Height:=190)
With oChObj.Chart
.ChartType = xlColumnClustered
.SetSourceData Source:=rngSourceData, PlotBy:=xlColumns
.Axes(xlCategory).CategoryNames = ws.Range("A2:A8")
.HasTitle = True
End With
End Sub
I guess this code is what you need (providing your example table starts in A1 cell):
Sub CreateChart()
Dim sh As Shape
Dim ch As Chart
Dim ser As Series
Dim lColor&, i%, x, arr
'// Remove all charts
For Each sh In ActiveSheet.Shapes
If sh.Type = msoChart Then sh.Delete
Next
'// Add chart to sheet
With Range("A10:N30")
Set ch = .Parent.Shapes.AddChart(xlColumn, .Left, .Top, .Width, .Height).Chart
End With
With ch
'// If user's selection is within chart data range,
'// then Excel will create chart based on data in this range.
'// We don't need it, so clear the chart out.
.ChartArea.ClearContents
'// Add series
Set ser = ch.SeriesCollection.NewSeries()
ser.Values = Range("B2:B8").Value
ser.XValues = Range("A2:A8").Value
'// Get values
arr = ser.Values
'// Format points based on values
For i = 1 To UBound(arr)
x = arr(i)
Select Case True
Case x >= 90: lColor = vbGreen
Case x >= 50 And x < 90: lColor = vbYellow
Case x < 50: lColor = vbRed
End Select
ser.Points(i).Format.Fill.ForeColor.RGB = lColor
Next
End With
End Sub
You can download workbook with code here.
Result:

vba legacy function to return row count returns 1 instead

I'm working with some legacy code I'd like to build on and I can't seem to figure out the following: Why does the function AantalZichtbareRows return 1? Where It says For Each row In rng.Rows the row count is 1500 something (and so is the actual excel I'm working with).
I'm specifically puzzeled by n = r.Areas.Count. This is where the 1 originates.
Sub motivatieFormOpmaken()
Public iLaatsteKolom As Integer
Public iLaatsteRij As Integer
Public iKolomnrCorpID As Integer
Public iKolomnrNaam As Integer
Public iKolomnrHuidigeFunctie As Integer
Const StBestand = "Stambestand.xlsm"
Const motivatie = "Template motivatieformulier opstapregeling.xlsx"
Dim wbMotivTemp As Workbook
Dim wsMotiv As Worksheet
Dim PathOnly, mot, FileOnly As String
Dim StrPadSourcenaam As String
Set wbMotivTemp = ThisWorkbook
Set wsMotiv = ActiveSheet
StrHoofdDocument = ActiveWorkbook.Name
StrPadHoofdDocument = ActiveWorkbook.Path
StrPadSourcenaam = StrPadHoofdDocument & "\" & c_SourceDump
If Not FileThere(StrPadSourcenaam) Then
MsgBox "Document " & StrPadSourcenaam & " is niet gevonden."
Exit Sub
End If
Application.ScreenUpdating = False
Workbooks.Open FileName:=StrPadSourcenaam
Application.Run "Stambestand.xlsm!unhiderowsandcolumns"
Worksheets("stambestand").Activate
iLaatsteKolom = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).Column
iLaatsteRij = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).row
VulKolomNr
If KolomControle = False Then Exit Sub
Aantalregels = AantalZichtbareRows
Dim rng As Range
Dim row As Range
Dim StrFileName As String
'If Aantalregels > 1 Then
Set rng = Selection.SpecialCells(xlCellTypeVisible)
For Each row In rng.Rows
iRijnummer = row.row
If iRijnummer > 1 Then
wsMotiv.Range("motiv_cid") = Cells(iRijnummer, iKolomnrCorpID).Text
wsMotiv.Range("motiv_naam") = Cells(iRijnummer, iKolomnrNaam).Text
wsMotiv.Range("motiv_ldg") = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
n = naamOpmaken
wbMotivTemp.Activate
ActiveWorkbook.SaveAs FileName:=StrPadHoofdDocument & "\Docs\" & n & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
End If
Next row
End Sub
Function naamOpmaken() As String
Dim rng As Range
Dim row As Range
Set rng = Selection.SpecialCells(xlCellTypeVisible)
iRijnummer = rng.row
If iRijnummer > 1 Then
naam = Cells(iRijnummer, iKolomnrNaam).Text
ldg = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
cid = Cells(iRijnummer, iKolomnrCorpID).Text
Dim Position As Long, Length As Long
Dim n As String
Position = InStrRev(naam, " ")
Length = Len(naam)
n = Right(naam, Length - Position)
End If
naamOpmaken = n + "-" + ldg + "-" + cid
End Function
Public Function AantalZichtbareRows() As Integer
Dim rwCt As Long
Dim r As Range
Dim n As Long
Dim I As Long
Set r = Selection.SpecialCells(xlCellTypeVisible)
n = r.Areas.Count
For I = 1 To n
rwCt = rwCt + r.Areas(I).Rows.Count
Next I
AantalZichtbareRows = rwCt
End Function
Range.areas specifies the number of selection areas. Range.Areas
I tested your code and it works as expected. You can have a single selection area containing 1500 rows. Example: "A1:A1500" Or you can have a selection containing 2 areas with three rows each for a total of 6 rows. Example: "A1:A3" and "C4:C6".
This code might help you understand how the method returns information about the selected cells.
Public Function AantalZichtbareRows() As Integer
Dim rwCt As Long
Dim rwCt2 As Long
Dim r As Range
Dim n As Long
Dim I As Long
Set r = Selection.SpecialCells(xlCellTypeVisible)
n = r.Areas.Count
For I = 1 To n
rwCt = rwCt + r.Areas(I).Rows.Count
Next I
Set r = Selection
n = r.Areas.Count
For I = 1 To n
rwCt2 = rwCt2 + r.Areas(I).Rows.Count
Next I
Debug.Print n & " areas selected."
Debug.Print rwCt2 & " rows selected."
Debug.Print rwCt & " visible rows selected."
Debug.Print (rwCt2 - rwCt) & " hidden rows selected."
AantalZichtbareRows = rwCt
End Function

vba only add new series to the chart if it does not exist

I have several sheets in my workbook which contains data to plot, every time I run a new analysis a new sheet is generated.
On my first sheet I plot all the data in the same graph, so to avoid re plotting all the series every time I append a new sheet I would like to just add a new series.
I thought that should be simple, but it is not for two reasons: When I first create the chart it adds somewhere between 1 and 9 series automatically:
Set myChart = ws.Shapes.AddChart.Chart
myChart.ChartType = xlXYScatterLinesNoMarkers
why does this generate any random series?
also if I delete the graph because I want to rerun one analysis, the graph will then be called 2 and so on... So I tried to give it a name and refer to its name instead, however that does not work:
Set myChart = ws.ChartObjects(ws.Name)
So in the first sheet(Orginal) I plot all data in the workbook, and in the rest I just plot the data for the current sheet as seen below. I use the same code function for both cases, where i just pass the argument all as true(orginal sheet) or false(sheet 1.....300)
Below is the code:
Sub createChart(ws As Worksheet, Optional all As Boolean = False)
Dim lastRow As Long
Dim myChart As Chart
Dim temp As Integer
Dim n As Integer
On Error Resume Next
' Delete the charts, just in case
If ws.ChartObjects.Count > 0 Then ' And Not all Then
ws.ChartObjects.Delete
End If
'If ws.ChartObjects.Count = 0 Then
Set myChart = ws.Shapes.AddChart.Chart
myChart.Name = ws.Name
'Else
'Set myChart = ws.ChartObjects(ws.Name) '''Fails why commented out
'End If
myChart.ChartType = xlXYScatterLinesNoMarkers
myChart.SetElement (msoElementPrimaryCategoryGridLinesMinor)
myChart.SetElement (msoElementPrimaryValueGridLinesMinorMajor)
myChart.SetElement (msoElementLegendBottom)
myChart.SetElement (msoElementChartTitleCenteredOverlay)
myChart.Parent.width = 800 ' px width graph
myChart.Parent.height = 500 ' px height graph
' it adds mysterious sometimes several random series, so we need to delete those that does not match sheet name
For n = myChart.SeriesCollection.Count To 0 Step -1
If Not SheetExists(myChart.SeriesCollection(n).Name) Then
myChart.SeriesCollection(n).Delete
End If
Next n
'*******************************************************************
'**************** FIRST PAGE CHART *********************************
'*******************************************************************
If all Then
Dim wsOther As Worksheet
Dim i As Integer
Dim fixRange As Boolean
Dim skipGraph As Boolean
fixRange = True
myChart.HasLegend = True
myChart.Legend.Position = xlLegendPositionRight
myChart.Parent.Top = 120
myChart.Parent.Left = 450
For Each wsOther In ThisWorkbook.Worksheets
If wsOther.Name <> ws.Name Then
lastRow = getLastRow(wsOther, 1)
skipGraph = False
'******* we only add graphs if it is not before ******************
If myChart.SeriesCollection.Count > 0 Then
For n = myChart.SeriesCollection.Count To 1 Step -1
If myChart.SeriesCollection(n).Name = wsOther.Name Then
skipGraph = True
Exit For
End If
Next n
End If
If Not skipGraph Then
With myChart.SeriesCollection.NewSeries
.Values = "=" & wsOther.Name & "!$E$2:$E$" & lastRow
.Name = wsOther.Name
.XValues = "=" & wsOther.Name & "!$B$2:$B$" & lastRow
End With
End If
If fixRange Then
' Range on axis
myChart.Axes(xlPrimary).MinimumScale = CDate(Application.WorksheetFunction.Min(Range(wsOther.Name & "!$B$2:$B$" & lastRow).Value2))
myChart.Axes(xlPrimary).MaximumScale = CDate(Application.WorksheetFunction.Max(Range(wsOther.Name & "!$B$2:$B$" & lastRow).Value2))
myChart.Axes(xlValue, xlPrimary).ScaleType = xlLogarithmic
fixRange = False
End If
End If
Next
'*******************************************************************************************************
'****************** SINGLE CHART ***********************************************************************
'*******************************************************************************************************
Else
myChart.HasLegend = False
myChart.Parent.Top = 40
myChart.Parent.Left = 300
lastRow = getLastRow(ws, 1)
With myChart.SeriesCollection.NewSeries
.Values = "=" & ws.Name & "!$E$2:$E$" & lastRow
.XValues = "=" & ws.Name & "!$B$2:$B$" & lastRow
End With
' Range on axis
myChart.Axes(xlPrimary).MinimumScale = CDate(Application.WorksheetFunction.Min(Range(ws.Name & "!$B$2:$B$" & lastRow).Value2))
myChart.Axes(xlPrimary).MaximumScale = CDate(Application.WorksheetFunction.Max(Range(ws.Name & "!$B$2:$B$" & lastRow).Value2))
End If
' *********************************************************************
' ******************* Sizing ******************************************
' *********************************************************************
With myChart.PlotArea
temp = .Top
temp = .height
.Top = 70
.height = 420
End With
'really dirty and crappy formatting of title
myChart.ChartTitle.Text = "Faraday Torr"
'X axis name
myChart.Axes(xlCategory, xlPrimary).HasTitle = True
myChart.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time [s]"
'y-axis name
myChart.Axes(xlValue, xlPrimary).HasTitle = True
myChart.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Pressure[Torr]"
Set myChart = Nothing
Set wsOther = Nothing
ws.Select
ws.Range("A1").Select
End Sub

series deletion in chart

I have an table and would like to generate an chart out of it. the problem is I would like to have only the column Values of A, F, G, and H.
I tried seriescollection(1).deletion method,. but I am still getting the column B and C series in my chart.
Could anyone tell me how I can do it.
Any lead would be helpful
Sub chartstatus()
Dim Rng As Range
Dim cht As Object
Set Rng = ActiveSheet.Range("A2:H53")
ThisWorkbook.Sheets("Status").ChartObjects.delete
Set Sh = ActiveSheet.ChartObjects.Add(Left:=650, _
Width:=600, _
Top:=80, _
Height:=250)
Sh.Select
Set cht = ActiveChart
With cht
.SetSourceData Source:=Rng
.ChartType = xlColumnClustered
cht.Axes(xlSecondary).TickLabels.NumberFormat = "0.%"
End With
cht.SeriesCollection(6).Name = " % Missing "
cht.SeriesCollection(7).Name = " % OnTime"
cht.SeriesCollection(8).Name = " % Delayed"
cht.SeriesCollection(6).HasDataLabels = True
cht.SeriesCollection(7).HasDataLabels = True
cht.SeriesCollection(8).HasDataLabels = True
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(255, 255, 255) '<~~ Red
cht.HasTitle = True
cht.ChartTitle.Text = "Result "
End Sub
You can combine 2 range into 1 range
Dim Rng As Range
Dim Rng_A As Range
Dim Rng_FH As Range
Set Rng_A = ActiveSheet.Range("A2:A52")
Set Rng_FH = ActiveSheet.Range("F2:H52")
Set Rng = Union(Rng_A, Rng_FH)

Insert inputboxes making code more interactive

I am currently working on the following code which is searching through all tabs in an excel workbook, selects all currencies greater a certain threshold in a defined column "J" and if criteria is met the line containing the currency that is greater threshold is pasted in a new created tab called "summary".
Now my question is:
1. Is there any chance to make this code more interactive? What I would like to do, is to add an inputbox in which the user is typing his threshold (in my example 1000000) and this threshold is used for looping through all tabs.
2. It would be great to get an input box like "select column containing currency", as column "J" won't be set all time, it could also be another column ("I", "M" etc) however this will be the same for all sheets then.
3. Any chance to select certain sheets within workbook (STRG + "sheetx" "sheety" etc....) which are then pasted into my loop and all others are neglected?
Any help, especially for my issues within question 1 and 2 is appreciated. Question 3 would only be a "nice-to-have" thing
Option Explicit
Sub Test()
Dim WS As Worksheet
Set WS = Sheets.Add
WS.Name = "Summary"
Dim i As Long, j As Long, lastRow As Long
Dim sh As Worksheet
With Sheets("Summary")
.Cells.Clear
End With
j = 2
For Each sh In ActiveWorkbook.Sheets
If sh.Name <> "Summary" Then
lastRow = sh.Cells(sh.Rows.Count, "A").End(xlUp).Row
For i = 4 To lastRow
If sh.Range("J" & i) > 1000000 Or sh.Range("J" & i) < -1000000 Then
sh.Range("a" & i & ":n" & i).Copy Destination:=Worksheets("Summary").Range("A" & j)
Sheets("Summary").Range("N" & j) = sh.Name
j = j + 1
End If
Next i
End If
Next sh
Sheets("Summary").Columns("A:N").AutoFit
End Sub
You may want to try this
Option Explicit
Sub Test()
Dim WS As Worksheet
Dim i As Long, j As Long, lastRow As Long
Dim sh As Worksheet
Dim sheetsList As Variant
Dim threshold As Long
Set WS = GetSheet("Summary", True)
sheetsList = Array("STRG","sheetx","sheety") '<--| fill this array with the sheets names to be looped through
threshold = Application.InputBox("Input threshold", Type:=1)
j = 2
For Each sh In ActiveWorkbook.Sheets(sheetsList)
lastRow = sh.Cells(sh.Rows.Count, "A").End(xlUp).Row
For i = 4 To lastRow
If sh.Range("J" & i) > threshold Or sh.Range("J" & i) < -threshold Then
sh.Range("a" & i & ":n" & i).Copy Destination:=WS.Range("A" & j)
WS.Range("N" & j) = sh.Name
j = j + 1
End If
Next i
Next sh
WS.Columns("A:N").AutoFit
End Sub
Function GetSheet(shtName As String, Optional clearIt As Boolean = False) As Worksheet
On Error Resume Next
Set GetSheet = Worksheets(shtName)
If GetSheet Is Nothing Then
Set GetSheet = Sheets.Add(after:=Worksheets(Worksheets.count))
GetSheet.Name = shtName
End If
If clearIt Then GetSheet.UsedRange.Clear
End Function
You can set a UserForm as input into the program - something like what follows. You only need to run the 'CreateUserForm' sub once to get the UserForm1 event handlers set up in your spreadsheet. Once that's done you can run the 'Test' to see the UserForm1 itself. You can edit the event handlers to check the user input or reject it if need be. Also once the UserForm1 is set up you can move the various labels and listboxes around and, of course, create new ones. It should look like this:
You can select as many sheets as required from the last listbox and the selections will be added to a vba Collection. See the MsgBox at the beginning of your code and play with entering values/selections into the user box to see what it does.
The UserForm handler that's called when you press the okay button will save the selections to global variables so that they can be picked up in the code.
Option Explicit
' Global Variables used by UserForm1
Public lst1BoxData As Variant
Public threshold As Integer
Public currencyCol As String
Public selectedSheets As Collection
' Only need to run this once. It will create UserForm1.
' If run again it will needlessly create another user form that you don't need.
' Once it's run you can modify the event handlers by selecting the UserForm1
' object in the VBAProject Menu by right clicking on it and selecting 'View Code'
' Note that you can select multiple Sheets on the last listbox of the UserForm
' simply by holding down the shift key.
Sub CreateUserForm()
Dim myForm As Object
Dim X As Integer
Dim Line As Integer
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
'Create the User Form
With myForm
.Properties("Caption") = "Currency Settings"
.Properties("Width") = 322
.Properties("Height") = 110
End With
' Create Label for threshold text box
Dim thresholdLabel As Object
Set thresholdLabel = myForm.Designer.Controls.Add("Forms.Label.1")
With thresholdLabel
.Name = "lbl1"
.Caption = "Input Threshold:"
.Top = 6
.Left = 6
.Width = 72
End With
'Create TextBox for the threshold value
Dim thresholdTextBox As Object
Set thresholdTextBox = myForm.Designer.Controls.Add("Forms.textbox.1")
With thresholdTextBox
.Name = "txt1"
.Top = 18
.Left = 6
.Width = 75
.Height = 16
.Font.Size = 8
.Font.Name = "Tahoma"
.borderStyle = fmBorderStyleSingle
.SpecialEffect = fmSpecialEffectSunken
End With
' Create Label for threshold text box
Dim currencyLabel As Object
Set currencyLabel = myForm.Designer.Controls.Add("Forms.Label.1")
With currencyLabel
.Name = "lbl2"
.Caption = "Currency Column:"
.Top = 6
.Left = 100
.Width = 72
End With
'Create currency column ListBox
Dim currencyListBox As Object
Set currencyListBox = myForm.Designer.Controls.Add("Forms.listbox.1")
With currencyListBox
.Name = "lst1"
.Top = 18
.Left = 102
.Width = 52
.Height = 55
.Font.Size = 8
.Font.Name = "Tahoma"
.borderStyle = fmBorderStyleSingle
.SpecialEffect = fmSpecialEffectSunken
End With
' Create Label for sheet text box
Dim sheetLabel As Object
Set sheetLabel = myForm.Designer.Controls.Add("Forms.Label.1")
With sheetLabel
.Name = "lbl3"
.Caption = "Select Sheets:"
.Top = 6
.Left = 175
.Width = 72
End With
'Create currency column ListBox
Dim sheetListBox As Object
Set sheetListBox = myForm.Designer.Controls.Add("Forms.listbox.1")
With sheetListBox
.Name = "lst3"
.Top = 18
.Left = 175
.Width = 52
.Height = 55
.Font.Size = 8
.MultiSelect = 1
.Font.Name = "Tahoma"
.borderStyle = fmBorderStyleSingle
.SpecialEffect = fmSpecialEffectSunken
End With
'Create Select Button
Dim selectButton As Object
Set selectButton = myForm.Designer.Controls.Add("Forms.commandbutton.1")
With selectButton
.Name = "cmd1"
.Caption = "Okay"
.Accelerator = "M"
.Top = 30
.Left = 252
.Width = 53
.Height = 20
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
' This will create the initialization sub and the click event
' handler to write the UserForm selections into the global
' variables so they can be used by the code.
myForm.CodeModule.InsertLines 1, "Private Sub UserForm_Initialize()"
myForm.CodeModule.InsertLines 2, " me.lst1.addItem ""Column I"" "
myForm.CodeModule.InsertLines 3, " me.lst1.addItem ""Column J"" "
myForm.CodeModule.InsertLines 4, " me.lst1.addItem ""Column M"" "
myForm.CodeModule.InsertLines 5, " me.lst3.addItem ""Sheet X"" "
myForm.CodeModule.InsertLines 6, " me.lst3.addItem ""Sheet Y"" "
myForm.CodeModule.InsertLines 7, " lst1BoxData = Array(""I"", ""J"", ""M"")"
myForm.CodeModule.InsertLines 8, "End Sub"
'add code for Command Button
myForm.CodeModule.InsertLines 9, "Private Sub cmd1_Click()"
myForm.CodeModule.InsertLines 10, " threshold = CInt(Me.txt1.Value)"
myForm.CodeModule.InsertLines 11, " currencyCol = lst1BoxData(Me.lst1.ListIndex)"
myForm.CodeModule.InsertLines 12, " Set selectedSheets = New Collection"
myForm.CodeModule.InsertLines 13, " For i = 0 To Me.lst3.ListCount - 1"
myForm.CodeModule.InsertLines 14, " If Me.lst3.Selected(i) = True Then"
myForm.CodeModule.InsertLines 15, " selectedSheets.Add Me.lst3.List(i)"
myForm.CodeModule.InsertLines 16, " End If"
myForm.CodeModule.InsertLines 17, " Next"
myForm.CodeModule.InsertLines 18, " Unload Me"
myForm.CodeModule.InsertLines 19, "End Sub"
'Add form to make it available
VBA.UserForms.Add (myForm.Name)
End Sub
' This is your code verbatim except for now
' the UserForm is shown for selecting the
' 1) currency threshold, 2) the column letter
' and 3) the sheets you want to process.
' The MsgBox just shows you what you've
' selected just to demonstrate that it works.
Sub Test()
Dim WS As Worksheet
Set WS = Sheets.Add
WS.Name = "Summary"
Dim i As Long, j As Long, lastRow As Long
Dim sh As Worksheet
With Sheets("Summary")
.Cells.Clear
End With
'**** Start: Running & Checking UserForm Output ****
UserForm1.Show
Dim colItem As Variant
Dim colItems As String
For Each colItem In selectedSheets:
colItems = colItems & " " & colItem
Next
MsgBox ("threshold=" & threshold & vbCrLf & _
"currencyCol=" & currencyCol & vbCrLf & _
"selectedSheets=" & colItems)
'**** End: Running & Checking UserForm Output ****
j = 2
For Each sh In ActiveWorkbook.Sheets
If sh.Name <> "Summary" Then
lastRow = sh.Cells(sh.Rows.Count, "A").End(xlUp).row
For i = 4 To lastRow
If sh.Range("J" & i) > 1000000 Or sh.Range("J" & i) < -1000000 Then
sh.Range("a" & i & ":n" & i).Copy Destination:=Worksheets("Summary").Range("A" & j)
Sheets("Summary").Range("N" & j) = sh.Name
j = j + 1
End If
Next i
End If
Next sh
Sheets("Summary").Columns("A:N").AutoFit
End Sub
The following code works for my purposes except the selection of single tabs to loop through:
Option Explicit
Sub Test()
Dim column As String
Dim WS As Worksheet
Dim i As Long, j As Long, lastRow As Long
Dim sh As Worksheet
Dim sheetsList As Variant
Dim threshold As Long
Set WS = GetSheet("Summary", True)
threshold = Application.InputBox("Input threshold", Type:=1)
column = Application.InputBox("Currency Column", Type:=2)
j = 2
For Each sh In ActiveWorkbook.Sheets
If sh.Name <> "Summary" Then
lastRow = sh.Cells(sh.Rows.Count, "A").End(xlUp).Row
For i = 4 To lastRow
If sh.Range(column & i) > threshold Or sh.Range(column & i) < -threshold Then
sh.Range("a" & i & ":n" & i).Copy Destination:=WS.Range("A" & j)
WS.Range("N" & j) = sh.Name
j = j + 1
End If
Next i
End If
Next sh
WS.Columns("A:N").AutoFit
End Sub
Function GetSheet(shtName As String, Optional clearIt As Boolean = False) As Worksheet
On Error Resume Next
Set GetSheet = Worksheets(shtName)
If GetSheet Is Nothing Then
Set GetSheet = Sheets.Add(after:=Worksheets(Worksheets.Count))
GetSheet.Name = shtName
End If
If clearIt Then GetSheet.UsedRange.Clear
End Function