Error ending For/Next loop through CheckBoxes - vba

I have UserForm4 which contains CheckBox1...19 and also OptionButton1...3, along with TextBox1, CommandButton1, 2.
When OptionButton 1 = True I want to loop through all CheckBoxes and set each to True.
The error I get states "Cannot find object" and i = 21, n = 23. How are they getting that high, when I only have 19 CheckBoxes?
Thanks!
Private Sub OptionButton1_Click()
Dim ctrl As Control
Dim i As Integer
Dim n As Integer
n = 0
For Each ctrl In UserForm4.Controls
If TypeOf ctrl Is MSForms.CheckBox Then
n = n + 1
End If
Next ctrl
For i = 1 To n
If UserForm4.Controls("CheckBox" & i) = False Then
UserForm4.Controls("CheckBox" & i) = True
End If
Next i
End Sub

Did you create more than 19 initially and delete some? Each VBA object has a unique name. Doing this the way you are doing it is likely to cause all sorts of problems.
For example, if you create 10 CheckBoxes and delete 8 of them, the remaining two might be named Checkbox8 and Checkbox9. So your loop will not hit them at all.
Also, why not do something like the following:
Private Sub OptionButton1_Click()
Dim ctrl As Control
Dim i As Integer
Dim n As Integer
n = 0
For Each ctrl In UserForm4.Controls
'this will make your problem really obvious
debug.print ctrl.name
If TypeOf ctrl Is MSForms.CheckBox Then
ctrl.value = True
End If
Next ctrl
End Sub

Related

VBA Userform: Update Total value in a label with multiple inputs, when entries change, by using a class module

I have a userform with 120 textboxes (10 years x 12 months). Going across are the months, and at the end is the total.
This is repeated 10 times for the 10 years going downwards
I would like it so the total label is updated when the values for the corresponding years' months change.
Textboxes are labelled for each year and month. The first one is 'TextBox1_1', the second is 'TextBox1_2'. for the third year, and fifth month it is 'TextBox3_5' and so forth.
I have a module which is set up to calculate the totals:
Sub totalVal(i As Integer)
Dim arr(1 To 12) As Integer
Dim j As Integer
For j = 1 To 12
If Trim(Basic_Info_Setup.Controls("TextBox" & i & "_" & j).Value & vbNullString) = vbNullString Then
Else
arr(j) = Basic_Info_Setup.Controls("TextBox" & i & "_" & j).Value
End If
Next j
Basic_Info_Setup.Year1_Total.Caption = Application.WorksheetFunction.Sum(arr)
End Sub
The 'i' will be passed as the year and the rest can be calculated. However to use this would a change event in all 120 textboxes which is far from ideal, but not undoable.
I have read and understand this is possible with a class module.
This one which shows how to do it with textboxes (Here) and I also had a look at how this one (Here) albeit it confused me more than it helped.
What do I need to do to make this class module for me?
I currently have in the class module, which is called 'clsLabel'
Private WithEvents MyTextBox As MSForms.TextBox
Public Property Set Control(tb As MSForms.TextBox)
Set MyTextBox = tb
End Property
Private Sub MyTextBox_Change()
totalVal (1)
End Sub
and in the userform
Private Sub UserForm_Initialize()
Dim tbCollection As Collection
Dim ctrl As MSForms.Control
Dim obj As clsLabel
Set tbCollection = New Collection
For Each ctrl In Me.Controls
If TypeOf ctrl Is MSForms.TextBoxThen
Set obj = New clsLabel
Set obj.Control = ctrl
tbCollection.Add obj
End If
Next ctrl
Set obj = Nothing
End Sub
when things work I would be happy to change the passing 'i' integer to be dynamic, I just have it set at 1 for now to see if it works for a specific year
There are no errors.
EDIT: corrections to above code as it now works
thanks

Setting a VBA form object using a string

