Excel UserForm dynamic TextBox control exit events - excel

UPDATE: Upon further research in the object browser... it appears that an MSForms.TextBox implements neither the .Name property or _Exit events - only _Change events. Is there a way to determine which specific TextBox generated a change event?
Alternately is it possible to use the MSForms.Control with this technique? The Control object implements the .Name property and _Exit event.
Can you listen for a TextBox exit event? Similarly to how a normal TextBox event would work? E.g.
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'Update a certain label based on the value of the TextBox
End Sub
The following doesn't catch the exit event. Moreover, while I can see the .Name property of the TextBox which generated the event for MyTextBox in the locals window, I cannot access that info to determine which label to act on.
This class technique was adapted from this post, and this post, which caught the change events.
Class clsTextBox:
Private WithEvents MyTextBox As MSForms.TextBox
Public Property Set Control(tb As MSForms.TextBox)
Set MyTextBox = tb
End Property
' Want to handle this event, but it's not caught when exiting the TextBox control
Private Sub MyTextBox_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'Debug.Print me.Control.name
'Update a certain label based on the value of the TextBox
Stop
End Sub
' Catching this event but can't identify the control which triggered it
Private Sub MyTextBox_Change()
Debug.Print MyTextBox.Value ' <--- This prints the correct value
Debug.Print Me.Control.Name ' <--- ERROR here on any variation of Me or MyTextBox
'Update a certain label based on the value of the TextBox
Stop
End Sub
I have a series of dynamically created controls which need listeners. Code follows:
Option Explicit
Dim tbCollection As Collection
Private Sub UserForm_Initialize()
Dim ctrl As MSForms.Control
Dim obj As clsTextBox
Dim acftNumber As Long
Dim mPage As MSForms.MultiPage ' Control
Dim lbl_acftName As MSForms.Label
Dim lbl_currentHrs As MSForms.Label
Dim lbl_hrsDUE As MSForms.Label
Dim lbl_dateXFRIn As MSForms.Label
Dim lbl_dateXFROut As MSForms.Label
Dim lbl_hrsOnXFROut As MSForms.Label
Dim txb_currentHrs As MSForms.TextBox
Dim txb_hrsDUE As MSForms.TextBox
Dim txb_dateXFRIn As MSForms.TextBox
Dim txb_dateXFROut As MSForms.TextBox
Dim txb_hrsOnXFROut As MSForms.TextBox
Dim i As Double
Dim pgName As String
Dim acftName As String
' Correct for border size calculations bug in Excel 2016
Me.Height = 249.75
Me.Width = 350.25
acftNumber = Range("aircraft").Count 'Unknown value from 3 to 10
Set mPage = Me.multipage_file_week 'set Multipage variable
For i = 1 To acftNumber
'set name/title for new page
pgName = "pg_acft_" & i
acftName = Range("aircraft").Cells(i, 1).Value
'mPage.Pages.Add pgName, pgTitle
With mPage 'add acft tab
' add the aircraft page to the multipage
.Pages.Add pgName, acftName
' Aircraft Name Label
Set lbl_acftName = .Pages(i).Controls.Add("Forms.Label.1", "lbl_acftName_" & i, True)
With lbl_acftName
.Caption = acftName
.Font = "Arial"
.Font.Size = 12
.Font.Bold = True
.Left = 10
.Width = 55
.Top = 0
End With
' Current Hours Label and TextBox
Set lbl_currentHrs = .Pages(i).Controls.Add("Forms.Label.1", "lbl_currentHrs_" & i, True)
With lbl_currentHrs
.Caption = "Current Asset Hours:"
.TextAlign = fmTextAlignRight
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 20
.Width = 120
.Top = 25
End With
Set txb_currentHrs = .Pages(i).Controls.Add("Forms.TextBox.1", "txb_currentHrs_" & i, True)
With txb_currentHrs
.Value = "16004.5"
.Text = "16004.5"
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 150
.Width = 70
.Top = 25
End With
' Hours DUE Label and TextBox
Set lbl_hrsDUE = .Pages(i).Controls.Add("Forms.Label.1", "lbl_hrsDUE_" & i, True)
With lbl_hrsDUE
.Caption = "Hours next HMC DUE:"
.TextAlign = fmTextAlignRight
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 20
.Width = 120
.Top = 50
End With
Set txb_hrsDUE = .Pages(i).Controls.Add("Forms.TextBox.1", "txb_hrsDUE_" & i, True)
With txb_hrsDUE
.Value = "16004.5"
.Text = "16004.5"
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 150
.Width = 70
.Top = 50
End With
' Date XFR In Label and TextBox
Set lbl_dateXFRIn = .Pages(i).Controls.Add("Forms.Label.1", "lbl_dateXFRIn_" & i, True)
With lbl_dateXFRIn
.Caption = "Estimated arrival date:"
.TextAlign = fmTextAlignRight
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 20
.Width = 120
.Top = 75
End With
Set txb_dateXFRIn = .Pages(i).Controls.Add("Forms.TextBox.1", "txb_hrsDUE_" & i, True)
With txb_dateXFRIn
.Value = "4/16/2019"
.Text = "4/16/2019"
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 150
.Width = 70
.Top = 75
End With
' Date XFR Out Label and TextBox
Set lbl_dateXFROut = .Pages(i).Controls.Add("Forms.Label.1", "lbl_dateXFROut_" & i, True)
With lbl_dateXFROut
.Caption = "Estimated departure date:"
.TextAlign = fmTextAlignRight
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 20
.Width = 120
.Top = 100
End With
Set txb_dateXFROut = .Pages(i).Controls.Add("Forms.TextBox.1", "txb_hrsDUE_" & i, True)
With txb_dateXFROut
.Value = "4/16/2019"
.Text = "4/16/2019"
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 150
.Width = 70
.Top = 100
End With
' Hours on XFR Out Label and TextBox
Set lbl_hrsOnXFROut = .Pages(i).Controls.Add("Forms.Label.1", "lbl_hrsOnXFROut_" & i, True)
With lbl_hrsOnXFROut
.Caption = "Desired hours remaining on departure:"
.TextAlign = fmTextAlignLeft
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 20
.Width = 170
.Top = 125
End With
Set txb_hrsOnXFROut = .Pages(i).Controls.Add("Forms.TextBox.1", "txb_hrsDUE_" & i, True)
With txb_hrsOnXFROut
.Value = "35"
.Text = "35"
.Font = "Arial"
.Font.Size = 10
.Font.Bold = False
.Left = 200
.Width = 35
.Top = 125
End With
End With
'Debug
Debug.Print Me.multipage_file_week.Pages(i).Name & ":"
For Each ctrl In Me.multipage_file_week.Pages(i).Controls
Debug.Print " - " & ctrl.Name
Next ctrl
Next i
mPage.Value = 0
Me.Caption = FILE_WEEK_FORM_TITLE
Set tbCollection = New Collection
For Each ctrl In Me.Controls
If TypeOf ctrl Is MSForms.TextBox Then
Set obj = New clsTextBox
Set obj.Control = ctrl
tbCollection.Add obj
End If
Next ctrl
Set obj = Nothing
End Sub

