Sub _change reference of added comobox to userform VBA - excel

The following code will open a userform (examples) in which I have a commmandbutton which adds a new Combobox. I can name the combobox and can retrive the name in the immediate window, but I am unable to accecs the change command of the added combobox(es) or retrive the acces to their input.
In would like to do things upon change of this added combobox. I am able to do it for 1 box using the set "newgene1" = .... but than it on reclickit this first box will get lost.
Option Explicit
Dim Counter As Integer
Private WithEvents newgene1 As MSForms.ComboBox
Private WithEvents newgene2 As MSForms.ComboBox
Dim Generanger As Range
Private Sub UserForm_Initialize()
Set Generanger = ThisWorkbook.ActiveSheet.Range("A1", Range("A1").End(xlDown)) 'list of data
Generanger.Select
Counter = 1
cboGenelist.RowSource = Generanger.Address
End Sub
--------------------------------------------------------------------
Private Sub cboGenelist_Change()
MsgBox (cboGenelist.Text)
End Sub
--------------------------------------------------------------------
Private Sub cmdAddgene_Click()
UserForm1.Height = UserForm1.Height + 20
UserForm1.Controls.Add("Forms.comboBox.1", "newgene" & Counter) = "select"
With Me.Controls("newgene" & Counter)
.Left = 20
.Top = UserForm1.Height - 50
.RowSource = Generanger.Address
.Font.Name = "Trebuchet MS"
.Font.Size = 12
End With
Debug.Print Me.Controls("newgene" & Counter).Name
Counter = Counter + 1
End Sub
--------------------------------------------------------------------
Private Sub newgene1_Change()
MsgBox (newgene.Text)
End Sub
--------------------------------------------------------------------
Private Sub newgene2_Change()
MsgBox (newgene2.Text)
End Sub

Related

Refer to ComboBox that is just created after user input

i am trying to have VBA create a user form and based off of what selection you choose populate more selections.
the following code is my initial user form and i have it adding Comboboxes Based on whatever selection is chosen.
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Selection1"
ComboBox1.AddItem "Selection2"
ComboBox1.AddItem "Selection3"
ComboBox1.FontSize = 13
End Sub
But i have it going to comboboxchange to do so
Private Sub ComboBox1_Change()
'Here i have some Working Code That Adds another ComboBox
Dim MsgType As Control
Set MsgType = UserForm2.Controls.Add("Forms.ComboBox.1")
With MsgType
.Height = 25
.Width = 300
.Top = 75
.Left = 20
.FontSize = 13
.Name = "vmtype"
.AddItem "Selection1"
.AddItem "Selection2"
Debug.Print .Value
End With
EndSub
I now need to have a private sub refer to this combo box just as "Private Sub ComboBox1_Change()" had. that way i can add more items depending on that selection.
What i have so far is the following.
Private Sub ComboBox2_Change()
Dim Notetype As String
Notetype = ComboBox1.Value
Debug.Print Notetype
End Sub
But it is not actually refering to the newly created Combo Box any idea how i can Fix this?
Use WithEvents to listen for dynamically added controls.
Here is a simple example where you are just adding a single control:
Private WithEvents vmtype As MSForms.ComboBox
Private Sub vmtype_Change()
Debug.Print MsgType
End Sub
Private Sub ComboBox1_Change()
Set vmtype = UserForm2.Controls.Add("Forms.ComboBox.1")
With vmtype
.Height = 25
.Width = 300
.Top = 75
.Left = 20
.FontSize = 13
.Name = "vmtype"
.AddItem "Selection1"
.AddItem "Selection2"
End With
End Sub
Consider using a custom class when adding many control. See my post: Responding to Events of Dynamically added Controls

Create and Add Controls and Attach Events to them at Runtime in Excel UserForms

recently I found a very useful article about “How to add Events to dynamically created Controls in Excel using VBA class module”. I tried it in my project and it worked perfectly for just one textbox at a time. Actually I have to create multiple textboxes dynamically using VBA "For Next Loop" and attach the same event to all of them explicitly. but only the last created textbox gets the event.
Would you please help?
userform:
Private Sub UserForm_Initialize()
' Create and add the textboxes.
Dim i As Integer
For i = 0 To 4
Set tbPin = Me.Controls.Add("Forms.TextBox.1")
With tbPin
.Top = 8 + (i * 20)
.Left = 10
.Width = 130
.Name = "thePin"
End With
Set objMyEventClass.tbEvents = tbPin ' Attach an event to the textbox.
Next
' Create and add the button control.
Dim btEx As MSForms.CommandButton
Set btEx = Me.Controls.Add("Forms.CommandButton.1")
With btEx
.Top = Me.Height - 60
.Left = 10
.Width = 130
.Height = 25
.Caption = "Submit"
End With
Set objMyEventClass.btEvents = btEx ' Attach at event to the button.
End Sub
class module:
Option Explicit
Public WithEvents tbEvents As MSForms.TextBox
Public WithEvents btEvents As MSForms.CommandButton
Private Sub tbEvents_Change()
If Len(UserForm1.tbPin) > 6 Then
MsgBox "Max 6 digits only"
With UserForm1.tbPin
.Text = ""
.SetFocus
End With
End If
End Sub
Private Sub btEvents_click()
If Trim(UserForm1.tbPin) <> "" Then
Call showMyPin(UserForm1.tbPin)
End If
End Sub
Private Sub showMyPin(pin As String)
MsgBox "You have entered " & pin
End Sub

