Adding OptionButtons to the Userform programatically in VBA Excel - vba

I am very new to VBA programming.
My scenario is I will get a list of String values I need these values to be displayed to the user using radio buttons on a small window so that whenever the user selects any value by clicking on the radio button I should be able to get that value in the VBA code. I searched for adding options button in the user form in the internet I got some solution which use GUI method of creating option buttons. But I need it done through program. I found a helpful thread in stackoverflow (How can I dynamically add a radio button on a form using VBA ) I used this but still I am unable to get any label or button on the user form, a plain userform will be displayed. So anybody please give information regarding this.
The code is :
Sub Button1_Click()
lResult As Variant ' this is a array which contains string vaues to be dispayed as radio button.
' Some operatin is done here to get the list of values in lResult
Dim rad As Variant
Set rad = UserForm1.Controls.Add("Forms.OptionButton.1", "radioFoo", True)
rad.Caption = "bar"
rad.Left = 10
rad.Width = 10
rad.Top = 10
End Sub
UserForm1 is the userform which I created using Insert option in VBA menu bar.
I tried to add a single button on the userform. I did not use initialize function on userform. There is button on excel sheet Button1 I am calling this function on clicking that button.
Thank you

If you have a form named UserForm1 that contains a button named CommandButton1
You can set the Initialize method for your UserForm to programmatically create a group of radio buttons
Private Sub UserForm_Initialize()
Dim OptionList(1 To 3) As String
Dim btn As CommandButton
Set btn = UserForm1.CommandButton1
Dim opt As Control
Dim s As Variant
Dim i As Integer
OptionList(1) = "Option 1"
OptionList(2) = "Option 2"
OptionList(3) = "Option 3"
For Each s In OptionList
Set opt = UserForm1.Controls.Add("Forms.OptionButton.1", "radioBtn" & i, True)
opt.Caption = s
opt.Top = opt.Height * i
opt.GroupName = "Options"
UserForm1.Width = opt.Width
UserForm1.Height = opt.Height * (i + 2)
i = i + 1
Next
btn.Caption = "Submit"
btn.Top = UserForm1.Height - btn.Height + (0.5 * opt.Height)
btn.Left = (UserForm1.Width * 0.5) - (btn.Width * 0.5)
UserForm1.Height = UserForm1.Height + btn.Height + (0.5 * opt.Height)
End Sub
Private Sub CommandButton1_Click()
Dim i As Integer
For i = 0 To UserForm1.Controls.Count - 1
If UserForm1.Controls(i) Then
SelectedOption = UserForm1.Controls(i).Caption
End If
Next
UserForm1.Hide
End Sub
If you want to pull your list from a sheet you can change
Dim OptionList(1 To 3) As String
OptionList(1) = "Option 1"
OptionList(2) = "Option 2"
OptionList(3) = "Option 3"
to pull from a range like this
Dim OptionList() as Variant
OptionList = Range("A1:A3")
In your "button_onclick()" procedure stored in a module add this code:
'This is set by the code in UserForm1
Public SelectedOption As String
Sub Button1_OnClick()
UserForm1.Show
MsgBox SelectedOption
End Sub
Which gets you this result:
And when you click submit a message box will pop up showing you which option was selected

