Trying to add Textboxes to a userform dynamically? - excel

I have code inside a excel workbook that helps me create mass emails to send to users of various programs. I have a userform that pops up and the user populates all the info needed. but that only counts for one app at a time. Can someone share code with me that dynamically adds textboxes to a userform dependant on what checkboxes are ticked ?
In the first frame I have check boxes that indicate what applications are affected, second frame I have option buttons to describe what type of incident and then I would like the textboxes to appear according to what has been ticked.
Any guidance much appreciated as I think this is way too deep for me at the moment
I've reverse engineered this code it adds the boxes I want but I need to be able to populate them with cell data and then use it in the emails:
Option Explicit
Dim SpnColct As Collection
Private Sub CommandButton2_Click()
Dim cSpnEvnt As cControlEvent
Dim ctlSB As Control
Dim ctlTXT As Control
Dim lngCounter As Long
For lngCounter = 1 To 7
Set ctlTXT = Me.Frame7.Controls.Add("Forms.TextBox.1", "Text" & lngCounter)
ctlTXT.Name = "Text" & lngCounter
ctlTXT.Left = 5
ctlTXT.Height = 125: ctlTXT.Width = 280
ctlTXT.Top = (lngCounter - 1) * 125 + 2
Set cSpnEvnt = New cControlEvent
Set cSpnEvnt.SP = ctlSB
Set cSpnEvnt.TXT = ctlTXT
SpnColct.Add cSpnEvnt
Next lngCounter
Me.Frame1.ScrollHeight = (lngCounter - 1) * 17 + 2
End Sub
This added to a class module:
Option Explicit
Public WithEvents SP As MSForms.SpinButton
Public WithEvents TXT As MSForms.TextBox
Private Sub SP_SpinDown()
SP.Value = SP.Value - 1
MsgBox "Spin Down to " & SP.Value
End Sub
Private Sub SP_SpinUp()
SP.Value = SP.Value + 1
MsgBox "Spin Up to " & SP.Value
End Sub
Private Sub TXT_Change()
MsgBox "You changed the value."
End Sub