Write to the cell next to a checkbox when that checkbox is checked

I have a to do list in excel. When a check box is checked a macro is ran that selects a specific cell and adds values to offsets of that cell. The problem is I have 600 check boxes and they all need their own code to reference the correct cells.
private sub checkbox1_click ()
Range ("I2").offset(0,3).value= "hello world"
Sub end
I want something like this:
Range ("location of checkbox I just checked").offset(0,3).value= "hello world"
This would be easier if you are using ActiveX control checkboxes instead of Form control.
With ActiveX control checkboxes, you can refer to the object as a part of Me, which points to the worksheet itself and use something like this:
Private Sub CheckBox1_Click()
If Me.CheckBox1.Value = True Then
Me.CheckBox1.TopLeftCell.Offset(0, 3).Value = "hello world"
End If
End Sub
If you can't use ActiveX controls, please let me know and I can adjust my answer. Note that you could also look at more information on how to make a checkbox refer to itself by looking at the answer to this question.
In the answer from PeterT, you can also see how to use a Class Module to avoid the problem of having one macro per checkbox. Here, I'm copying the relevant part of the answer:
[...] Create a class module that you can instantiate for any number of
CheckBoxes.
Code for Class module MyCheckBoxClass
Dim WithEvents cbControl As MSForms.CheckBox
Private controlName As String
Public Sub cbControl_Click()
Debug.Print controlName & " is now " & cbControl.Value
If cbControl.Value = True Then
Range("CheckBoxCount") = Range("CheckBoxCount") + 1 'choose to store on the sheet
groupCheckBoxCount = groupCheckBoxCount + 1 'or in a variable
Else
Range("CheckBoxCount") = Range("CheckBoxCount") - 1
groupCheckBoxCount = groupCheckBoxCount - 1
End If
End Sub
Public Sub Attach(newCB As MSForms.CheckBox, newName As String)
Set cbControl = newCB
controlName = newName
End Sub
Private Sub Class_Initialize()
controlName = ""
End Sub
Code in a regular code module:
Public groupClickCount As Integer
Private cbCollection As Collection
Public Sub SetUpControlsOnce()
Dim thisCB As MyCheckBoxClass
Dim ctl As OLEObject
Dim cbControl As MSForms.CheckBox
If cbCollection Is Nothing Then
Set cbCollection = New Collection
End If
For Each ctl In ThisWorkbook.Sheets("Sheet1").OLEObjects
If TypeName(ctl.Object) = "CheckBox" Then
'--- this is an ActiveX CheckBox
Set thisCB = New MyCheckBoxClass
thisCB.Attach ctl.Object, ctl.name
cbCollection.Add thisCB
End If
Next ctl
End Sub
Of course, you would have to replace "Sheet1" with the appropriate name for your sheet and
If cbControl.Value = True Then
Range("CheckBoxCount") = Range("CheckBoxCount") + 1 'choose to store on the sheet
groupCheckBoxCount = groupCheckBoxCount + 1 'or in a variable
Else
Range("CheckBoxCount") = Range("CheckBoxCount") - 1
groupCheckBoxCount = groupCheckBoxCount - 1
End If
With
If cbControl.Value = True Then
cbControl.TopLeftCell.Offset(0, 3).Value = "hello world"
End If
And finally, I would suggest to run the SetUpControlsOnce macro when you open the workbook by including it in the Open Event of the Workbook Object (Thisworkbook). ie.:
Private Sub Workbook_Open()
Call SetUpControlsOnce
End Sub

A checkbox that refers to itself in Excel VBA