Remember in using option buttons, your option buttons need to share the same GroupName.
Your control Name is only there for you to refer it back for changing/reading.
Your Caption is a string that appear on your userform to the users.
Your GroupName is a string that allows Excel to recognize the option buttons are linked together.
So, if opt1's GroupName is "1" while opt2's GroupName is "2", then you will be able to select both since they are in different Groups.
Private Sub UserForm_Initialize()
Dim opt1 As Control, opt2 As Control
Set opt1 = UserForm1.Controls.Add("Forms.OptionButton.1", , True)
With opt1
.Name = "radioFoo"
.GroupName = "1"
.Caption = "Option 1"
End With
Set opt2 = UserForm1.Controls.Add("Forms.OptionButton.1", , True)
With opt2
.Name = "radioFoo2"
.GroupName = "1"
.Caption = "Option 2"
.Left = 100
End With
End Sub
EDIT:
From seeing your edited post and your comment...
No, you don't need to have UserForm_Initialize() method.
It is an Excel-VBA functionality called Event.
What it's used for is specifying the userform to do something when userform is initialized (first started).
Similarly from your code, Button1_Click() is an event as well.
Since you are telling Excel to do the following at the event where Button1 is clicked by the user...
Anyways, let me briefly explain to you what option buttons do.
A group of option buttons forces the user to select only one option out of options given by the program.
And an option button in VBA only allows you to create one option. So, if you want to create 2 options, you must create 2 option buttons.
But there is just one problem: what if you want to create 2 groups of option buttons so that the user can select 2 separate options? For example, food and drinks?
VBA presents us a property of an option button called GroupName. GroupName allows VBA to distinguish between separate groups of option buttons.
Therefore, in every option button you create, it is essential that you initialize its GroupName value. If you see any implementation of option button without GroupName, you are playing with fire.
So, let's finally take a look at your code:
Sub Button1_Click()
' Some operatin is done here to get the list of values in lResult
Dim rad1 As Control, rad2 As Control
Set rad1 = UserForm1.Controls.Add("Forms.OptionButton.1", "radioFoo1", True)
rad1.Caption = "bar"
rad1.Left = 10
rad1.Width = 10
rad1.Top = 10
rad1.GroupName = "Group1"
Set rad2 = UserForm1.Controls.Add("Forms.OptionButton.1", "radioFoo2", True)
rad2.Caption = "foo"
rad2.Left = 10
rad2.Width = 10
rad2.Top = 50
rad2.GroupName = "Group1"
End Sub
Just one thing:
- As I've implicitly mentioned before, an option button with only one option does not mean anything. If you are looking for on/off kind of functionality, you might as well go with checkbox. So, I've created another option button defining it to be in the same group as the first option button you've created (rad1).
Hope it helps.
Cheers,
kpark
Be sure to select the best answer when the question/problem has been answered/solved.
Thanks.

Related

is there a way of changing the Font properties of a text box in access VBA on a continuous form?

I am writing an app that send reports to a word document, this is done by the usage of data that is displayed on a continuous form, one form has the data that display's the selected headers that will be printed onto the report, the user can then change the font style by the usage of the windows font window.
This all works fine, what I want to do now is then update the text box on the continuous form with the font styles that have been stored in the data table, so that the user can see the font and style they have selected.
I have tried various approaches to no success, the last method I have tried I will post below in code.
dim i as integer
Private Sub Form_Load()
i = 0
End Sub
Private Sub Form_Current()
i = i + 1
Me.txtchapterName.Tag = "ctrl" & i
End sub
Function SetFieldProperties()
Dim rst As Recordset
Dim ctrl As TextBox
Set rst = Me.Recordset
Set ctrl = Me.ActiveControl
If rst.RecordCount > 0 Then
If ctrl.Tag = Me.txtchapterName.Tag Then
ctrl.ForeColor = Nz(Me![TextFontColour], 0)
ctrl.FontName = Nz(Me![TextFontName], "Calibri")
ctrl.FontSize = Nz(Me![TextFontSize], 14)
ctrl.FontUnderline = Nz(Me![TextFontAlign], 0)
ctrl.FontBold = Nz(Me![TextFontBold], False)
End If
End If
End Function
Private Sub txtchapterName_AfterUpdate()
SetFieldProperties
End Sub
To some extent this works, but it will update all of the controls on the form with the font style.
For clarity my question is in the title of the post...
Thank you all in advance.
Mark.

Create ComboBox's and AddItems to them all within the VBA code

I need to create ComboBox's and then AddItems to each ComboBox. This will all be done to a userform. I need to do this entirely within the VBA code, this is because each time the userform is opened new information will be shown.
this is what I have so far:
Private Sub UserForm_Initialize()
for i = 1 to size
Set CmbBX = Me.Controls.Add("Forms.ComboBox.1")
CmbBX.Top = ((90 * i) - 18) + 12 + 20
CmbBX.Left = 30
CmbBX.Text = "Please select an item from the drop down"
CmbBX.TextAlign = fmTextAlignCenter
CmbBX.Width = 324
CmbBX.Visible = False
CmbBX.Name = "ComBox2" & i
Next
end sub
the problem is, once each ComboBox is created its like its name isnt there. I cannot referance the combobox. this is what I have tried:
ComBox21.AddItems "Test1"
ComBox22.AddItems "Test2"
And it errors out. When I look at the UserForms function bar at the top of the screen (where I would usually select ComBox22_Change() for example), It shows that no ComboBoxes even exist!
Any Ideas on how to dynamically create and additems to comboboxes?
Thank you in advance
Here an sample of the code.
You need still to change it for you needs but this will be easy.
I have created a simple userform and one button to do test and it works fast.
To imput the comboboxes replace ".additem" with a loop to load each of them.
How to do that -- search in google
how to Populate a combobox with vba
You cannot refferance any controls on userform if they dont exist.
You need to search for them after creation and then modify them.
Example below with button code.
I think this should bring you to an idea how to manage this.
Option Explicit
Private Sub CommandButton1_Click()
Dim refControl As Control, frm As UserForm
Dim x
Set frm = Me
With Me
For Each x In Me.Controls
If TypeName(x) = "ComboBox" Then
Select Case x.Name
Case "cmbDemo3"
MsgBox "works!"
'here you can put your code
End Select
MsgBox x.Name
End If
Next x
End With
End Sub
Private Sub UserForm_Initialize()
Dim combobox_Control As Control
Dim i
For i = 0 To 5
Set combobox_Control = Controls.Add("forms.combobox.1")
With combobox_Control
.Name = "cmbDemo" & i
.Height = 20
.Width = 50
.Left = 10
.Top = 10 * i * 2
.AddItem "hihi" 'here you can add your input code
End With
Next i
End Sub

