Events on dynamic userform VBA - excel

I'm trying to assign event handlers on a dynamic userform in excel and let's just say that I can't find the answer, at least none I can get to work. I need Event handled on the checkbox...
Private Sub UserForm_Initialize()
Feuil1.Select
ThisWorkbook.Generate_Client_List
Dim i As Integer
i = 1
Dim topref As Integer
topref = 25
Dim imgFile1 As Object
Set imgFile1 = Client_picking.Controls.Add("Forms.Image.1")
With imgFile1
.Left = 140
.Height = 40
.Width = 40
.Picture = LoadPicture("C:\Users\Temp\Desktop\Project\excel.jpg")
End With
Dim imgFile As Object
Set imgFile = Client_picking.Controls.Add("Forms.Image.1")
With imgFile
.Left = 180
.Height = 40
.Width = 40
.Picture = LoadPicture("C:\Users\Temp\Desktop\Project\mail.jpg")
End With
Dim Label As Object
Set Label = Client_picking.Controls.Add("Forms.Label.1")
With Label
.Caption = "Clients"
.Left = 35
.top = topref - 15
.Width = 90:
.Height = 20
.Object.BackStyle = 0
End With
For Each distinctClientList In Feuil1.Range("DA3:DA10").Cells
Dim MaCheckBox As Object
Set MaCheckBox = Client_picking.Controls.Add("Forms.CheckBox.1")
With MaCheckBox
.Caption = "fichier"
.Left = 140
.top = topref + (20 * i)
End With
Dim MaCheckBoxmail As Object
Set MaCheckBoxmail = Client_picking.Controls.Add("Forms.CheckBox.1")
With MaCheckBoxmail
.Caption = "mail"
.Left = 180
.top = topref + (20 * i)
End With
Dim MaTextBox As Object
Set MaTextBox = Client_picking.Controls.Add("Forms.TextBox.1")
With MaTextBox
.Text = CStr(distinctClientList.Value)
.Left = 20
.top = topref + (20 * i)
.Width = 90:
.Height = 20
End With
i = i + 1
Next
Dim MyButton As Object
Set MyButton = Client_picking.Controls.Add("Forms.CommandButton.1")
With MyButton
.top = topref + (20 * i) + 20
.Left = 100
.Caption = "Ok"
End With
Client_picking.Height = topref + (20 * i) + 100
ThisWorkbook.Clear_Client_List
ClearToggleList
End Sub
The end result:

Related

Ambiguous Userform name