MSForms.Control defines the Enter and Exit events: if you need to handle TextBox.Change, then you need two WithEvents variables:
Private WithEvents TextBoxEvents As MSForms.TextBox
Private WithEvents ControlEvents As MSForms.Control
Public Property Set Control(ByVal tb As Object)
Set TextBoxEvents = tb
Set ControlEvents = tb
End Property
MSForms.Control is also the interface through which you get to access properties like Name, Top, Left, Visible, etc.
Tip: Never type event handler procedure signatures by hand. Select the source interface from the dropdown in the upper-left corner of the code pane, then select an event to handle from the upper-right dropdown; let the VBE generate the members with the correct signature. If you're in a handler procedure and the upper-left dropdown says "(general)", you're not in an event handler.
EDIT
While the above code compiles fine and the MSForms.Control interface does expose the events we're looking to handle...
?TypeOf tb Is MSForms.Control
True
?TypeOf tb Is MSForms.TextBox
True
...there's a bit of COM hackery going on behind the scenes; there's enough smokes & mirrors for VBA to successfully compile the above, but, basically, you're looking at a glitch in The Matrix (Rubberduck's resolver has similar "nope" issues with MSForms controls): there isn't any obvious way to get VBA to bind a dynamic control object to its MSForms.Control events.

With the help of the ConnectToConnectionPoint API you can catch the Event (Every Event, also Enter and Exit) for every control.
Have a look here: Trigger Enter field behaviour through class for a control
For Exit it will be
Public Sub myExit(ByVal Cancel As MSForms.ReturnBoolean)
Attribute myExit.VB_UserMemId = -2147384829
'code
End Sub