How to tell which dynamic control sent to an event?

This is my first attempt at working with dynamically created controls in a user form. The reason is there will always be a different amount of rows returned by some processing.
I have created a class object cControlEvent with the following code. (I cut out the code not pertaining to the checkbox)
Public WithEvents CHK As MSForms.CheckBox
Private Sub CHK_Change()
** tell me which box was changed **
End Sub
in the code module, I have the following code:
Dim CHK_Evts As New Collection
sub Form_Builder()
**non relevant code deleted****
Set Evt = New cControlEvent
If i_Columns = 1 Then
Set Evt.CHK = ctl
CHK_Evts.Add Evt
Else
** more code**
End if
end sub
What do I need to change/add to be able to get the name of the control that is firing off the change event?
EDITED TO ADD:
I have a series of dynamically created checkboxes and textboxes on each line of a user form, with a checkbox before each line, when the checkbox is checked/unchecked, I need to change the backcolor on all the textboxes in that row. Each control is named by it's type, then row then column like this CHX_1_1 would be a checkbox on row 1 column 1, and TXT_1_5 would be row 1 column 5. So, if I know what the name of the checkbox is, I have all I need to change the other controls on that row with a simple for-next loop.
I am not quite sure if I understand your question correctly. But it seems to me that it boils down to "which FormControl (linked to a particular procedure) caused this sub to run". If that's the case then you should be able to make use of the
Application.Caller
Here is a short video to demonstrate it's use in a very simple environment:
Here's hopefully a full solution showing how to get the properties from the check boxes:
Create a blank userform and add a command button to it.
Add this code to the form (note - CommandButton1_Click should be updated to the name of the button you added).
Public CHK_Evts As New Collection
Private Sub CommandButton1_Click()
Dim ChkBox As Variant
For Each ChkBox In CHK_Evts
MsgBox ChkBox.Position & vbCr & _
ChkBox.Status
Next ChkBox
End Sub
Private Sub UserForm_Initialize()
Dim tmpCtrl As Control
Dim cmbEvent As clsControlEvents
Dim X As Long
For X = 1 To 10
Set tmpCtrl = frmNameParser.Controls.Add("Forms.Checkbox.1", "Name" & X)
With tmpCtrl
.Left = 6
.Top = X * 20 + 24
.Height = 18
.Width = 150
End With
Set cmbEvent = New clsControlEvents
Set cmbEvent.CHK = tmpCtrl
CHK_Evts.Add cmbEvent, "Name" & X
Next X
End Sub
Create a class called clsControlEvents and add this code:
Public WithEvents CHK As MSForms.CheckBox
Public Property Get Position() As String
Position = CHK.Top
End Property
Public Property Get Status() As String
Status = CHK.Value
End Property
Private Sub CHK_Click()
MsgBox CHK.Name
End Sub
The two GET procedures pass information back to the CommandButton1_Click procedure so it can list information about all check boxes on the form (held in the CHK_EVTS collection).
The CHK_Click procedure gives immediate information about the check box being clicked.
http://www.cpearson.com/excel/classes.aspx

Populating a dropdown box with already-existing options in VBA?