Updated This is going to be a bit of a long one - step through it see if you understand it. Have changed it to create the textboxes on the CheckBox_Click event but change to the commandbutton if you wish. Any more then this and I think you'll need to start a new question.
I've been doing something similar recently and found that the reason you're having issues is due to the order of loading objects. I unfortunately can't find the link that explains it at the moment (will update if can) but briefly to be able to achieve this you need an additional Class that does the loading of the objects, otherwise the Userform can't see them. This is the kind of solution that I came up with (using your example)
Userform:
Option Explicit
Private WithEvents cControls As EventController
Private Sub cControls_Click(ctrl As CheckBoxControl)
Dim tBox As TextBoxControl
Dim i As Long
Dim NextTop As Long, FrameHeight As Long
For i = 1 To cControls.GetControls.Count
Debug.Print TypeName(cControls.GetControl(i))
If TypeName(cControls.GetControl(i)) = "TextBoxControl" Then
Set tBox = cControls.GetControl(i)
If tBox.TXT.Parent Is Me.Frame7 Then
NextTop = tBox.Top + tBox.Height
End If
End If
Next i
Set tBox = cControls.AddTextBox
With tBox
.Height = 125
.Width = 280
.Left = 5
.Top = NextTop
.TXT.Text = ctrl.cBox.Caption
FrameHeight = NextTop + .Height
End With
If FrameHeight > Me.Frame7.InsideHeight Then
With Me.Frame7
.ScrollBars = fmScrollBarsVertical
.ScrollHeight = FrameHeight
.Scroll yAction:=6
End With
End If
End Sub
Private Sub UserForm_Initialize()
Dim i As Long
Dim cBox As CheckBoxControl
Set cControls = New EventController
' This can be set to a userform or a frame
Set cControls.UserForm = Me
For i = 1 To 8
Set cBox = cControls.AddCheckBox
cBox.cBox.Left = 5
With cBox.cBox
.Top = 5 + (i - 1) * .Height
.Caption = IIf(i = 8, "App Unknown", "App " & i)
End With
Next i
End Sub
Private Sub cControls_Change(ctrl As TextBoxControl)
' This can be handled in the class instead as you were - just doing it in the userform to show the exposing of the event
MsgBox ctrl.TXT.Name & " Change"
End Sub
Private Sub cControls_SpinDown(ctrl As TextBoxControl)
' This can be handled in the class instead as you were - just doing it in the userform to show the exposing of the event
With ctrl.SP
If .Value >0 Then
.Value = .Value - 1
End If
End With
MsgBox ctrl.SP.Name & " Spin Down"
End Sub
Private Sub cControls_SpinUp(ctrl As TextBoxControl)
' This can be handled in the class instead as you were - just doing it in the userform to show the exposing of the event
With ctrl.SP
.Value = .Value + 1
End With
MsgBox ctrl.SP.Name & " Spin Up"
End Sub
Classes - These need to be named as in bold
EventControl
Option Explicit
Private CtrlCollection As Collection
Private cUserForm As UserForm1
Public Event SpinDown(ctrl As TextBoxControl)
Public Event SpinUp(ctrl As TextBoxControl)
Public Event Change(ctrl As TextBoxControl)
Public Event Click(ctrl As CheckBoxControl)
Public Property Set UserForm(v As UserForm1)
Set cUserForm = v
End Property
Public Property Get UserForm() As UserForm1
Set UserForm = cUserForm
End Property
Public Function AddTextBox() As TextBoxControl
Dim tBox As TextBoxControl
Set tBox = New TextBoxControl
tBox.Initialize Me
CtrlCollection.Add tBox
Set AddTextBox = tBox
End Function
Public Function AddCheckBox() As CheckBoxControl
Dim cBox As New CheckBoxControl
cBox.Initalize Me
CtrlCollection.Add cBox
Set AddCheckBox = cBox
End Function
Public Function GetControl(Index As Long)
Set GetControl = CtrlCollection(Index)
End Function
Public Function GetControls() As Collection
Set GetControls = CtrlCollection
End Function
Private Sub Class_Initialize()
Set CtrlCollection = New Collection
End Sub
Public Sub SpinDown(ctrl As TextBoxControl)
RaiseEvent SpinDown(ctrl)
End Sub
Public Sub SpinUp(ctrl As TextBoxControl)
RaiseEvent SpinUp(ctrl)
End Sub
Public Sub Change(ctrl As TextBoxControl)
RaiseEvent Change(ctrl)
End Sub
Public Sub Click(ctrl As CheckBoxControl)
RaiseEvent Click(ctrl)
End Sub
CheckBoxControl
Option Explicit
Public WithEvents cBox As MSForms.CheckBox
Private cParent As EventController
Public Property Set Parent(v As EventController)
Set cParent = v
End Property
Public Property Get Parent() As EventController
Set Parent = cParent
End Property
Public Sub Initalize(Parent As EventController)
Set Me.Parent = Parent
Set cBox = Parent.UserForm.Frame1.Controls.Add("Forms.CheckBox.1")
End Sub
Private Sub cBox_Click()
Parent.Click Me
End Sub
TextBoxControl
Option Explicit
Public WithEvents SP As MSForms.SpinButton
Public WithEvents TXT As MSForms.TextBox
Private cParent As EventController
Public Sub Initialize(Parent As EventController)
Set Me.Parent = Parent
With Parent.UserForm.Frame7.Controls
Set SP = .Add("Forms.SpinButton.1")
Set TXT = .Add("Forms.TextBox.1")
End With
End Sub
Public Property Set Parent(v As EventController)
Set cParent = v
End Property
Public Property Get Parent() As EventController
Set Parent = cParent
End Property
Public Property Let Left(v As Single)
TXT.Left = v
SP.Left = TXT.Left + TXT.Width
End Property
Public Property Get Left() As Single
Left = TXT.Left
End Property
Public Property Let Top(v As Single)
TXT.Top = v
SP.Top = v
End Property
Public Property Get Top() As Single
Top = TXT.Top
End Property
Public Property Let Height(v As Single)
TXT.Height = v
SP.Height = v
End Property
Public Property Get Height() As Single
Height = TXT.Height
End Property
Public Property Let Width(v As Single)
TXT.Width = v - SP.Width
SP.Left = TXT.Left + TXT.Width
End Property
Public Property Get Width() As Single
Width = TXT.Width + SP.Width
End Property
Public Sub SP_SpinDown()
Parent.SpinDown Me
' SP.Value = SP.Value - 1
' MsgBox "Spin Down to " & SP.Value
End Sub
' The commented out lines below you can either leave in here, or handle in the Userform
Public Sub SP_SpinUp()
Parent.SpinUp Me
' SP.Value = SP.Value + 1
' MsgBox "Spin Up to " & SP.Value
End Sub
Public Sub TXT_Change()
Parent.Change Me
' MsgBox "You changed the value."
End Sub
The issue is stemmed from that when the Userform is loaded the controls aren't loaded and therefore the Userform hasn't registered that they're something that has an Event. By using the intermediary class the Userform recognises that that class has an Event and we load this statically on initialize of the Userform. We can then add in whatever Controls we want to this Class and the Userform will handle them.
Demo:

Related

How to create _Change() Event for dynamically created TextBox in VBA UserForm?

I am trying to add _Change() event to dynamically created TextBox using classes in VBA. However there is nothing happening, when I try to run my code. Could you please point me where I am wrong?
I have got class conditionEventClass
Public WithEvents conditionEvent As MSForms.textBox
Public Property Let textBox(boxValue As MSForms.textBox)
Set conditionEvent = boxValue
End Property
Public Sub conditionEvent_Change()
MsgBox conditionEvent.Name & " changed."
End Sub
I have got following code in my module:
Sub addConditions()
Dim conditionCommand As conditionEventClass
Dim newTextBox As MSForms.textBox
Set newTextBox = commandRequestForm.MultiPage1(1).Controls.Add("Forms.TextBox.1", "conditionValue", True)
With newTextBox
.Name = "conditionValue"
.Left = 750
.height = 15
.Width = 100
.Top = 20
End With
Set conditionCommand = New conditionEventClass
conditionCommand.textBox = newTextBox
End Sub
I expect that my sub conditionEvent_Change() is going to show msgBox. But unfortunately nothing happens.
Talking about only a single Text Box, you can use the next simpler way:
1.Declare a private variable on top of the form code module (in the declarations area):
Private WithEvents myTextBox As MSForms.TextBox
Then, create the event for the above declared variable:
Private Sub myTextBox_Change()
MsgBox activecontrol.name & " changed."
End Sub
Use your adapted code as:
Sub addConditions()
Dim newTextBox As MSForms.TextBox
Set newTextBox = commandRequestForm.MultiPage1(1).Controls.Add("Forms.TextBox.1", "myTextBox", True)
With newTextBox
.left = 10
.height = 15
.width = 100
.top = 20
End With
Set myTextBox = newTextBox
End Sub
For 1 to 3, 4 such controls you can use the simpler (above shown) way. If you need creating on the fly a lot of such controls, I can show you how to adapt your code...
Edited:
Please, use the next working way using a class to be assigned to many text boxes created on the fly:
Copy the next code in a class module and name it 'clsTBox':
Option Explicit
Public WithEvents newTBox As MSForms.TextBox
Private Sub newTBox_Change()
MsgBox newTBox.name & " changed."
End Sub
2.Declare a Private variable on top of the form code module:
Private TBox() As New clsTBox
Use the next Sub to create three text boxes and assign the Click event to them:
Private Sub CreateThreeTB()
Dim i As Long, txtBox01 As MSForms.TextBox, leftX As Double, tWidth As Double, k As Long
leftX = 20: tWidth = 50
ReDim TBox(100) 'use here the maximum number of text boxes you intend creating
For i = 1 To 3
Set txtBox01 = Me.Controls.Add("Forms.TextBox.1", "dynTxtBox_" & i)
With txtBox01
.top = 10
.left = leftX: leftX = leftX + tWidth
.width = tWidth
.Text = "something" & i
End With
Set TBox(k).newTBox = txtBox01: k = k + 1
Next i
ReDim Preserve TBox(k - 1)
End Sub
Call the above Sub from Initialize event or from another control, play with the newly created text boxes value and see how the change event is triggered...