Related

Change event of Combobox in Userform not getting triggered

I have a userform and a Click button on it. On click of this button a combobox is dynamically created. I want to do something when a particular value is selected from this combobox but the change event is not getting triggered. What could be the reason.
Here is my code which is put in the UserForm1 module.
Private WithEvents ComboBox1 As MSForms.ComboBox
Private Sub ClickButton_Click()
'Create combo box
Dim ComboBox1 As MSForms.ComboBox
Set ComboBox1 = Me.Controls.Add("Forms.ComboBox.1")
With ComboBox1
.Left = 160
.Top = 50
.Width = 70
.Height = 20
.AddItem ("> than")
.AddItem ("< than")
.AddItem ("Max")
.AddItem ("Min")
.Enabled = True
.BackColor = RGB(255, 255, 255)
.ForeColor = RGB(0, 0, 0)
.SpecialEffect = fmSpecialEffectFlat
.Font.Size = 12
.Font.Bold = False
.Font.Name = "Arial"
.TabIndex = 2
End With
DoEvents
ComboBox1.SetFocus
End Sub
Private Sub ComboBox1_Change()
Dim inputNumber As Variant
If ComboBox1.Value = "> than" Then
inputNumber = InputBox("Enter a number:")
'Check if the input is valid number
If IsNumeric(inputNumber) Then
ComboBox1.Value = ComboBox2.Value & " " & inputNumber
Else
MsgBox "Invalid input"
End If
End If
End Sub
The method you need to use is described here: https://stackoverflow.com/a/8986622/9852011 , but for your particular case, here is what you need to do:
This is the code that should be in the module of your UserForm:
Private m_oCollectionOfEventHandlers As Collection
Private Sub UserForm_Initialize()
Set m_oCollectionOfEventHandlers = New Collection
End Sub
Private Sub CommandButton1_Click()
Dim ComboBox1 As MSForms.ComboBox
Set ComboBox1 = Me.Controls.Add("Forms.ComboBox.1")
With ComboBox1
.Left = 160
.Top = 50
.Width = 70
.Height = 20
.AddItem ("> than")
.AddItem ("< than")
.AddItem ("Max")
.AddItem ("Min")
.Enabled = True
.BackColor = RGB(255, 255, 255)
.ForeColor = RGB(0, 0, 0)
.SpecialEffect = fmSpecialEffectFlat
.Font.Size = 12
.Font.Bold = False
.Font.Name = "Arial"
.TabIndex = 2
End With
DoEvents
ComboBox1.SetFocus
Dim cb1EventHandler As comboboxeventhandler
Set cb1EventHandler = New comboboxeventhandler
Set cb1EventHandler.ComboBox = ComboBox1
m_oCollectionOfEventHandlers.Add cb1EventHandler
End Sub
Then, insert a new class module into your project, name it "ComboBoxEventHandler" and put this code into it:
Private WithEvents m_oComboBox As MSForms.ComboBox
Public Property Set ComboBox(ByVal oComboBox As MSForms.ComboBox)
Set m_oComboBox = oComboBox
End Property
Private Sub m_oComboBox_Change()
Dim inputNumber As Variant
With m_oComboBox
If .Value = "> than" Then
inputNumber = InputBox("Enter a number:")
'Check if the input is valid number
If IsNumeric(inputNumber) Then
.Value = .Parent.ComboBox2.Value & " " & inputNumber
Else
MsgBox "Invalid input"
End If
End If
End With
End Sub
I don't know what "ComboBox2" is but for the sake of this example, I just assumed it is a ComboBox which already exists in the UserForm somewhere.