I create Userform
'Sub Crt_UserForm(ByVal count23 As Long, ByVal Temp As String, shts As Variant)
Dim myForm As Object
Dim Textbox1 As MSForms.TextBox
Dim Textbox2 As MSForms.TextBox
Dim Label1 As MSForms.Label
Dim Label2 As MSForms.Label
Dim Button1 As MSForms.CommandButton
Dim Button2 As MSForms.CommandButton
'Dim shtchk() As MSForms.CheckBox
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
'Set myForm = CallByName(UserForms, "Add", VbMethod, "Test")
ReDim shtchk(count23) As MSForms.CheckBox
With myForm
.Properties("Name") = "Test" 'Иногда эта строка вызывает ошибку
.Properties("Caption") = "Выберите листы для защиты паролем"
.Properties("Width") = 300
.Properties("Height") = 150
End With
'For Each x In Me.UserForms
'If x.Name = "Test" & a Then
'Next x
Set Label1 = Test.Controls.Add("Forms.Label.1", "Label1")
Set Label2 = Test.Controls.Add("Forms.Label.1", "Label2")
Set Textbox1 = Test.Controls.Add("Forms.Textbox.1", "Textbox1")
Set Textbox2 = Test.Controls.Add("Forms.Textbox.1", "Textbox2")
Set Button1 = Test.Controls.Add("Forms.CommandButton.1", "Button1")
Set Button2 = Test.Controls.Add("Forms.CommandButton.1", "Button2")
With Label1
.Top = 10
.Left = 10
.Width = 50
.Height = 20
.Caption = "Текущий пароль"
End With
With Label2
.Top = 10
.Left = 70
.Width = 50
.Height = 20
.Caption = "Новый пароль"
End With
With Textbox1
.Top = 40
.Left = 10
.Width = 50
.Height = 20
'.Caption = "Новый пароль"
End With
With Textbox2
.Top = 40
.Left = 70
.Width = 50
.Height = 20
'.Caption = "Новый пароль"
End With
With Button1
.Top = 70
.Left = 10
.Width = 50
.Height = 20
'.Caption = "Новый пароль"
End With
With Button2
.Top = 70
.Left = 70
.Width = 50
.Height = 20
'.Caption = "Новый пароль"
End With
Test.Show
End Sub
'
after the actions are over, I delete the created userform:
Sub RemoveUserForm()
With ThisWorkbook.VBProject.VBComponents
.Remove .item("Test")
End With
End Sub
First time it runs OK. But when I run it second time, it gives the error "Ambiguous name detected: Test" in the string:
Set Label1 = Test.Controls.Add("Forms.Label.1", "Label1")
So, somewhere deleted object myForm with the name "Test" is stored and prevents from creating the Userform object with the same name. How to fix it?
The solvation was in method of call to userform object via .Designer property Set Label1 = myForm.Designer.Controls.Add("Forms.Label.1", "Label1")
and method of userform show VBA.UserForms.Add(s).Show
Sub Crt_UserForm()
Dim myForm As Object
Dim s As String
Dim Textbox1 As MSForms.TextBox
Dim Textbox2 As MSForms.TextBox
Dim Label1 As MSForms.Label
Dim Label2 As MSForms.Label
Dim Button1 As MSForms.CommandButton
Dim Button2 As MSForms.CommandButton
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
With myForm
.Properties("Caption") = "Smth"
.Properties("Width") = 300
.Properties("Height") = 150
End With
s = myForm.Name
Set Label1 = myForm.Designer.Controls.Add("Forms.Label.1", "Label1")
Set Label2 = myForm.Designer.Controls.Add("Forms.Label.1", "Label2")
Set Textbox1 = myForm.Designer.Controls.Add("Forms.Textbox.1", "Textbox1")
Set Textbox2 = myForm.Designer.Controls.Add("Forms.Textbox.1", "Textbox2")
Set Button1 = myForm.Designer.Controls.Add("Forms.CommandButton.1", "Button1")
Set Button2 = myForm.Designer.Controls.Add("Forms.CommandButton.1", "Button2")
With Label1
.Top = 10
.Left = 10
.Width = 50
.Height = 20
.Caption = "SMTH"
End With
With Label2
.Top = 10
.Left = 70
.Width = 50
.Height = 20
.Caption = "SMTH"
End With
With Textbox1
.Top = 40
.Left = 10
.Width = 50
.Height = 20
End With
With Textbox2
.Top = 40
.Left = 70
.Width = 50
.Height = 20
'.Caption = "SMTH"
End With
With Button1
.Top = 70
.Left = 10
.Width = 50
.Height = 20
.Caption = "OK"
End With
With Button2
.Top = 70
.Left = 70
.Width = 50
.Height = 20
.Caption = "SMTH"
End With
With myForm.CodeModule
x = .CountOfLines
.InsertLines x + 1, "Sub Button1_Click()"
.InsertLines x + 2, "MsgBox ""Hello!"""
.InsertLines x + 3, "Unload Me"
.InsertLines x + 5, "End Sub"
End With
VBA.UserForms.Add(s).Show
ThisWorkbook.VBProject.VBComponents.Remove VBComponent:=myForm
End Sub

How to check if optionbutton is selected for the group and store the value of the selected button for additional calculation in VBA?