Excel VBA UserForm Tag Property

I have a UserForm with Text and Combo Boxes, some of which represent "REQUIRED FIELDS" and cannot be left blank. I have entered the value RQD for the tag property of the target controls. My objective is to loop through the controls and use their Tag property to identify controls that cannot be empty (where Tag property value = RQD) and change their BackColor property if they are. However, I cannot get this work. Below is some of the code:-
With frm_RecCapture
'
.lbl01_RecDate = Format(Date, "Long Date", vbSunday)
.txt01_RecNum = Format(RecNum, "000000")
.txt01_RecNum.Enabled = False
.txt01_AccNum.SetFocus
'
frmComplete = False
.Show
'
Do While frmComplete = False
.Show
'
For Each frmCtrl In .Controls
If TypeName(frmCtrl) = "Textbox" Or TypeName(frmCtrl) = "Combobox" Then
If frmCtrl.Tag = "RQD" And frmCtrl.Text = "" Then
frmCtrl.BackColor = &HFFFF&
n = n + 1
End If
End If
Next frmCtrl
'
If n = 0 Then
frmComplete = True
Else
frmComplete = False
MsgBox "ERROR! Fields highlighted in yellow cannot be left blank. Please "
complete these fields before continuing.", vbInformation + vbOKOnly, SysTitle
End If
Loop
'
End With
Any suggestions? Thanks...
I prefer writing a class that wraps and validates a control. You will need to store a reference to the wrapper class in a collection of some type of class level variable keep it from falling out of scope.
Class: RequiredFieldControl
Option Explicit
Private WithEvents ComboBox As MSForms.ComboBox
Private WithEvents TextBox As MSForms.TextBox
Private mControl As MSForms.Control
Private Const DefaultBackColor As Long = -2147483643
Private Const InvalidBackColor As Long = vbYellow ' &HFFFF&
Public Property Set Control(ByVal Value As MSForms.Control)
Set mControl = Value
Select Case TypeName(Control)
Case "ComboBox"
Set ComboBox = Value
Case "TextBox"
Set TextBox = Value
End Select
FormatControl
End Property
Public Property Get Control() As MSForms.Control
Set Control = mControl
End Property
Sub FormatControl()
Control.BackColor = IIf(isValid, DefaultBackColor, InvalidBackColor)
End Sub
Public Function isValid() As Boolean
Select Case TypeName(Control)
Case "ComboBox"
isValid = ComboBox.ListIndex > -1
Case "TextBox"
isValid = Len(TextBox.Value) > 0
End Select
End Function
Private Sub ComboBox_Change()
FormatControl
End Sub
Private Sub TextBox_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
FormatControl
End Sub
Form Code
Private RequiredFields As Collection
Private Sub UserForm_Initialize()
Set RequiredFields = New Collection
AddRequiredFields Me.Controls
ComboBox1.List = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Debug.Print RequiredFields.Count
End Sub
Sub AddRequiredFields(pControls As MSForms.Controls)
Dim RequiredField As RequiredFieldControl
Dim Control As MSForms.Control
For Each Control In pControls
If Control.Tag = "RQD" Then
Select Case TypeName(Control)
Case "ComboBox", "TextBox"
Set RequiredField = New RequiredFieldControl
Set RequiredField.Control = Control
RequiredFields.Add RequiredField
End Select
Else
On Error Resume Next
AddRequiredFields Control.Controls
On Error GoTo 0
End If
Next
End Sub
Function AreAllRequiredFieldsFilled() As Boolean
Dim RequiredField As RequiredFieldControl
For Each RequiredField In RequiredFields
If Not RequiredField.isValid Then Exit Function
Next
AreAllRequiredFieldsFilled = True
End Function