Hello,
I am trying to set up a form which is a calendar from which the user can select a date (by default the current month appears). The form consists of 42 command buttons (I have left the default name ie. CommandButton1) which I am setting the day number.
At the moment I have a long-winded section of code for each button (I used Excel to generate this rather than type it all out) which locks and hides the button if it is outside of the month in question which looks like this:
NewDate.CommandButton1.Caption = Format(DATlngFirstMonth - DATintDayNumFirst + DATintX, "dd")
If DATintX < DATintDayNumFirst Then
With NewDate.CommandButton1
.Locked = True
.Visible = DATbooShowExtraDays
.ForeColor = RGB(150, 150, 150)
End With
Else
With NewDate.CommandButton1
.Locked = False
.Visible = True
.ForeColor = RGB(0, 0, 0)
End With
End If
I know that I can refer to a command button by:
Dim objCommandButton As Object
Set objCommandButton = NewDate.CommandButton1
..which neatens the code up somewhat. But what I would like to do is refer to the command button as a string so I can loop through all 42, ie.
Dim n as integer
n = 1
Do Until n > 42
Set objCommandButton = NewDate.CommandButton & n
'Some operations
n = n + 1
Loop
Many thanks in advance for assistance.
You can loop through all controls of the form. Try
Sub LoopButtons()
Dim it As Object
For Each it In NewDate.Controls
Debug.Print it.Name
Next it
End Sub
Then you can put conditional expression (if ... then) in place of Debug.Print or whatever. For example
If Instr(it.Name, "CommandButton") Then
'do your code
end if
Here's code which iterates over ActiveX controls on active sheet:
Sub IterateOverActiveXControlsByName()
Dim x As Integer
Dim oleObjs As OLEObjects
Dim ctrl As MSForms.CommandButton
Set oleObjs = ActiveSheet.OLEObjects
For x = 1 To 10
Set ctrl = oleObjs("CommandButton" & x).Object
Next
End Sub

How to check if userform checkboxes were checked or not; which were dynamically created?

I have a userform with dynamic checkboxes(programmed)
Below is my code
Dim Rows As Integer
Dim toppart As Integer
Dim Opt As Variant
Dim x As Integer
On Error Resume Next
toppart = 20
UpdateRow = Application.WorksheetFunction.CountA(ActiveSheet.Range("C3:CU3"))
For x = 3 To UpdateRow
Set Opt = Te.Controls.Add("Forms.CheckBox.1", "CheckBox" & x, True)
Opt.Caption = ActiveSheet.Cells(x, "C").Value
Opt.Width = 70
Opt.Height = 18
Opt.Left = 18
Opt.Top = toppart
toppart = toppart + 20
Next
I know if the checkboxes were set via the controls my code will look something like this:
If (CheckBox1.Value = False) Or (CheckBox2.Value = False) Then
MsgBox "You must select alteast 2 checkboxes", vbCritical
But when the checkboxes are dynamically created I can't think of a efficient way to do it. Please any suggestions or Help is very much appreciated, thanks.
Untested, but you can probably loop the controls on your form, check if each is a checkbox, if it is, query it's .Value and tally the total number of checkboxes which are "checked. If that number is LTE 1, then you raise your warning/MsgBox:
Dim checked as Long
Dim ctrl as Object
For Each ctrl in Me.Controls
If TypeName(ctrl) = "CheckBox" Then
If ctrl.Value = True Then
checked = checked + 1
End If
End If
Next
If checked <= 1 Then
MsgBox "You must select alteast 2 checkboxes", vbCritical
Exit Sub
End If

How to loop through userform frames with variable object name