This is the first time I've done something this complicated in UserForms using VBA. I'm not sure if this is even the correct way to do this or not.
The layout of the form
The form as a MultiPage with 5 pages.
Each Page has 5 survey questions with 4 option buttons per question (Low, Medium, High, Don't know)
4 option buttons per question are grouped
Low option button should have a value of 1, Medium 3, and High 5. Don't know should be 0 but if more
Then values from these option buttons are averaged for each page. e.g. Page 1 has 5 questions, the user selects 1. Low, 2. Low, 3. Medium, 4. Don't know, 5. High. Then the average for this page should be 2. And this average is the only one I care about and needs to be save in a sheet range (which I can do later). I don't need to store other responses.
Because the pages in the Multipage can change in the future, I created a loop to create the page dynamically based on items added in the table in a separate sheet.
Also, because questions can be added or removed for each page, I also created the labels for the question and radio buttons using the loop.
What I don't know how to do next
The layout is complete and works. What I need to do now is the following:
Make the option buttons mandatory, i.e. the user must select one option button per group.
Get the value of the option buttons for each group and calculate the average for each page
I don't know yet how to get the value of the option button when it's used in the loop. I just learnt that VBA is an event driven program, so now I'm concerned whether I can salvage the time and effort I put in creating the form using loop the following way.
In this case, I also tried to create a dictionary, store the values. But I need to store this in a collection?
Private Sub CreateAssessmentForm()
'Range variable for data from table
Dim rngTable As Range
Dim itemTable As Range
'UI forms and multipage
'Dim multiPage As MSForms.multiPage
'Labels
Dim itemLblBackground As Object
Dim itemLbl As Object
Dim lowRatingLabelBg As Object
Dim medRatingLabelBg As Object
Dim highRatingLabelBg As Object
Dim unknownRatingLabelBg As Object
Dim lowRatingLabel As Object
Dim medRatingLabel As Object
Dim highRatingLabel As Object
Dim unknownRatingLabel As Object
'Misc
Dim lblName As String
Dim lblBackground As String
Dim JobGrade As Integer
Dim itemTopPosition As Integer
Dim altBgClr As Long
'Leader Role table ID to keep track of for the Multipage tabs
Dim activeLeaderRoleId As String
'Radio buttons
Dim lowRadioButton As MSForms.OptionButton
Dim medRadioButton As MSForms.OptionButton
Dim highRadioButton As MSForms.OptionButton
Dim unknownRadioButton As MSForms.OptionButton
Set RadioDictionary = New Dictionary
'================================================================
Me.drName = Sheets("var").Range("Y2").Value
'Declaration
JobGrade = Sheets("var").Range("z2").Value
Me.dateLabel.Caption = DateValue(Now)
Me.ManagerView_SubmitAssessment.Enabled = True
'Define source range, referring to the table data range
Set rngTable = ThisWorkbook.Worksheets("LeaderRoles2").Range("leaderRoleTable2")
Set itemTable = ThisWorkbook.Worksheets("Items").Range("itemTable")
'Create a tabbed multipage to add the leader role information
Set multiPage = AssessmentForm.DriverTabs
multiPage.Font.Bold = False
multiPage.Font.Name = "Verdana"
multiPage.Font.Size = 9
multiPage.Style = fmSpecialEffectFlat
multiPage.ForeColor = RGB(0, 40, 85)
'Total page counts that may already exist
PageCount = multiPage.Pages.Count
Dim itemLabelWidth As Integer
itemLabelWidth = 325
'rngTable rows have different count than rngTable.Count if multiple columns are selected
For i = 1 To rngTable.Rows.Count
itemTopPosition = (multiPage.Height - (32 * 5)) / 2
'get leader role id
activeLeaderRoleId = rngTable.Item(i, 1).Value
If (i <= PageCount) = True Then
multiPage.Pages(i - 1).Caption = rngTable.Item(i, 2).Value
Else
multiPage.Pages.Add
Me.DriverTabs.Pages(i - 1).Name = "Page" & i
Me.DriverTabs.Pages(i - 1).Caption = rngTable.Item(i, 2).Value
End If
'Tab height
multiPage.TabFixedHeight = 25
lblName = "lr" & i & "Item" & j
lblBackground = "lblBkgrnd" & i & j
'Multipage page background
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.BackColor = RGB(255, 255, 255)
.Width = multiPage.Width
.Height = multiPage.Height
.Top = 0
.Left = 0
End With
'For alternating the background in the item labels
Dim k As Integer
k = 1
'Loop through item table to add items to the multipage page
For j = 1 To itemTable.Rows.Count
If itemTable.Item(j, 2).Value = activeLeaderRoleId And itemTable.Item(j, 3) = JobGrade Then
Set itemLblBackground = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1", lblBackground)
Set itemLbl = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1", lblName)
altBgClr = RGB(250, 250, 250)
If (k Mod 2 = 0) Then altBgClr = RGB(255, 255, 255)
'Alternate background
With itemLblBackground
.Caption = ""
.BorderStyle = fmBorderStyleNone
.BackColor = altBgClr
.Left = 0
.Width = multiPage.Width
.Height = 35
.Top = itemTopPosition
End With
'display items
With itemLbl
.Caption = itemTable.Item(j, 4).Value
.BackStyle = fmBackStyleTransparent
.Font.Name = "Verdana"
.AutoSize = True
.Font.Size = 10
.Left = 6
.Width = itemLabelWidth
.Height = 30
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2) 'itemLblBackground.Top
End With
'==============================================================================================================
'
' LOW RADIO BUTTON
'
'==============================================================================================================
'Low radio button
Dim lowLabelName As String
Dim medLabelName As String
Dim highLabelName As String
Dim unknownLabelName As String
lowLabelName = "lowRadioGroup" & i & "_" & j
medLabelName = "medRadioGroup" & i & "_" & j
highLabelName = "highRadioGroup" & i & "_" & j
unknownLabelName = "unknownRadioGroup" & i & "_" & j
Set lowRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", lowLabelName)
With lowRadioButton
.Width = 20
.BackStyle = fmBackStyleTransparent
.Left = itemLabelWidth + 40
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = lowLabelName
RadioDictionary("GroupName") = lowRadioButton.GroupName
RadioDictionary("Value") = lowRadioButton.Value
'==============================================================================================================
'
' MEDIUM RADIO BUTTON
'
'==============================================================================================================
Set medRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", medLabelName)
With medRadioButton
.Width = 20
.BackStyle = fmBackStyleTransparent
.Left = lowRadioButton.Left + lowRadioButton.Width + 40
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = medLabelName
RadioDictionary("GroupName") = medRadioButton.GroupName
RadioDictionary("Value") = medRadioButton.Value
'==============================================================================================================
'
' HIGH RADIO BUTTON
'
'==============================================================================================================
Set highRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", highLabelName)
With highRadioButton
.Width = 20
.BackStyle = fmBackStyleTransparent
.Left = medRadioButton.Left + medRadioButton.Width + 40
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = highLabelName
RadioDictionary("GroupName") = highRadioButton.GroupName
RadioDictionary("Value") = highRadioButton.Value
'==============================================================================================================
'
' DON'T KNOW RADIO BUTTON
'
'==============================================================================================================
Set unknownRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", unknownLabelName)
With unknownRadioButton
.Width = 22
.BackStyle = fmBackStyleTransparent
.Left = highRadioButton.Left + highRadioButton.Width + 45
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = unknownLabelName
RadioDictionary("GroupName") = unknownRadioButton.GroupName
RadioDictionary("Value") = unknownRadioButton.Value
itemTopPosition = itemTopPosition + itemLblBackground.Height
k = k + 1
End If
Next j 'End item table range
'==============================================================================================================
'
' DISPLAY RATING OPTIONS AND LINE BOUNDARIES
'
'==============================================================================================================
'Adding a line in the headers
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = multiPage.Width - 10
.Height = 1
.Top = multiPage.TabFixedHeight + 16
.Left = multiPage.Left - 10
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = itemLabelWidth + 10
End With
'==============================================================================================================
'
' LOW
'
'==============================================================================================================
Set lowRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Low rating instruction background
With lowRatingLabelBg
.BackColor = RGB(244, 67, 54)
.Left = itemLabelWidth + 20
.Top = 12
.Width = 50
.Height = 25
End With
'Low rating instruction label
Set lowRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With lowRatingLabel
.Caption = "LOW"
.BackColor = RGB(244, 67, 54)
.Width = 24
.Height = 12
.Left = lowRatingLabelBg.Left + (lowRatingLabelBg.Width - lowRatingLabel.Width) / 2
.Top = lowRatingLabelBg.Top + (lowRatingLabelBg.Height - lowRatingLabel.Height) / 2
.ForeColor = RGB(255, 255, 255)
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = lowRatingLabelBg.Width + lowRatingLabelBg.Left + 5
End With
'==============================================================================================================
'
' MEDIUM
'
'==============================================================================================================
Set medRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Med rating instruction
With medRatingLabelBg
.BackColor = RGB(255, 193, 7)
.Left = lowRatingLabelBg.Left + lowRatingLabelBg.Width + 10
.Top = 12
.Width = 50
.Height = 25
End With
'Low rating instruction label
Set medRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With medRatingLabel
.Caption = "MEDIUM"
.BackStyle = fmBackStyleTransparent
.Width = 42
.Height = 12
.Left = medRatingLabelBg.Left + (medRatingLabelBg.Width - medRatingLabel.Width) / 2
.Top = medRatingLabelBg.Top + (medRatingLabelBg.Height - medRatingLabel.Height) / 2
.ForeColor = RGB(9, 9, 9)
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = medRatingLabelBg.Width + medRatingLabelBg.Left + 5
End With
'==============================================================================================================
'
' HIGH
'
'==============================================================================================================
Set highRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Med rating instruction
With highRatingLabelBg
.BackColor = RGB(46, 125, 50)
.Left = medRatingLabelBg.Left + medRatingLabelBg.Width + 10
.Top = 12
.Width = 50
.Height = 25
End With
Set highRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With highRatingLabel
.Caption = "HIGH"
.BackStyle = fmBackStyleTransparent
.Width = 26
.Height = 12
.Left = highRatingLabelBg.Left + (highRatingLabelBg.Width - highRatingLabel.Width) / 2
.Top = highRatingLabelBg.Top + (highRatingLabelBg.Height - highRatingLabel.Height) / 2
.ForeColor = RGB(255, 255, 255)
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = highRatingLabelBg.Width + highRatingLabelBg.Left + 5
End With
'==============================================================================================================
'
' Don't Know
'
'==============================================================================================================
Set unknownRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Dont know rating instruction
With unknownRatingLabelBg
.BackColor = RGB(148, 176, 182)
.Left = highRatingLabelBg.Left + highRatingLabelBg.Width + 10
.Top = 12
.Width = 65
.Height = 25
End With
Set unknownRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With unknownRatingLabel
.Caption = "DON'T KNOW"
.BackStyle = fmBackStyleTransparent
.Width = 80
.Height = 12
.Left = unknownRatingLabelBg.Left + 9 + (unknownRatingLabelBg.Width - unknownRatingLabel.Width) / 2
.Top = unknownRatingLabelBg.Top + (unknownRatingLabelBg.Height - unknownRatingLabel.Height) / 2
.ForeColor = RGB(255, 255, 255)
End With
Next i 'End leader role table range
'Finally, get the actual page count
PageCount = multiPage.Pages.Count
End Sub
In regards of what I tried to suggest (in comments) I prepared a simple event wrapper class, which must be built in this way:
Insert a class module, name it optBClass and paste the next code inside it:
Option Explicit
Public WithEvents optEvent As MSForms.OptionButton
Private Sub optEvent_Change()
If optEvent.Name = "Opt1" Then
If optEvent.Value = True Then
testOptCreate.boolOpt1 = True
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
Else
testOptCreate.boolOpt1 = False
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
End If
ElseIf optEvent.Name = "Opt2" Then
If optEvent.Value = True Then
testOptCreate.boolOpt2 = True
testOptCreate.boolOpt1 = False: testOptCreate.boolOpt3 = False
Else
testOptCreate.boolOpt1 = False
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
End If
ElseIf optEvent.Name = "Opt3" Then
If optEvent.Value = True Then
testOptCreate.boolOpt3 = True
testOptCreate.boolOpt1 = False: testOptCreate.boolOpt2 = False
Else
testOptCreate.boolOpt1 = False
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
End If
End If
MsgBox optEvent.Name & " - " & optEvent.Value & vbCrLf & _
"boolOpt1 = " & testOptCreate.boolOpt1 & vbCrLf & _
"boolOpt2 = " & testOptCreate.boolOpt2 & vbCrLf & _
"boolOpt3 = " & testOptCreate.boolOpt3
End Sub
On top of the the form (module) you want to create option buttons, on the fly (testOptCreate in my exammple), please create the next variable (in the declarations part):
Option Explicit
Private optBColl As New Collection
Private OptionB() As New optBClass
Public boolOpt1 As Boolean, boolOpt2 As Boolean, boolOpt3 As Boolean
Create a button (btCreateOptB) and use this code for its Click event:
Private Sub btCreateOptB_Click()
Dim optCount As Long, theOptB As control, i As Long
optCount = 3
ReDim OptionB(0 To optCount)
For i = 1 To optCount
Set theOptB = Me.Controls.aDD("Forms.OptionButton.1", "Opt" & i, True)
With theOptB
.height = 17
.Caption = "Opt" & i
.left = 50 * i
End With
optBColl.aDD theOptB, theOptB.Name
Set OptionB(i).optEvent = theOptB
Next i
End Sub
Show the form and press btCreateOptB button!
Check each newly created option buttons. When first of them is clicked, the message box being shown display the clicked option button name, its value and the boolean variables associated to the group values.
Starting from the second option button click, the message will be shown twice. One time triggered by the previous option button change (its value becomes false) and second time referring to the last option button clicked.
Please, try understanding of its logic and try to apply it on your project.
If something not clear, do not hesitate to ask, even if I believe that it should be clear enough...
You can also use a Dictionary to automatically create boolean variables and use it to keep all of them and check when needed. Look, please at this test Sub:
Sub testDictionaryBooleanVar()
'it needs a reference to 'Microsoft Scripting Runtime`,
'or `dict` variable must be created `As Object` and create through `Set dict = CreateObject("scripting.dictionary")`
Dim it As Variant, dict As New Scripting.Dictionary, i As Long
With dict
For i = 1 To 10
.Item("boolOpt" & i) = False
Next i
End With
dict.Item("boolOpt2") = True: dict.Item("boolOpt5") = True
Debug.Print Join(dict.Items, "|")
Debug.Print dict("boolOpt2"), dict("boolOpt3")
End Sub
Presented this option in order to suggest a way to avoid manually creating boolean variables to be checked in the Option button Change event...

wire up events for dynamically created controls in frames in vba userform

I am new here and I am struggling with VBA, especially the userform.
I want to create a userform that allows to check if everyone is present or not in a list of people.
The list of people can vary every day, so I made the choice to create a dynamic userform. I ask Excel to go to get the number of people in my list then I create a userform with all the names of these people and 2 optionbuttons at each line "here" or "absent".
My problem is this:
my optionbuttons have been created in a FOR loop so they have the following names: "here" & i or "absent" & i (with i from 1 to the number of people on my list)
Now I wish I could create a code when you click on these buttons to update an excel sheet. Something like "Private sub here&i_click() ...."
But I don't know ow many buttons I have and the value of i is not changing anymore since we are out of the FOR loop.
Can someone help me with that?
Thank you
Here is my code. When the userform rosterfill is shown I would like the different frames acting like that:
for i= 6 to lastrowd
If here & i is clicked then frame3 & i is visible
If absent & i is clicked then frame2 & i is visible
if none is clicked then msgbox ("select here/absent for everyone")
Next
For sure I understand it cannot be done with this kind of loop but I can't find any example online with my situation...
-- VBA CODE---
Workbooks.Open (pathroot & "\" & dpt & "\Roster")
Worksheets("Shift " & shi).Activate
lastrowd = Cells(Rows.Count, 1).End(xlUp).Row
topini = 18
initop = 18
For i = 6 To lastrowd
Set thelabel = rosterfill.Controls.Add("Forms.TextBox.1", "label" & i, True)
With thelabel
.Value = Cells(i, 1).Value 'name of the person
.Left = 6
.Width = 234
.Top = topini + 30
.Locked = True
.Height = 24
End With
Set theframe = rosterfill.Controls.Add("Forms.Frame.1", "frame" & i, True)
With theframe
.Top = initop + 30
.Width = 100
.Left = 246
.Height = 24
Set here = .Controls.Add("forms.OptionButton.1", "here" & i, True)
With here
.Height = 18
.Left = 5
.Width = 108
.Caption = "here"
End With
Set absent = .Controls.Add("forms.OptionButton.1", "absent" & i, True)
With absent
.Height = 18
.Left = 50
.Width = 108
.Caption = "absent"
End With
End With
Set theframe2 = rosterfill.Controls.Add("Forms.Frame.1", "frame2" & i, False)
With theframe2
.Top = initop + 30
.Width = 350
.Left = 350
.Height = 24
Set abs1 = .Controls.Add("forms.OptionButton.1", "abs1" & i, True)
With abs1
.Height = 18
.Left = 5
.Width = 108
.Caption = "PTO"
End With
Set abs2 = .Controls.Add("forms.OptionButton.1", "abs2" & i, True)
With abs2
.Height = 18
.Left = 50
.Width = 108
.Caption = "UPTO"
End With
Set abs3 = .Controls.Add("forms.OptionButton.1", "abs3" & i, True)
With abs3
.Height = 18
.Left = 95
.Width = 108
.Caption = "MED"
End With
Set abs4 = .Controls.Add("forms.OptionButton.1", "abs4" & i, True)
With abs4
.Height = 18
.Left = 140
.Width = 108
.Caption = "ANCI"
End With
Set abs5 = .Controls.Add("forms.OptionButton.1", "abs5" & i, True)
With abs5
.Height = 18
.Left = 185
.Width = 108
.Caption = "FMLA"
End With
Set abs6 = .Controls.Add("forms.OptionButton.1", "abs6" & i, True)
With abs6
.Height = 18
.Left = 230
.Width = 108
.Caption = "AE"
End With
Set abs7 = .Controls.Add("forms.OptionButton.1", "abs7" & i, True)
With abs7
.Height = 18
.Left = 260
.Width = 108
.Caption = "S"
End With
Set abs8 = .Controls.Add("forms.OptionButton.1", "abs8" & i, True)
With abs8
.Height = 18
.Left = 285
.Width = 108
.Caption = "BRV"
End With
Set abs9 = .Controls.Add("forms.OptionButton.1", "abs9" & i, True)
With abs9
.Height = 18
.Left = 320
.Width = 108
.Caption = "JD"
End With
End With
Set hours = rosterfill.Controls.Add("forms.TextBox.1", "hours" & i, False)
With hours
.Left = 700
.Width = 50
.Top = topini + 30
.Height = 24
End With
Set Comment = rosterfill.Controls.Add("forms.TextBox.1", "comment" & i, False)
With Comment
.Left = 755
.Width = 100
.Top = topini + 30
.Height = 24
End With
Set theframe3 = rosterfill.Controls.Add("Forms.Frame.1", "frame3" & i, False)
With theframe3
.Top = initop + 30
.Width = 350
.Left = 350
.Height = 24
Set here1 = .Controls.Add("forms.OptionButton.1", "here1" & i, True)
With here1
.Height = 18
.Left = 5
.Width = 108
.Caption = "LE"
End With
Set here2 = .Controls.Add("forms.OptionButton.1", "here2" & i, True)
With here2
.Height = 18
.Left = 50
.Width = 108
.Caption = "AL"
End With
Set here3 = .Controls.Add("forms.OptionButton.1", "here3" & i, True)
With here3
.Height = 18
.Left = 95
.Width = 108
.Caption = "Entire Shift"
End With
End With
topini = topini + 30
initop = initop + 30
Next i
If topini + 100 > 450 Then
rosterfill.Height = 450
rosterfill.CommandButton1.Top = topini + 100 - 60
rosterfill.CommandButton2.Top = topini + 100 - 60
rosterfill.ScrollBars = fmScrollBarsVertical
rosterfill.ScrollHeight = topini + 100
rosterfill.ScrollWidth = 50
rosterfill.ScrollTop = 0
Else
rosterfill.Height = topini + 100
rosterfill.CommandButton1.Top = topini + 100 - 60
rosterfill.CommandButton2.Top = topini + 100 - 60
End If
rosterfill.Show

Use the SpinButton_change() event where there is an unknown number of spin buttons

I have a userform with various checkboxes. Each checkbox when selected opens up a new userform with a new set of checkbox, textbox and spinbutton controls based on a column in a worksheet. This column will change and thus there will be a new number of checkboxes, textbox and spinbutton controls every time the macro runs.
I need to use the spinbutton_change() event to set the value of the textbox. Since I don't know the number of spinbuttons that will exist at a given time how can I code this so each spinbutton updates its respective textbox?
Private Sub UserForm_Activate()
Dim NewChkBx As MSForms.CheckBox
Dim NewTxtBx As MSForms.TextBox
Dim NewSpinButton As MSForms.SpinButton
Dim rngSource As Range
Dim rngCell As Range
Dim TopPos As Integer
Dim MaxWidth As Long
Sheets("Background").UsedRange.ClearContents
'Filters items in Col A which Equal "Light"
Application.ScreenUpdating = False
Worksheets("Weight_Data").Unprotect
Worksheets("Background").[a1].CurrentRegion.Offset(1).ClearContents
Worksheets("Weight_Data").Range("D1:D1000").AutoFilter 1, "Light"
Worksheets("Weight_Data").Range("A2:H1000").Copy (Worksheets("Background").Range("A65536").End(xlUp)(2))
Worksheets("Weight_Data").Range("A1").AutoFilter 'Turn Filter Off
' End of filter
' Start of creating new userform based only on checked boxes.
With Worksheets("Background")
Set rngSource = Worksheets("Background").Range("B2", .Cells(.Rows.Count, "B").End(xlUp))
End With
TopPos = 5
MaxWidth = 0
For Each rngCell In rngSource
If rngCell.Value <> "" Then
Set NewChkBx = Me.Controls.Add("Forms.CheckBox.1")
Set NewTxtBox = Me.Controls.Add("Forms.Textbox.1")
Set NewSpinButton = Me.Controls.Add("Forms.Spinbutton.1")
With NewChkBx
.Caption = rngCell.Value
.Left = 5
.Top = TopPos
.AutoSize = True
If .width > MaxWidth Then MaxWidth = .width
End With
With NewTxtBox
.Enabled = True
.Value = 0
.Enabled = False
.Text = 0
.Height = 15
.width = 20
.Left = NewChkBx.width + 20
.Top = TopPos
.AutoSize = True
If .width > MaxWidth Then MaxWidth = .width
End With
With NewSpinButton
.Value = 0
.Height = 15
.width = 10
.Left = NewTxtBox.width + NewChkBx.width + 20
.Top = TopPos
If .width > MaxWidth Then MaxWidth = .width
End With
TopPos = TopPos + 60
End If
Next rngCell
Me.width = MaxWidth + 60
Me.Height = TopPos + 25
' Worksheets("Weight_Data").Protect
Application.ScreenUpdating = True
Sheets("Background").UsedRange.ClearContents
End Sub
Here's a slightly-simplified version of your code which has some dynamic event capture built in.
Userform:
Option Explicit
Dim col As Collection '<<< needs to be global
Private Sub UserForm_Activate()
Dim x As Long, TopPos As Long, MaxWidth As Long
Dim NewChkBx As MSForms.CheckBox
Dim NewTxtBox As MSForms.TextBox
Dim NewSpinButton As MSForms.SpinButton
Set col = New Collection
TopPos = 5
MaxWidth = 0
For x = 1 To 10
Set NewChkBx = Me.Controls.Add("Forms.CheckBox.1")
Set NewTxtBox = Me.Controls.Add("Forms.Textbox.1")
Set NewSpinButton = Me.Controls.Add("Forms.Spinbutton.1")
With NewChkBx
.Caption = "Number " & x
.Left = 5
.top = TopPos
.AutoSize = True
If .Width > MaxWidth Then MaxWidth = .Width
End With
With NewTxtBox
.Enabled = True
.Value = 0
.Enabled = False
.Text = 0
.Height = 15
.Width = 20
.Left = NewChkBx.Width + 20
.top = TopPos
.AutoSize = True
If .Width > MaxWidth Then MaxWidth = .Width
End With
With NewSpinButton
.Value = 0
.Height = 15
.Width = 10
.Left = NewTxtBox.Width + NewChkBx.Width + 20
.top = TopPos
If .Width > MaxWidth Then MaxWidth = .Width
End With
col.Add CaptureEvents(NewSpinButton, NewTxtBox) '<<< save new class instance
TopPos = TopPos + 20
Next x
Me.Width = MaxWidth + 60
Me.Height = TopPos + 25
End Sub
'Return a new instance of clsEvents with controls added....
Private Function CaptureEvents(spn As MSForms.SpinButton, txt As MSForms.TextBox)
Dim rv As New clsEvents
Set rv.spn = spn
Set rv.tb = txt
Set CaptureEvents = rv
End Function
Class module "clsEvents":
Option Explicit
Public WithEvents spn As MSForms.SpinButton
Public tb As MSForms.TextBox
Private Sub spn_Change()
Me.tb.Text = spn.Value
End Sub

Excel VBA - Can't refer to objects/can't drop the info into sheet

I have some problems with an interface I'm making. I'm new to this and after a lot of search, I finally gave up and came here to ask.
First of all I made my code do this:
Open a userform from a button on a sheet.
After the userform is open, it has some default fields (some textboxes, a label and a commandbutton).
Then you have a commandbutton that creates a new round of fields and assign them a class to execute some simple code (numerical restriction for some textboxes and create a new textbox with content for the button).
My problem is the following :
I tried to assign ControlSource to the fields but Excel doesnt allow me to, and the only time it allowed me to, the fields didn't update the cell nor the cell updated the field.
I also tried to load the value from the newly created field directly into the sheet but I don't know how to call the object and get its properties.
Here is the code I'm using :
Option Explicit
Dim cargarconcepto() As New Clase3
Private Sub CommandButton19_Click()
Dim txtCtl As Control
Dim concepto As Object
Dim i As Long
i = labelcounter
controlextra = controlextra + 1
Dim Label As Object
Dim lblctr As Long
Dim nmctr As Long
Dim t1 As Object
Dim t2 As Control
Dim t3 As Control
Dim t4 As Control
Dim t5 As Object
Dim t6 As Object
Dim cargaconcepto As Control
UserForm1.Frame21.ScrollHeight = 80 + (25 * controlextra) - 25
UserForm1.Frame21.ScrollTop = UserForm1.Frame21.ScrollHeight
nmctr = labelcounter + 1
For lblctr = labelcounter To controlextra
Set Label = UserForm1.Frame21.Controls.Add("Forms.Label.1", "Labelt" & labelcounter, True)
With Label
.Caption = "0005 - "
.Left = 3
.Height = 12
.Width = 24
.Top = 25 + (25 * labelcounter)
End With
Set t1 = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "t" & labelcounter + 1 & "1", True)
With t1
.value = Workbooks("A Facturar Proyecto tarjetas.xlsm").Sheets("Data").Range("as1").value
.Left = 31
.TextAlign = fmTextAlignCenter
.Enabled = False
.Height = 15.75
.Width = 54
.Top = 25 + (25 * labelcounter)
End With
Set t2 = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "t" & labelcounter + 1 & "2", False)
With t2
.value = ""
.Left = 97
.Height = 15.75
.Width = 90
.Top = 25 + (25 * labelcounter)
.Visible = True
End With
Set t3 = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "t" & labelcounter + 1 & "3", False)
With t3
.value = ""
.Left = 199
.Height = 15.75
.Width = 90
.Top = 25 + (25 * labelcounter)
.Visible = True
End With
Set t4 = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "t" & labelcounter + 1 & "4", False)
With t4
.value = ""
.Left = 307
.Height = 15.75
.Width = 90
.Top = 25 + (25 * labelcounter)
.Visible = True
End With
Set t5 = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "t" & labelcounter + 1 & "5", True)
With t5
.value = ""
.Left = 415
.Height = 15.75
.Width = 90
.Top = 25 + (25 * labelcounter)
End With
Set t6 = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "t" & labelcounter + 1 & "6", True)
With t6
.value = ""
.Left = 517
.Height = 15.75
.Width = 90
.Top = 25 + (25 * labelcounter)
End With
Set concepto = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "concepto" & labelcounter + 1, False)
With concepto
.value = ""
.BackStyle = fmBackStyleTransparent
.Left = 619
.Height = 20
.Width = 210
.Top = 25 + (25 * labelcounter)
.Enabled = False
.value = Workbooks("A Facturar Proyecto tarjetas").Sheets("Data").Range("Ac45")
.Visible = True
End With
Set cargaconcepto = UserForm1.Frame21.Controls.Add("forms.commandbutton.1", "Cargar Concepto" & labelcounter + 1, False)
With cargaconcepto
.Caption = "Cargar Concepto"
.Left = 834
.Height = 20
.Width = 90
.Top = 25 + (25 * labelcounter)
.Tag = labelcounter + 1
.Visible = True
End With
ReDim Preserve num(1 To i)
Set num(i).txtCtrl = t2
ReDim Preserve num2(1 To i)
Set num2(i).txtCtrl = t3
ReDim Preserve num3(1 To i)
Set num3(i).txtCtrl = t4
ReDim Preserve cargarconcepto(1 To i)
Set cargarconcepto(i).cargar = cargaconcepto
Set cargaconcepto = Nothing
Set t3 = Nothing
Set t4 = Nothing
Set t2 = Nothing
labelcounter = labelcounter + 1
Next
End Sub
And then here is the class:
Option Explicit
Public WithEvents cargar As MSForms.CommandButton
Private Sub cargar_Click()
Dim concepto As Control
Set concepto = UserForm1.Frame21.Controls.Add("Forms.TextBox.1", "concepto" & labelcounter + 1, True)
With concepto
.value = ""
.BackStyle = fmBackStyleTransparent
.Left = 619
.Height = 20
.Width = 210
.Top = (25 * b)
.Enabled = False
.value = Workbooks("A Facturar Proyecto tarjetas").Sheets("Data").Range("Ac45")
End With
End Sub
I tried to use something like UserForm1.Frame21.concepto & cargar.Tag to get the name of the newly created field and therefore replace its value for a new one AND to load that value into the sheet.
But I just cant find a way to do it. Now I have an almost complete interface for data entry but I cant drop the data into the spreadsheet.
Please I need help!

Resources