It is possible to access a dynamic object of Excel UserForm1 from code of UserForm2? Not from code of a module

I have a "Class" Module whit declaration and events of my dynamics labels
Option Explicit
Public WithEvents ClassLabel As MSForms.Label
Public Sub ClassLabel_Click()
If InStr(ClassLabel.Name, "LB_Label") Then
Set CurrentLabel = ClassLabel
'Bla Bla Bla
End If
End Sub
And I have created 15 dynamic labels, in the "FR_Runtime" frame of UserForm1, which I have saved in an array in the Controls_Init() Sub of a normal Module1 as follows
Option Explicit
Public gArrayClassLabel() As New Class
Public CurrentLabel As MSForms.Label
Public Sub Controls_Init()
Dim Row As Integer
Dim nRow As Integer
Dim H As Integer
Dim LB_Label As MSForms.Label
nRow = 15
H = 30
ReDim gArrayClassLabel(1 To nRow)
For Row = 1 To nRow
Set LB_Label = UserForm1.FR_Runtime.Controls.Add("Forms.Label.1")
With LB_Label
.Name = "LB_Label" & Row
.Caption = " Label " & Row & ", 2"
.Left = 100
.Top = H
.Width = 75
.Height = 18
.ForeColor = vbRed
.BackColor = vbWindowBackground
.BorderStyle = fmBorderStyleSingle
.SpecialEffect = fmSpecialEffectSunken
End With
Set gArrayClassLabel(Row).ClassLabel = LB_Label
H = H + 30
Next Row
End Sub
From my UserForm1.FR_Runtime_Exit() event (or any other UserForm1, Module1 code), I have access to the fifth dynamic label as follows
Private Sub FR_Runtime_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Set glbCurrentLabel = gArrayClassLabel(5).ClassLabel
With UserForm1.TextBox1
.Text = Trim$(glbCurrentLabel.Caption)
.Left = glbCurrentLabel.Left
.Top = glbCurrentLabel.Top
.SelStart = 0
.SelLength = Len(glbCurrentLabel.Caption)
End With
End Sub
From UserForm2, I can access to a label created at design time: UserForm1.Label3.Caption = "This is an design time Label"
Can I acces the gArrayClassLabel(5).ClassLabel from a Sub of The UserForm2? Not from Module1 code.
Thanks Tragamor, I had not thought about the class modules properties. This is the new "Class" Module
Public WithEvents ClassLabel As MSForms.Label
Private sContent As String
'new Get property
Property Get Content() As String
Content= sContent
End Property
'new Let property
Property Let Content(NumLbl As String)
sContent = gArrayClassLabel(NumLbl).ClassLabel.Caption
End Property
Public Sub ClassLabel_Click()
If InStr(ClassLabel.Name, "LB_Label") Then
Set CurrentLabel = ClassLabel
'Bla Bla Bla
End If
End Sub
And I can access the fifth dynamic label Caption from anywhere in the code as follows
Dim NumDynamicLabel As New Class
'I use Let Content property to obtain the fifth dynamic label Caption
NumDynamicLabel.Content = 5
Dim CaptionDynamicLabel As String
'I use the Get Content Property to retrieve Caption of fifth dynamic label
CaptionDynamicLabel = NumDynamicLabel.Content

click event not working on programmatically / dynamically created optionbutton