I am attempting to loop the a specific set of frames within each Multipage page in my VBA User_Form. However, it does not seem like I can use a variable object name with each frame control like I can with the pages.
I am getting an error
object doesn't support this property or method
at the following line
For Each cCont in Me.MultiPage1.Pages(PageName).Frames(DataFrame).Controls
My Code
Do While x <= Me.MultiPage1.Pages.Count
PageName = "Page" & CStr(x)
DataFrame = "DataFrame" & CStr(x)
For Each cCont In Me.MultiPage1.Pages(PageName).Frames(DataFrame).Controls
You actually can't iterate the way you would think you could.
First, you need to iterate through all Pages of your MultiPage1.
Second, loop through all Controls inside the current Page , and check if they are of type Frame, if they are you can iterate inside the Frame but the syntax is a little different (see in the code below).
Code
Option Explicit
Private Sub IterateIn_MultiPage()
Dim x As Long, j As Long
Dim cCont As Control
For x = 0 To Me.MultiPage1.Pages.Count - 1 ' <-- loop through all MultiPage Pages
For Each cCont In Me.MultiPage1.Pages(x).Controls ' <-- loop through controls of current page
If TypeOf cCont Is Frame Then ' <-- check if control type is Frame
For j = 0 To cCont.Controls.Count - 1 '<-- loop through all items related to the current Frame collection
MsgBox cCont.Controls(j).Name '<-- display a message box
Next j
End If
Next cCont
Next x
End Sub
Thanks for the help on putting together the code #Shai, for anyone else wondering what the final code looks like here it is. This loops through each frame within each multipage and pastes the caption of checked checkboxes in my desired range.
Option Explicit
Sub IterateIn_MultiPage()
Dim x As Long, j As Long
Dim cCont As Control
Dim counter As Integer
Dim y As Integer
Dim Range As String
y = 1
For x = 0 To ImportData.MultiPage1.Pages.Count - 1
counter = 0
For Each cCont In ImportData.MultiPage1.Pages(x).Controls
Do While counter < 1
If TypeOf cCont Is Frame Then
For j = 0 To cCont.Controls.Count - 1
If cCont.Controls(j).Value = True Then
Range = "E" & y
If counter = 0 Then
Worksheets("Calculations").Range(Range) = cCont.Controls(j).Caption
counter = counter + 1
ElseIf counter = 1 Then
Worksheets("Calculations").Range(Range) = Worksheets("Calculations").Range(Range) & " & " & cCont.Controls(j).Caption
y = y + 1
End If
End If
Next j
End If
Loop
Next cCont
Next x
End Sub

vba : why click event is diffused on initialising?

In excel, I have an userForm with checkBox dynamically created from a list
on initialize, I call a sub to affect a click event to my checkbox.
I have then a classmodule call MyEvents in wich I declare click event for check box.
Here is the class module MyEvents :
Option Explicit
Public WithEvents chkGroup As MSForms.CheckBox
Private Sub chkGroup_Click()
Debug.Print "chkGroup_Click -----> " & chkGroup.Caption
End Sub
Here is the sub on userForm :
Private Sub initCheckBox(chanelList As Variant)
Dim myEvent As MyEvents
Dim chkBox As Collection
Dim n As Long, j As Integer, i As Integer
n = Application.CountA(chanelList)
Dim checkBoxChanel() As MSForms.CheckBox
ReDim checkBoxChanel(n) As MSForms.CheckBox
n = 1
j = 1
i = 1
Set chkBox = New Collection
chkBoxNum = 0
For Each chanel In chanelList
Set myEvent = New MyEvents
Set checkBoxChanel(n) = Frame1.Controls.Add("Forms.CheckBox.1", "chkBoxChanel" & n)
Set myEvent.chkGroup = Frame1.Controls("chkBoxChanel" & n)
chkBox.Add myEvent
With checkBoxChanel(n)
.Top = j
.Left = i
.Caption = chanel
.AutoSize = True
.Value = True
.Enabled = False
End With
n = n + 1
i = i + 80
If n Mod 3 = 0 Then
j = j + 20
i = 1
End If
Next
End Sub
Can someone explain me why clickevent is diffused on initialising. Is it the normal behavior ?
okay, I've found the trick. Setting check box value to true is like clicking on check box ! to avoid this, I just have to affect event after setting value to true. Thanks to all for you comment and answers