I have an excel spreadsheet that sets a cell's value to the number of checked boxes in a group. I would like to assign a macro to each that looks like this:
Sub clickedBox()
If thisBox(or however you would do it).Checked = True Then
Range("D9").Value = Range("D9").Value + 1
Else
Range("D9").Value = Range("D9").Value - 1
End If
End Sub
The cell defaults to 0 and all the boxes default to unchecked. That way, ticking a box ups the count, and unticking it knocks it down one and it can never go below zero or higher than the number of boxes.
I realize that I should also make it so that the macro triggers when a checkbox's state is changed not only when it's clicked, but I want to make sure this is possible first.
Is there a way to have a checkbox just reference itself like that?
It really depends if you're tied into ActiveX controls or Form Controls. Either can work, and either path likely directs how to clearly implement it.
Using ActiveX Controls (checkboxes):
You have two options to code your "click handlers" for ActiveX controls. The first is hard-coding a public sub for each control:
control on Thisworkbook.Sheets("Sheet1"): CheckBox1
code in Excel Object Sheet1:
Private groupCheckBoxCount As Integer
Private Sub CheckBox1_Click()
Debug.Print "Control on " & Me.Name & " is now " & Me.CheckBox1.Value
RegisterCheckedValue Me.CheckBox1.Value
End Sub
Private Sub RegisterCheckedValue(cbVal As Boolean)
If cbVal = True Then
Range("CheckBoxCount") = Range("CheckBoxCount") + 1 'choose to store on the sheet
groupCheckBoxCount = groupCheckBoxCount + 1 'or in a variable
Else
Range("CheckBoxCount") = Range("CheckBoxCount") - 1
groupCheckBoxCount = groupCheckBoxCount - 1
End If
End Sub
Then if you have ten checkboxes, you'll have ten CheckBox(x)_Click subs, each specifically tied to a single ActiveX control. Each of these click handlers can increment or decrement your counter in stored in a worksheet cell (or in a module private variable).
The second option is to create a class module that you can instantiate for any number of CheckBoxes.
code for class module MyCheckBoxClass
Dim WithEvents cbControl As MSForms.CheckBox
Private controlName As String
Public Sub cbControl_Click()
Debug.Print controlName & " is now " & cbControl.Value
If cbControl.Value = True Then
Range("CheckBoxCount") = Range("CheckBoxCount") + 1 'choose to store on the sheet
groupCheckBoxCount = groupCheckBoxCount + 1 'or in a variable
Else
Range("CheckBoxCount") = Range("CheckBoxCount") - 1
groupCheckBoxCount = groupCheckBoxCount - 1
End If
End Sub
Public Sub Attach(newCB As MSForms.CheckBox, newName As String)
Set cbControl = newCB
controlName = newName
End Sub
Private Sub Class_Initialize()
controlName = ""
End Sub
code in a regular code module:
Public groupClickCount As Integer
Private cbCollection As Collection
Public Sub SetUpControlsOnce()
Dim thisCB As MyCheckBoxClass
Dim ctl As OLEObject
Dim cbControl As MSForms.CheckBox
If cbCollection Is Nothing Then
Set cbCollection = New Collection
End If
For Each ctl In ThisWorkbook.Sheets("Sheet1").OLEObjects
If TypeName(ctl.Object) = "CheckBox" Then
'--- this is an ActiveX CheckBox
Set thisCB = New MyCheckBoxClass
thisCB.Attach ctl.Object, ctl.name
cbCollection.Add thisCB
End If
Next ctl
End Sub
Using Form Controls (checkboxes):
While there are several ways to catch the click event for a Form checkbox, the simplest is to connect ALL checkboxes in a group to a single macro:
Public groupClickCount As Integer
Public Sub cbControl_Click()
'--- loop through all the controls on the form and filter for
' only checkboxes, then count up how many are checked
Dim ctl As Shape
Dim checkCount As Integer
checkCount = 0
For Each ctl In ActiveSheet.Shapes
If ctl.Type = msoFormControl Then
On Error Resume Next
If ctl.ControlFormat = xlCheckBox Then
If ctl.ControlFormat.Value = 1 Then
checkCount = checkCount + 1
Else
checkCount = checkCount - 1
End If
End If
End If
Next ctl
Range("CheckBoxCount") = checkCount 'choose to store on the sheet
groupClickCount = checkCount 'or in a variable
End Sub
Either solution can be adapted in many ways, depending on your needs and how you'd like to track your checkboxes.

Too much data in a cell to display in a Userform Listbox

I have a listbox in a userform in Excel 2007.
Some cells in my worksheet contain more than 10 rows (data with ALT ENTER).
I'm trying to clean and display the data. I don't want to change the column width to 1000, but I'd like to use a mouseover box to show all the cell data.
Is there another idea that would work?
With mouse over would be possible to do it but it is complicated I think. Here I have another simpler idea: on double click in list box a multi line text box with selected list item(s) data will be shown. This text box has the same position and size as the list box. On the user form click text box hides. Here is some sample code, to test it you need form with list box named "ListBox1":
Option Explicit
Public ListItemInfo As Control
Private Sub UserForm_Initialize()
Set ListItemInfo = Me.Controls.Add("Forms.TextBox.1", "ListItemInfo", False)
With Me.ListItemInfo
.Top = Me.ListBox1.Top
.Left = Me.ListBox1.Left
.Width = Me.ListBox1.Width
.Height = Me.ListBox1.Height
.MultiLine = True
End With
End Sub
Private Sub ListBox1_Change()
Me.ListItemInfo.text = GetSelectedItemsText
End Sub
Private Sub ListBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
SwitchListItemInfo
End Sub
Private Sub UserForm_Click()
SwitchListItemInfo
End Sub
Private Function GetSelectedItemsText() As String
Dim text As String
Dim i As Integer
For i = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Selected(i) Then
text = text & Me.ListBox1.List(i) & vbNewLine
End If
Next i
GetSelectedItemsText = text
End Function
Private Sub SwitchListItemInfo()
If Me.ListItemInfo.text = "" Then Exit Sub
Me.ListItemInfo.Visible = Not Me.ListItemInfo.Visible
Me.ListBox1.Visible = Not Me.ListBox1.Visible
End Sub

Resources