I have the following code that programmatically / dynamically creates a frame and adds an option button:
Private Sub ComboBox1_Change()
Dim cb1234Frame As MsForms.Frame
Dim opbtn1 As MsForms.OptionButton
Set cb1234Frame = RT_Graph_Form.Controls.Add("Forms.Frame.1")
With cb1234Frame
.Top = 132
.Left = 12
.Height = 30
.Width = 144
.Caption = "Number of Graphs to Display"
End With
Set opbtn1 = cb1234Frame.Controls.Add("Forms.OptionButton.1")
With opbtn1
.Top = 6
.Left = 6
.Height = 18
.Width = 21.75
.Caption = "1"
End With
End Sub
But then this does not work:
Private Sub opbtn1_Click()
MsgBox "Test Successful!!"
End Sub
The problem is that event handlers need to be bound at compile-time: you cannot create an event handler for a dynamically created control.
Add a new class module to your project, call it DynamicOptionButton. The role of this class is to wrap the MSForms control and have a compile-time reference to it:
Option Explicit
Private WithEvents Wrapper As MSForms.OptionButton
Public Sub Initialize(ByVal ctrl As MSForms.OptionButton)
Set Wrapper = ctrl
End Sub
Private Sub Wrapper_Click()
MsgBox "Works!"
End Sub
Note that only a subset of the events will be available to handle: what events are available, depend on the interface you're declaring the wrapper reference with - MSForms.Control has a number of events (and properties), MSForms.OptionButton has another set: you may need to declare both interfaces (i.e. 2 wrappers for the same object) in order to access all the members.
Now in your form's declarations section, you'll need to hold a reference to all wrappers, otherwise the objects just fall out of scope and the handlers won't work. A Collection can do that:
Option Explicit
Private ControlWrappers As Collection
Private Sub UserForm_Initialize()
Set ControlWrappers = New Collection
End Sub
'...
Private Sub CreateOptionButton()
Dim ctrl As MSForms.OptionButton
Set ctrl = Me.Controls.Add("Forms.OptionButton.1")
'set properties...
Dim wrap As DynamicOptionButton
Set wrap = New DynamicOptionButton
wrap.Initialize ctrl
ControlWrappers.Add wrap
End Sub
Be careful to never reference the form's class name in the form's own code-behind: the global-scope RT_Graph_Form identifier refers to a VBA-controlled "default instance" auto-instantiated object that may or may not be the actual form instance that's being shown. You want to add your dynamic controls to Me.Controls, not RT_Graph_Form.Controls.
Now, we can handle events of controls spawned at run-time, but there's another problem: the event handler in the DynamicOptionButton class has no reference to the form it's on!
Or does it?
Every MSForms control has a Parent property; you can get ahold of the parent UserForm by recursively going up the Parent property until the returned reference is a UserForm - and from there you can access everything that's publicly exposed.
I'm not sure it's appropriate, but I managed to do-ish it.
I'm creating the userform from thisworkbook direcly so everything is stored there. I did not need the parent property anywhere.
Option Explicit
Const FolderPath As String = "C:"
Public TESTS As New Collection
Public CONTROLWRAPPERS As New Collection
Sub gotothere()
On Error GoTo bleh
Call Shell("explorer.exe" & " " & FolderPath & "\" & ThisWorkbook.ActiveSheet.Range("C14").Value, vbNormalFocus)
Exit Sub
bleh: Call Shell("explorer.exe" & " " & FolderPath, vbNormalFocus)
End Sub
Sub ChooseFolder()
Call Createform
End Sub
Private Sub Createform()
Set TESTS = Nothing
Call listalltests
Call Module1.MakeUserForm
Dim i As Integer
For i = 1 To TESTS.Count
Call CreateCommandbuttonButton(i)
Next i
Formol.Show vbModeless
End Sub
Private Sub listalltests()
Dim objFSO As Object
Dim objFolder As Object
Dim objSubFolder As Object
Dim i As Integer
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(FolderPath & "\")
i = 1
For Each objSubFolder In objFolder.subfolders
TESTS.Add objSubFolder.Name
i = i + 1
Next objSubFolder
End Sub
Private Sub CreateCommandbuttonButton(pos As Integer)
Dim ctrl As MSForms.CommandButton
Set ctrl = Formol.Controls.Add("Forms.commandbutton.1")
With ctrl
.Caption = TESTS(pos)
If (pos * 20 + 2) > 600 Then
.Left = 130
.Top = (pos - 29) * 26 + 2
.Width = 102
Else
.Left = 12
.Top = pos * 26 + 2
.Width = 102
End If
End With
Dim wrap As DynamicOptionButton
Set wrap = New DynamicOptionButton
wrap.Initialize ctrl
CONTROLWRAPPERS.Add wrap
End Sub
The MakeUserForm function is stored in a module and just check if there is a form named formol and if not create it with a certain width & height. it's an empty form.
The class is the exact same as the one made by mathieu except for the Wrapper_click event.

How do you use a public variable in a Class Module?

I'm using a Class Module to make a collection of save buttons all do the same thing. But when I try to get them to run a sub that requires a variable I can't get the variable passed to them.
Edited using #Teasel's advice about properties. The problem seems to be the Let Property is not allowing me to set the variable from Module1.
Class1
Public WithEvents SaveBtn As MSForms.CommandButton
Dim currentrow As Long
Private Sub SaveBtn_Click()
SendMessage
`Even if I just have it Msgbox currentrow it returns 0
End Sub
Property Let GetRow(myrow As Long)
currentrow = myrow
End Property
Property Get GetRow() As Long
GetRow = currentrow
End Property
Module1
`Trying to send the value into the Class using Let
Private Sub SendRow_Click()
Module1.GetRow = 22
End Sub
`Trying to Get the value back from the Class
Public Sub SendMessage()
Dim therow As Long
therow = Module1.GetRow
`I get the "Method or Data Member not found" error in the line above
MsgBox therow
End Sub
UserForm1
`This part works fine
Dim colSaveButtons As New Collection
Private Sub UserForm_Initialize()
Dim i As Long
Dim ctl As MSForms.Control
Dim obEvents As Class1
For Each ctl In Me.Controls
If TypeOf ctl Is MSForms.CommandButton Then
For i = 0 To 5
If ctl.Name = "btnSavePage" & i Then
Set obEvents = New Class1
Set obEvents.SaveBtn = ctl
colSaveButtons.Add obEvents
End If
Next
End If
Next ctl
End Sub
Add a "CurrentRow" field to your class module:
Public WithEvents SaveBtn As MSForms.CommandButton
Public CurrentRow As Long '<< add this
Private Sub SaveBtn_Click()
SendMessage CurrentRow
End Sub
In your loop:
...
If ctl.Name = "btnSavePage" & i Then
Set obEvents = New Class1
obEvents.CurrentRow = 10 'or whatever...
Set obEvents.SaveBtn = ctl
colSaveButtons.Add obEvents
End If
...
And your SendMessage method:
Public Sub SendMessage(CurrentRow As Long)
MsgBox "This works"
End Sub
You can use two differents ways to achieve that.
1. Public Property
To simple access your variable's value you need a Get property and to set its value you need a Let property.
In your Module:
'Your module private variable
Dim nameOfYourModuleVariable As String
...
'Set property to assign a value to your variable
Public Property Let nameOfYourProperty(value As String)
nameOfYourModuleVariable = value
End Property
'Get property to return the value of your variable
Public Property Get nameOfYourProperty() As String
nameOfYourProperty = nameOfYourModuleVariable
End Property
You can then use it like this:
'Set the value
MyModule.nameOfYourProperty = "foo"
'Get the value
MyModule.nameOfYourProperty
I highly recommend to use properties to do such things however you can also simply set your variable as public as shown in point 2.
2. Public Variable
Define your variable to be public so you can access it from everywhere.
In your Module:
Public nameOfYourVariable As String
Get or set the value from another module:
'Set the value
MyModule.nameOfYourVariable = "foo"
'Get the value
MyModule.nameOfYourVariable

Resources