VBA: Couldn't find names of textboxes created by control.add loop - vba

I created textboxes with control.add loop but I couldn't change their values. I want their names tb1, tb2...
Private Sub UserForm_Initialize()
For i = 1 To 10
Dim cCntrl As Control
Set cCntrl = Me.Controls.Add("Forms.textbox.1", "tb" & i)
Next
tb4 = "b"
End Sub

You cannot access the controls via name as the compiler doesn't know about these names. Instead, you can assign the controls to an array. Probably you want to access the controls not only at Initializing, so declare it as global.
Option Explicit
Dim ctrlArr(1 To 10) As Control, i As Long
Private Sub UserForm_Initialize()
For i = 1 To 10
Set ctrlArr(i) = Me.Controls.Add("Forms.textbox.1", "tb" & i)
ctrlArr(i).Top = i * 20
Next
ctrlArr(4).value = "b"
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

Loop through single column of Userform

I've worked with userforms in VBA a bit and know some of the tricks for looping through all controls. However, I'm running into issues with this one, and need a way to read the values of the line and reason columns into arrays based upon the values of "Area" and "Shift". The possible values for these two columns are in the picture.
Basically what I need is something like
For Each ctl In Me.Controls
If somectl.Value = "Kitting" And otherctl.Value = "1" Then
ReDim Preserve somearray(i)
somearray(i) = ctl.Value
End If
Next ctl
If you've manage to standardized your naming, you can do it like this:
Private Sub CommandButton1_Click()
Dim i As Integer
Dim areaCB As MSForms.ComboBox
Dim shiftCB As MSForms.ComboBox
Dim reasonCB As MSForms.ComboBox
Dim somearray
For i = 1 To 3 ' 3 or more depending on how may you have in your form
Set areaCB = Me.Controls("areadd" & i)
Set shiftCB = Me.Controls("shiftdd" & i)
Set reasonCB = Me.Controls("reasondd" & i)
If areaCB.Value = "Kitting" _
And shiftCB.Value = "1" Then
If IsArray(somearray) Then
ReDim Preserve somearray(UBound(somearray) + 1)
somearray(UBound(somearray)) = reasonCB.Value
Else
somearray = Array(reasonCB.Value)
End If
End If
Next
End Sub
So for example in areadd1, 1 is the row number.
Correspondingly, the ComboBox next to it to the right is shiftdd1 and so on.
This is just to give you idea. Modify it to suit your needs.

How can I get the value of a text variable that have the same name of a integer variable in VBA?

I have an userform that get some values..and I try to use a loop to get the values of theses variables that I get through a textbox, so I try to get the value of a variable through other variable(text) that have the same name of a number variable.. Anyone can help me to do this?
Example of my variables are: amountfra11a,amountfra12a...(these are the name of my textbox)
follows the code:
Private Sub OKTESTE_Click()
Dim b As Integer
For i = 1 To 1
a = "amountfra1" & i & "a.value"
b = CInt(a)
If b = 10 Then
c = d
End If
Next
End Sub
You can get the texbox values via the Controls collection of the UserForm:
Private Sub OKTESTE_Click()
Dim i, nm, a
For i = 11 To 12 'for example
nm = "amountfra" & i & "a"
a = Me.Controls(nm).Text
MsgBox nm & " = " & a
Next
End Sub

'Object Required' error when referencing dynamically created controls, stored in a collection, in the class of another dynamically created control