I'm making an add records form for a spreadsheet of mine, and let's say that I want one of the controls to be a dropdown that is populated by unique entries under a certain column "type". However, I want to also make it such that the dropbox always has a initial option to "add new type" and upon such selection, it becomes a regular text box. How would I do this in VBA?
You cannot change a control type at run time. The easiest thing to do is create a combo box and a text box. Set the text box visibility to false. Then in the onchange event of the combo box your code will unhide the text box and hide the combo box. You will also need a save button so that when it is clicked it will add the option to the drop down, clear the text box, hide the text box, hide the button and unhide the drop down.
Okay, so here's my idea of how to tackle this.
Create 2 hidden elements (Visibility = False), one a TextBox and one a CommandButton.
Populate your ComboBox with the values from the sheet under column "type"
Add one more entry AddItem with wording such as "Add new item..."
When the user selects "Add new item...", change the Visibility of the TextBox & CommandButtons to True
When the user clicks the CommandButton, add the phrase to the column and add a new element to the ComboBox
I have created a mockup UserForm and code that does a little more than just this; it also styles the user entry to sentence case (consistency purposes) and checks to make sure the value isn't already in the column.
Excel Sheet with "type" column
UserForm with name labels
UserForm Code
Private Sub bAdd_Click()
Dim str As String
Dim rng As Range
Dim ro As Integer
'Makes sure there is an entry, adds it to the Sheet and then updates the dropdown
If Len(Me.tbNew) > 0 Then
'Converts user entry to "Sentance Case" for better readability
str = StrConv(Me.tbNew, vbProperCase)
'Finds out if the entry already exists
Set rng = Sheets(1).Range(Sheets(1).Cells(2, 1), Sheets(1).Cells(Sheets(1).Cells(Sheets(1).Rows.Count, 1).End(xlUp).Row, 1))
On Error Resume Next
Err.Number = 0
'Searches for duplicate; if found, then ListIndex of cbColor is modified without inserting new value (prevents duplicates)
ro = rng.Find(str, LookIn:=xlValues, LookAt:=xlWhole).Row
Debug.Print Err.Number
'Ensures a user doesn't add the same value twice
If Err.Number > 0 Then
Sheets(1).Cells(Sheets(1).Cells(Sheets(1).Rows.Count, 1).End(xlUp).Row + 1, 1) = str
Me.cbColor.AddItem StrConv(Me.tbNew, vbProperCase), Me.cbColor.ListCount - 1
Me.cbColor.ListIndex = Me.cbColor.ListCount - 2
Else
Me.cbColor.ListIndex = ro - 2
End If
'Resets and hides user form entries
Me.tbNew = vbNullString
Me.tbNew.Visible = False
Me.bAdd.Visible = False
End If
End Sub
Private Sub bClose_Click()
Unload Me
End Sub
Private Sub cbColor_Change()
'Visibility is toggled based on if the user selected the last element in the dropdown
Me.bAdd.Visible = Me.cbColor.ListIndex = Me.cbColor.ListCount - 1
Me.tbNew.Visible = Me.cbColor.ListIndex = Me.cbColor.ListCount - 1
End Sub
Private Sub UserForm_Initialize()
'Populate from the sheet
For a = 2 To Sheets(1).Cells(Cells(Sheets(1).Rows.Count, 1).End(xlUp).Row, 1).Row
Me.cbColor.AddItem Sheets(1).Cells(a, 1)
Next
'Add option for new type
Me.cbColor.AddItem "Add new type..."
End Sub

Reading Userform Object Values

I created a Userform (manually in the VBA Projectbrowser). I have written VBA code, which fills this Userform with different Objects in runtime (Labels, Optionbuttons etc.). So far everything worked fine
The Userform is filled with data read from my Excel sheets and correctly displayed. However I'm not able to read the inputs from the objects on it (for example Optionbutton - TRUE or FALSE). These objects do not appear anywhere (except on the userform) so that I can link them and use them in another Module.
I guess they are only displayed and not really read into the memory or whatever (initialized !?).
There are two ways to go about it.
WAY 1
Declare your option button object as Public.
Module Code
Public theOpBut As Object
Sub Fill()
If theOpBut.Value = True Then
ActiveSheet.Cells(1, 5) = 1
Else
ActiveSheet.Cells(1, 5) = "NO"
End If
End Sub
Userform Code
Private Sub UserForm_Initialize()
Set theOpBut = UserForm1.Controls.Add("Forms.optionbutton.1", "OptionButton", True)
With theOpBut
.Caption = "Test Button"
'.GroupName = OpButGroupCounter
.Top = 10
.Left = 20
.Height = 16
.Width = 50
.Font.Size = 12
.Font.Name = "Ariel"
End With
End Sub
Private Sub CommandButton1_Click()
Call Fill
End Sub
WAY 2
Declare a Boolean Variable and create a click event of the Option button and then set the value of the Boolean Variable in that click event. To create the click event of the Option button at Run Time, see THIS EXAMPLE
You can then check the value of Boolean Variable in Sub Fill() and act accordingly.