UserForm Object with Methods in VBA

I need to create an Object representing a UserForm, with methods to add Controls, and a method to present the UserForm.
I'm having a hard time wrapping my head around object-oriented VBA, and the tutorials/answers/documentation aren't helping me.
Here's how I imagine the Object and an example of its methods.
Sub UI_Window(caption as String)
Dim Form As Object
' This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
Set Form = ThisWorkbook.VBProject.VBComponents.Add(1)
With Form
.Properties("Caption") = caption
.Properties("Width") = 600
.Properties("Height") = 50
End With
return Form
Sub addButton(action as String, code as String)
Set NewButton = Form.designer.Controls.Add("Forms.commandbutton.1")
With NewButton
.Name = "cmd_1"
.Caption = action
.Accelerator = "M"
.Top = Form.Height
.Left = 50
.Width = 500
.Height = 100
.Font.Size = 14
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
' Adjust height of Form to added content
With Form
.Properties("Height") = Form.Height + NewButton.Height + 50
End With
' Should loop through code argument, line-by-line
Form.codemodule.insertlines 8, "Private Sub cmd_1_Click()"
Form.codemodule.insertlines 9, "msgbox (""Button clicked!"")"
Form.codemodule.insertlines 10, "End Sub"
End Sub
Sub present()
'Show the form
VBA.UserForms.Add(Form.Name).Show
'Delete the form
ThisWorkbook.VBProject.VBComponents.Remove Form
End Sub
End Sub
And here's how it would be used
Sub SampleWindow()
Set Window = UI_Window "Window Title"
Window.addButton "Click me", "msgbox (""Button clicked!"")"
Window.present()
End Sub
Please, try this adapted way:
Copy the next code on top of module where the following code exists:
Public frm As Object 'to use it even after the UserForm has been created
'to avoid it deletion when tested the code
Copy the next code in the same standard module:
Sub CreateAFormWithAButton()
Const formName As String = "MyNewForm"
Const formCaption As String = "My Form"
removeForm formName 'remove the previously created form, if the case
UI_Window formCaption, formName 'create the new form
addButton frm, "myFirstButton", "Click Me" 'add a button
VBA.UserForms.Add(frm.Name).Show 'show the newly created form
End Sub
Function formExists(frmName As String) As Boolean
Dim fr As Variant
For Each fr In ThisWorkbook.VBProject.VBComponents
If fr.Type = vbext_ct_MSForm Then
If frmName = fr.Name Then
Set frm = fr
formExists = True: Exit Function
End If
End If
Next
End Function
Sub UI_Window(frmCaption As String, frmName As String)
Set frm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm) '3
With frm
.Properties("Caption") = frmCaption
.Properties("Width") = 500
.Properties("Height") = 200
.Properties("Name") = frmName
End With
End Sub
Sub addButton(form As Object, btName As String, btCaption As String)
Dim NewButton As MSForms.CommandButton
If buttonExists(btName) Then MsgBox "A button named """ & btName & """ already exists...": Exit Sub
Set NewButton = form.Designer.Controls.Add("Forms.commandbutton.1")
With NewButton
.Name = btName
.caption = btCaption
.top = 0
.left = 50
.width = 100
.height = 40
.Font.size = 14
.Font.Name = "Tahoma"
End With
' Should loop through code argument, line-by-line
form.CodeModule.InsertLines 8, "Private Sub " & btName & "_Click()"
form.CodeModule.InsertLines 9, " msgbox (""Button clicked!"")"
form.CodeModule.InsertLines 10, "End Sub"
End Sub
Function buttonExists(btName As String) As Boolean
Dim ctrl As Variant
For Each ctrl In frm.Designer.Controls
If ctrl.Name = btName Then buttonExists = True: Exit Function
Next
End Function
Sub removeForm(frmName As String)
Dim i As Long, strName As String
If Not formExists(frmName) Then Exit Sub
strName = "TestName"
tryAgain:
On Error Resume Next
frm.Name = strName
If err.Number = 75 Then 'a previously used name...
err.Clear 'clear the error
strName = strName & i: i = i + 1 'increment the new string
frm.Name = strName: GoTo tryAgain 'test the new name again
End If
On Error GoTo 0
ThisWorkbook.VBProject.VBComponents.Remove frm
End Sub
If you will try running the code for the second time, you cannot create a button with the same name. The code check if the name exists and warn. It can be adapted to propose another name (adding an incremented number), but it needs also to set other positioning, making the code more complicated and this does not make the object of the question, I would say...
Please, run/test it and send some feedback.

address textbox in dynamic userform

I have read a lot here so far and I have been helped a lot. Thanks for that! Now there is one thing I can't get further with.
I want to create a userform dynamically in Excel/VBA. This works so far, here an example how I create 5 TextBoxes with Names TextBox1-5.
For cTextBox = 1 To 5
Set edtBox_n = usrFrm.Controls.Add("Forms.textbox.1", "TextBox" & cTextBox)
With edtBox_n
.Top = nTop
.Left = 200
' .MultiLine = True
' .EnterKeyBehavior = True
.Height = 20
.Width = 150
.Text = .Name
'.Name = "Textbox" & cTextBox
End With
nTop = nTop + 20
Next cTextBox
But I cannot address the Textboxes with the command e.g.
Sub CommandButton1_Click()
test = usrFrm.TextBox1.Value
End Sub
Does anyone have an idea? Excel says that TextBox does not exist / the object does not exist.
Thanks a lot!
The way I handle this is by creating a class which will handle a lot of the creation of the Control and also the Events. e.g. Class ctrlTextBox
Option Explicit
Public WithEvents edtBox_n As MSForms.TextBox
Private UForm As UserForm
Public Sub Initialize(frm As UserForm, nme As String)
Set UForm = frm
Set editbox_n = UForm.Controls.Add(bstrProgID:="Forms.TextBox.1", Name:=nme)
End Sub
Private Sub edtBox_n_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
MsgBox edtBox_n.value
End Sub
The in my Userform I first declare a public Collection that is available throughout the form. I will store all of my dynamically created controls in here.
Option Explicit
Private cControls As Collection
Private Sub UserForm_Initialize()
Dim cTextBox As Long
Dim edtBox_n As ctrlTextBox
Dim nTop As Long
Set cControls = New Collection
For cTextBox = 1 To 5
Set edtBox_n = New ctrlTextBox
edtBox_n.Initialize frm:=Me, nme:="TextBox" & cTextBox
With edtBox_n.edtBox_n
.Top = nTop
.Left = 200
' .MultiLine = True
' .EnterKeyBehavior = True
.Height = 20
.Width = 150
.Text = .Name
End With
cControls.Add edtBox_n
nTop = nTop + 20
Next cTextBox
End Sub

Dynamic checkbox to enable textbox

I have a problem about dynamic controls. I create a dynamic userform with single frames depending by a number (rngprt in my example dependent by user input). No problem till now. Now I want to enable a textbox (in order to change its value) inside a specific frame when the relative checkbox is click. I used a Class Module (Classe1), but with my code I succeeded only to enable the last textbox of the n-frames when its checkbox is clicked (e.g. if I have 3 frames with 3 textboxes and 3 checkboxes, only the third checkbox it's able to enable the third textbox, the first and the second don't work).
Class Module: Classe1
Option Explicit
Public WithEvents cmbEvent1 As MSForms.CommandButton
Public WithEvents txbEvent1 As MSForms.TextBox
Public WithEvents frmEvent1 As MSForms.Frame
Public WithEvents ckbEvent1 As MSForms.CheckBox
Private Sub cmbEvent1_Click()
UserForm3.Hide
End Sub
Private Sub frmEvent1_Click()
End Sub
Public Sub txbEvent1_Change()
End Sub
Private Sub ckbEvent1_Click()
If UserForm3.Controls("CK" & xx).Value = True Then
UserForm3.Controls("TB" & xx).Enabled = True
End If
End Sub
Module: UserForm3
Option Explicit
Dim cmdB As New Classe1
Dim txtB As New Classe1
Dim chkB As New Classe1
Dim frm As New Classe1
Dim chkBColl As New Collection
Private Sub UserForm_Initialize()
Dim x As Long
Dim c As Variant
Dim cmdB1 As MSForms.CommandButton
Dim frm1 As MSForms.Frame
Dim txtB1 As MSForms.TextBox
Dim chkB1 As MSForms.CheckBox
Set cmdB1 = UserForm3.Controls.Add("Forms.CommandButton.1")
With cmdB1
.Name = "OKButton"
.Caption = "OK"
.Top = 40 * rngprt
.Left = 120
.Width = 40
.Height = 25
End With
Set cmdB.cmbEvent1 = cmdB1
For x = cel.Row To cel.Row + rngprt - 1 '**rngprt is a number from a Module1**
xx = x - cel.Row + 1 '**for progessive name of controls Dim xx as long into the Module1**
Set frm1 = UserForm3.Controls.Add("Forms.Frame.1")
frm1.Top = 40 * (xx - 1)
frm1.Left = 10
frm1.Width = 300
frm1.Height = 35
frm1.Name = "FR" & xx
With frm1.Controls
Set txtB1 = .Add("Forms.TextBox.1")
With txtB1
.Name = "TB" & xx
.Top = 10
.Left = 160
.Width = 30
.Height = 15
.TextAlign = fmTextAlignRight
.Enabled = False
.Value=50
End With
Set txtB.txbEvent1 = txtB1
Set chkB1 = .Add("Forms.CheckBox.1")
With chkB1
.Name = "CK" & xx
.Caption = "Part"
.Top = 10
.Left = 245
.Width = 45
.Height = 15
End With
Set chkB.ckbEvent1 = chkB1
'Here I added the code below
End With
Set frm.frmEvent1 = frm1
Next x
End Sub
I tried also to add this code below the chkB1 setting, but nothing.
Set chkB = New Classe1
Set chkB.ckbEvent1 = Me.Controls(chkB.txbEvent1)
chkBColl.Add chkB
Anybody have idea. Thank in advance to all for help.
Your code will not work.
You need to create an array of classe1.
Check this changes:
Classe1
Option Explicit
Public WithEvents cmbEvent1 As MSForms.CommandButton
Public WithEvents txbEvent1 As MSForms.TextBox
Public WithEvents frmEvent1 As MSForms.Frame
Public WithEvents ckbEvent1 As MSForms.CheckBox
Public xx As Integer
Private Sub cmbEvent1_Click()
UserForm3.Hide
End Sub
Private Sub frmEvent1_Click()
End Sub
Public Sub txbEvent1_Change()
End Sub
Private Sub ckbEvent1_Click()
If UserForm3.Controls("CK" & xx).value = True Then
UserForm3.Controls("TB" & xx).Enabled = True
End If
End Sub
UserForm3
Dim cmdB() As New Classe1
Dim txtB() As Classe1
Dim chkB() As Classe1
Dim frm() As New Classe1
Dim chkBColl As New Collection
Private Sub UserForm_Initialize()
Dim x As Long
Dim c As Variant
Dim cmdB1 As MSForms.CommandButton
Dim frm1 As MSForms.Frame
Dim txtB1 As MSForms.TextBox
Dim chkB1 As MSForms.CheckBox
ReDim Preserve cmdB(1)
Set cmdB1 = UserForm3.Controls.Add("Forms.CommandButton.1")
With cmdB1
.Name = "OKButton"
.Caption = "OK"
.Top = 40 * rngprt
.Left = 120
.Width = 40
.Height = 25
End With
Set cmdB(0).cmbEvent1 = cmdB1
For x = cel.Row To cel.Row + rngprt - 1 '**rngprt is a number from a Module1**
xx = x - cel.Row + 1 '**for progessive name of controls Dim xx as long into the Module1**
ReDim Preserve txtB(xx)
Set txtB(xx) = New Classe1
Set frm1 = UserForm3.Controls.Add("Forms.Frame.1")
frm1.Top = 40 * (xx - 1)
frm1.Left = 10
frm1.Width = 300
frm1.Height = 35
frm1.Name = "FR" & xx
With frm1.Controls
Set txtB1 = .Add("Forms.TextBox.1")
With txtB1
.Name = "TB" & xx
.Top = 10
.Left = 160
.Width = 30
.Height = 15
.TextAlign = fmTextAlignRight
.Enabled = False
.Value=50
End With
txtB(xx).xx = xx
Set txtB(xx).txbEvent1 = txtB1
ReDim Preserve chkB(xx + 1)
Set chkB(xx) = New Classe1
Set chkB1 = .Add("Forms.CheckBox.1")
With chkB1
.Name = "CK" & xx
.Caption = "Part"
.Top = 10
.Left = 245
.Width = 45
.Height = 15
End With
Set chkB(xx).ckbEvent1 = chkB1
chkB(xx).xx = xx
'Here I added the code below
End With
ReDim Preserve frm(xx)
Set frm(xx).frmEvent1 = frm1
Next x
End Sub

Excel VBA - Creating buttons dynamically with code assigned

I am trying to create some buttons dynamically, and assign code to them.
The following code works
Dim MyR As Range, MyB As OLEObject
Dim MyR_T As Long, MyR_L As Long
Set MyR = Cells(i + 1, 11) 'just an example - you get that from your own script
MyR_T = MyR.Top 'capture positions
MyR_L = MyR.Left '...
'create button
Set MyB = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False)
'set main button properties
With MyB
.Name = "MyPrecodedButton" 'important - code must exist ... see below
.Object.Caption = "MyCaption"
.Top = MyR_T
.Left = MyR_L
.Width = 50
.Height = 18
.Placement = xlMoveAndSize
.PrintObject = True 'or false as per your taste
End With
It creates the buttons within my loop. However, I want to assign something to the on click, so I use the following code
Dim MyR As Range, MyB As OLEObject
Dim MyR_T As Long, MyR_L As Long
Set MyR = Cells(i + 1, 11) 'just an example - you get that from your own script
MyR_T = MyR.Top 'capture positions
MyR_L = MyR.Left '...
'create button
Set MyB = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False)
'set main button properties
With MyB
.OnAction = "interpHere"
.Name = "MyPrecodedButton" 'important - code must exist ... see below
.Object.Caption = "MyCaption"
.Top = MyR_T
.Left = MyR_L
.Width = 50
.Height = 18
.Placement = xlMoveAndSize
.PrintObject = True 'or false as per your taste
End With
Sub interpHere()
MsgBox "hi"
End Sub
I have basically added .OnAction = "interpHere" but when I run it, I get an error, unable to set the onaction property.
Where am I going wrong?
try this code
Sub CreateButtons()
Dim btn As Button
ActiveSheet.Buttons.Delete
Dim t As Range
For i = 2 To 6 Step 2
Set t = ActiveSheet.Cells(i, 3)
Set btn = ActiveSheet.Buttons.Add(t.Left, t.Top, t.Width, t.Height)
With btn
.OnAction = "interpHere"
.Caption = "Btn " & i
.Name = "Btn" & i
End With
Next i
End Sub
Sub interpHere()
MsgBox "hi"
End Sub

Resources