I am using a spin button to cycle through dates of a phase. When I call an item from a collection called customtextboxcollection with its index value, I get an "Object Required" error. Both the spin button and the text box whose value changes are dynamically created controls displayed on a UserForm called UserForm1.
The sub to create the items in customtextbox collection run before the spin button is clicked:
Dim customtextboxcollection As Collection
Dim spinbuttoncollection As Collection
Public Sub ComboBox1_Click() 'When a person is selected to enter hours for an employee from a combobox, it triggers the creation of the controls
Sheet1.Activate
CommandButton1.Enabled = True 'Enable the OK and Apply buttons when personnel title is selected.
UserForm1.Label2.Visible = True
UserForm1.ratebox.Visible = True
QuantityLabel.Visible = True
quantitybox.Visible = True
'The variables below are to access the table where I store saved information regarding the project phases I will add hours to.
Dim counter As Integer
counter = 6 'The index of the first row for phases
Dim phasecolumn As Integer
phasecolumn = 3 'The index of the column containing the phases
Dim checkboxnumber As Integer
checkboxnumber = 1 'This is the number needed to distinguish between the checkboxes that appear/disappear.
phasestartcolumn = 4
phaseendcolumn = 5
Dim customtextboxHandler As cCustomTextBoxHandler
Set customtextboxcollection = New Collection 'Sets the previously created collection
Dim spinbuttonHandler As cSpinButtonHandler 'This is my spin button handler class
Set spinbuttoncollection = New Collection 'Sets the previously created collection
'This Do-Loop locates a row on the table with saved information
Do
If (Sheet3.Cells(savedpersonnelrow, savedpersonnelcolumn) = ComboBox1.Value) Then
storagerow = savedpersonnelrow
lastcomboboxvalue = ComboBox1.Value
Exit Do
End If
savedpersonnelrow = savedpersonnelrow + 1
Loop Until (savedpersonnelrow = 82)
Sheet1.Activate
'These sections create the controls depending on the number of phases saved.
Set spin = UserForm1.Controls.Add("Forms.SpinButton.1")
With spin
.name = "SpinButton" & checkboxnumber
.Left = 365
.Top = topvalue + 6
.Height = 15
.Width = 40
'.Value = Sheet3.Cells(storagerow, savedphasecolumn + checkboxnumber)
'Sheet1.Activate
Dim phasestart As Date
phasestart = Sheet1.Cells(counter, phasestartcolumn).Value
Dim phaseend As Date
phaseend = Sheet1.Cells(counter, phaseendcolumn).Value
spin.Min = phasestart
spin.Max = phaseend
spin.Orientation = fmOrientationVertical
'Do
'.AddItem Format(phasestart, "mmm-yy")
'phasestart = DateAdd("m", 1, phasestart)
'Loop Until (Month(phaseend) = Month(phasestart) And Year(phaseend) = Year(phasestart))
Set spinbuttonHandler = New cSpinButtonHandler
Set spinbuttonHandler.spin = spin
spinbuttoncollection.Add spinbuttonHandler
End With
Set ctext = UserForm1.Controls.Add("Forms.TextBox.1")
With ctext
.name = "CustomTextbox" & checkboxnumber
.Left = 470
.Top = topvalue + 6
.Height = 15
.Width = 40
.Value = phasestart
Set customtextboxHandler = New cCustomTextBoxHandler
Set customtextboxHandler.ctext = ctext
customtextboxcollection.Add customtextboxHandler
End With
topvalue = topvalue + 15
counter = counter + 1
checkboxnumber = checkboxnumber + 1
Loop Until counter = 14
End Sub
In my class called cSpinButtonHandler, I reference these customtextboxcollection object associated with it's corresponding spin button:
Public WithEvents spin As MSForms.SpinButton
Private Sub spin_Click()
UserForm1.CommandButton3.Enabled = True
End Sub
Private Sub spin_SpinDown()
x = 0
Do
x = x + 1
Loop Until spin.name = "SpinButton" & x
Dim spindate As Date
spindate = customtextboxcollection.Item(x).ctext.Value 'The error occurs here.
customtextboxcollection.Item(x).ctext.Value = DateAdd("m", -1, spindate)
End Sub
Why is this reference generating an error? What is the correct way to reference it?
This is not an answer to your real question, but a suggestion for an alternate approach which might be easier to manage.
Instead of using two separate collections and two different classes, you could create a single class which would handle each pair of controls (one spin and one text box). That would be easier to handle in terms of hooking events between each pair.
clsSpinText:
Option Explicit
Public WithEvents txtbox As MSForms.TextBox
Public WithEvents spinbutn As MSForms.SpinButton
Private Sub spinbutn_Change()
'here you can refer directly to "txtbox"
End Sub
Private Sub txtbox_Change()
'here you can refer directly to "spinbutn"
End Sub
When adding your controls create one instance of clsSpinText per pair, and hold those instances in a single collection.

Excel-VBA How to know which dynamically created UserForm TextBox has changed?

I have an excel UserForm that creates textboxes during execution time. code as follows;
Dim CompHandler() As New CCompHandler
Dim tb As MSForms.TextBox
Dim count As Integer
For i in Range(something)
If i = anotherthing Then
Set tb = UserForm1.Controls.Add("Forms.TextBox.1", "tb" & count)
With tb
.Width = iTbWidth
.Top = count * distance
.Left = iTbLeft
.Height = iTbHeight
.Value = Cells(row, column)
ReDim Preserve CompHandler(0 To count)
Set CompHandler(count).TextBoxGroup = tb
End With
count = count + 1
End If
Next i
I want to write back the changed value to the corresponding cell.
I'm already able to get when the box has changed and the new value with this code on a class called CCompHandler:
Option Explicit
Public WithEvents TextBoxGroup As MSForms.TextBox
Private Sub TextBoxGroup_Change()
MsgBox TextBoxGroup
End Sub
So.. any ideas on how can I get which textbox has changed?
Or maybe is there a better way of doing that?
Thanks in advance
The Tag property is typically used for something like this. On creation add something like:
With tb
...
.Tag = i.Address
...
End With
You can then access the Tag property later, with something like:
Debug.Print tbWhoseValueHasChanged.Tag
Your code snippet has a lot of undefined/unclear variables, including i. I assumed it was a range variable in the above.