Reputation: 385
I have a userform of 7 checkboxes and some labels that describe them. For each corresponding checkbox there is an array from which there will be created a report if the checkbox is checked as true. However, it doesn't loop through correctly.
I want it to loop through as A, B, C, D, E, F, G
for for each checkbox who have the TabIndex
numbers of 0, 1, 2, 3, 4, 5, 6
respectively. However it loops through in the order of 0,6,5,4,3,2,1
.
I have a main sub that defines and declares variables. My userform print code is as follows:
Sub Get_PDF_Click()
' Creating PDF
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
PDFUserForm.Hide
i = 0
j = 0
For Each ctl In Me.Controls
If TypeName(ctl) = "CheckBox" Then
If ctl.Value = True Then
j = j + 1
Name_of_File = Array(i + 1, 1) & " report" & YYMM & ".xlsx"
Workbooks.Open Filename:=OutputPath & Name_of_File
Set Wkb = Workbooks(Name_of_File)
For Each ws In Wkb.Worksheets
PDF_Name = Array(i + 1, 1) & " " & ws.Name & " " & YYMM
ws.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
OutputPath & PDF_Name, Quality _
:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas _
:=False, OpenAfterPublish:=False
Next ws
Wkb.Close SaveChanges:=False
End If ' See if checked
i = i + 1
Debug.Print ctl.Name
End If ' See if checkbox
Next ctl
If j > 0 Then
' Notification on process time
SecondsElapsed = Round(Timer - StartTime, 0)
MsgBox "PDF succesfully published after " & SecondsElapsed & " seconds." & Chr(10) & "Location: " & OutputPath, vbInformation
Else
MsgBox "No file was selected.", vbInformation
End If
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
As an aside I have a similar problem in another piece of code where I loop through charts on a worksheet which is also looping in the wrong order, so perhaps the same solution concept can be applied to that.
Upvotes: 3
Views: 157
Reputation: 149277
Here is another way ;) This does not need you to hard code the name of the checkboxes.
Logic: Create a 2D array. Store Tabindex
and CheckBox
Name in the array. Sort it on Tabindex
and use it as you want it :)
Code:
Option Explicit
Private Sub Sample()
Dim CbArray() As String
Dim n As Long: n = 1
Dim cbCount As Long
Dim tindex As String, ctlname As String
Dim ctl As Control
Dim i As Long, j As Long
For Each ctl In Me.Controls
If TypeName(ctl) = "CheckBox" Then
n = n + 1
End If
Next
n = n - 1: cbCount = n
ReDim CbArray(1 To n, 1 To 2)
n = 1
'~~> Sort the Tabindex and checkbox name in the array
For Each ctl In Me.Controls
If TypeName(ctl) = "CheckBox" Then
CbArray(n, 1) = ctl.TabIndex
CbArray(n, 2) = ctl.Name
n = n + 1
End If
Next
'~~> Sort the array
For i = 1 To cbCount
For j = i + 1 To cbCount
If CbArray(i, 1) < CbArray(j, 1) Then
tindex = CbArray(j, 1)
ctlname = CbArray(j, 2)
CbArray(j, 1) = CbArray(i, 1)
CbArray(j, 2) = CbArray(i, 2)
CbArray(i, 1) = tindex
CbArray(i, 2) = ctlname
End If
Next j
Next i
'~~> Loop through the checkboxes
For i = cbCount To 1 Step -1
With Controls(CbArray(i, 2))
Debug.Print .Name
'
'~~> Do what you want
'
End With
Next i
End Sub
Upvotes: 3
Reputation: 71157
For Each
isn't specified to guarantee an enumeration order. In all likelihood the controls are being enumerated in the order they were added to the Me.Controls
collection.
If you need a specific order, use a For
loop:
Dim checkboxNames As Variant
checkboxNames = Array("chkA", "chkB", "chkC", "chkD", "chkE", ...)
Dim current As Long, checkboxName As String, currentBox As MSForms.CheckBox
For current = LBound(checkboxNames) To UBound(checkboxNames)
checkboxName = checkboxNames(current)
Set currentBox = Me.Controls(checkboxName)
'work with the currentBox here
Next
Note that this also removes the need to iterate controls you're not interested in
Upvotes: 3