Assign code to a button created dynamically - vba

I'm trying to get a button I've created dynamically on an excel userform form to run a macro called transfer which I've written in Module 1 of the "Modules" section of my project.
Below I've pasted the code I've written so far in the userform which actually manages to create the Transfer to Sheet button in the frame (which I've also created dynamically) but for some reason, when I run VBA I get a 438 error message saying that Object doesn't support this property or method.
Can anybody tell me how I can resolve this?
Here's the code:
Dim framecontrol1 As Control
Set workitemframe = Controls.Add("Forms.Frame.1")
With workitemframe
.Width = 400
.Height = 400
.Top = 160
.Left = 2
.ZOrder (1)
.Visible = True
End With
workitemframe.Caption = "Test"
Set framecontrol1 = workitemframe.Controls.Add("Forms.commandbutton.1")
With framecontrol1
.Width = 100
.Top = 70
.Left = 10
.ZOrder (1)
.Visible = True
.Caption = "Transfer to Sheet"
End With
framecontrol1.OnAction = "transfer"

Here is an example. Please amend it to suit your needs :)
This example will create a command button and assign code to it so that when it is pressed, it will display "Hello World".
Paste this code in the click event of a command button which will create a new command button dynamically and assign code to it.
Option Explicit
Dim cmdArray() As New Class1
Private Sub CommandButton1_Click()
Dim ctl_Command As Control
Dim i As Long
i = 1
Set ctl_Command = Me.Controls.Add("Forms.CommandButton.1", "CmdXYZ" & i, False)
With ctl_Command
.Left = 100
.Top = 100
.Width = 255
.Caption = "Click Me " & CStr(i)
.Visible = True
End With
ReDim Preserve cmdArray(1 To i)
Set cmdArray(i).CmdEvents = ctl_Command
Set ctl_Command = Nothing
End Sub
and paste this code in a class module
Option Explicit
Public WithEvents CmdEvents As MSForms.CommandButton
Private Sub CmdEvents_Click()
MsgBox "Hello Word"
End Sub
SNAPSHOT

You need to add the code to the UserForm programatically. I used my code from this vbax article as the reference
The code below:
Runs from a normal module
Adds the button to a UserForm called UserForm1
Adds this code to the Userform for a Click Event
Private Sub CommandButton1_Click()
Call Transfer
End Sub
VBA from normal module
Sub AddToForm()
Dim UF As Object
Dim frameCOntrol1 As Object
Set UF = ActiveWorkbook.VBProject.VBComponents("UserForm1")
Set frameCOntrol1 = UF.designer.Controls.Add("Forms.CommandButton.1")
With frameCOntrol1
.Width = 100
.Top = 70
.Left = 10
.ZOrder (1)
.Visible = True
.Caption = "Transfer to Sheet"
End With
With UF.CodeModule
.InsertLines 2, _
"Private Sub " & frameCOntrol1.Name & "_Click()" & Chr(13) & _
"Call Transfer" & Chr(13) & _
"End Sub"
End With
End Sub

Related

ComboBox(number)_Change from generated ComboBoxes in VB

T he code below is what I am having some problems with. I'm pretty green to using Userforms in VB.
My goal is to create 3 ComboBoxes drawing data from the column of Vendors in the sheet "Vendor Bids" and 3 ListBoxes to select the vendor's product.
For j = 1 To 3
Set myCombo = Frame1.Controls.Add("Forms.ComboBox.1", "ComboBox" & j)
Set myList = Frame1.Controls.Add("Forms.ListBox.1", "ListBox" & j)
With myList
.Top = 18 + (150 - 84) * (j - 1)
.Height = 34.85
.Left = 198
.Width = 180
MsgBox .Name
End With
With myCombo
.Top = 18 + (150 - 84) * (j - 1)
.Height = 22.8
.Left = 42
.Width = 132
End With
Set rData = ThisWorkbook.Worksheets("VendorBids").Range("A:A").CurrentRegion
Me.Controls("ComboBox" & j).List = rData.Offset(1).Value
Me.Controls("ListBox" & j).ColumnCount = 1
Me.Controls("ListBox" & j).List = rData.Offset(1, 1).Value
Next
This part works perfectly. The reason I have this coded and not made in the Userform is because I have a function to add another row of the Combo and List boxes when the user presses the commandbutton. It works perfectly as well.
The problem I am having is with ComboBox_Change(). If I create the combobox in the UserForm GUI editor then ComboBox1_Change() will work. Below is an example with what I'm trying to achieve but with all of the generated comboboxes, like ComboBox2, 3, and so on...
Private Sub ComboBox1_Change()
Me.ListBox1.ListIndex = Me.ComboBox1.ListIndex
End Sub
I apologize if I'm not very clear in my logic or explanations - this is something I'm working to improve on as a novice.
Reference:Chip Pearson - Events And Event Procedures In VBA
You will need a combination of WithEvents and RaiseEvents to handle the events of the new controls.
ComboBoxHandler:Class
Stores a reference to a single Combobox. Using WithEvents it notifies the ControlHandlerCollection when the ComboBox_Change().
Option Explicit
Public ControlHandlerCollection As VBAProject.ControlHandlerCollection
Public WithEvents ComboBox As MSForms.ComboBox
Private Sub ComboBox_Change()
ControlHandlerCollection.ComboBoxChanged ComboBox
End Sub
ListBoxHandler:Class
Stores a reference to a single ListBox . Using WithEvents it notifies the ControlHandlerCollection when the ListBox_Change().
Option Explicit
Public ControlHandlerCollection As VBAProject.ControlHandlerCollection
Public WithEvents ListBox As MSForms.ListBox
Private Sub ListBox_Change()
ControlHandlerCollection.ListBoxChanged ListBox
End Sub
ControlHandlerCollection:Class
Holds a collection of both ComboBoxHandlers and ListBoxHandlers whenever one of the handler class notifies it of a change it raises an event to notify the Userform of the change.
Private EventHandlers As New Collection
Public Event ComboBoxChange(ComboBox As MSForms.ComboBox)
Public Event ListBoxChange(ListBox As MSForms.ListBox)
Public Sub AddComboBox(ComboBox As MSForms.ComboBox)
Dim ComboBoxHandler As New ComboBoxHandler
Set ComboBoxHandler.ControlHandlerCollection = Me
Set ComboBoxHandler.ComboBox = ComboBox
EventHandlers.Add ComboBoxHandler
End Sub
Public Sub AddListBox(ListBox As MSForms.ListBox)
Dim ListBoxHandler As New ListBoxHandler
Set ListBoxHandler.ControlHandlerCollection = Me
Set ListBoxHandler.ListBox = ListBox
EventHandlers.Add ListBoxHandler
End Sub
Public Sub ComboBoxChanged(ComboBox As MSForms.ComboBox)
RaiseEvent ComboBoxChange(ComboBox)
End Sub
Public Sub ListBoxChanged(ListBox As MSForms.ListBox)
RaiseEvent ListBoxChange(ListBox)
End Sub
UserForm1:UserForm
Option Explicit
Private WithEvents ControlHandlerCollection As ControlHandlerCollection
Private Sub ControlHandlerCollection_ComboBoxChange(ComboBox As MSForms.ComboBox)
MsgBox "Value: " & ComboBox.Value & vbNewLine & _
"Name: " & ComboBox.Name & vbNewLine & _
"Tag: " & ComboBox.Tag
End Sub
Private Sub ControlHandlerCollection_ListBoxChange(ListBox As MSForms.ListBox)
MsgBox "Value: " & ListBox.Value & vbNewLine & _
"Name: " & ListBox.Name & vbNewLine & _
"Tag: " & ListBox.Tag
End Sub
Private Sub UserForm_Initialize()
Set ControlHandlerCollection = New ControlHandlerCollection
End Sub
Private Sub btnAddRow_Click()
Dim j As Long
Dim rData As Range
Dim myCombo As MSForms.ComboBox, myList As MSForms.ListBox
Set rData = ThisWorkbook.Worksheets("VendorBids").Range("A:A").CurrentRegion
For j = 1 To 3
Set myCombo = Frame1.Controls.Add("Forms.ComboBox.1", "ComboBox" & j)
Set myList = Frame1.Controls.Add("Forms.ListBox.1", "ListBox" & j)
With myList
.Top = 18 + (150 - 84) * (j - 1)
.Height = 34.85
.Left = 198
.Width = 180
.ColumnCount = 1
.List = rData.Offset(1, 1).Value
.Tag = rData.Offset(1, 1).Address
End With
With myCombo
.Top = 18 + (150 - 84) * (j - 1)
.Height = 22.8
.Left = 42
.Width = 132
.List = rData.Offset(1).Value
.Tag = rData.Offset(1).Address
End With
ControlHandlerCollection.AddComboBox myCombo
ControlHandlerCollection.AddListBox myList
Next
End Sub

Excel VBA Userform CheckBoxes Access

I'm programmatically creating a userform based on number of rows in a sheet range (currently set to a fixed number for testing).
Then the user checks the boxes they want to check and clicks the command button.
The userform, as run with the code below, has one command button and one checkbox manually added. The other checkboxs is added programmatically.
I can't figure out how to get the value from the checkbox created problematically. I just get an error that "testbox" is not defined.
I know I'm missing something simple...
Any thoughts?
Thank you!
Option Explicit
Private Sub updateTablesBtn_Click()
If CheckBox1.Value = True Then
MsgBox "true"
End If
If testBox.Value = True Then
MsgBox "true"
End If
End Sub
Private Sub UserForm_Initialize()
Dim chkBox As MSForms.CheckBox
With formTableUpdate
.Width = 150
.Height = 200 '15 + 20 * (noOfVariants + 1) + 30
End With
Set chkBox = formTableUpdate.Controls.Add("Forms.CheckBox.1")
With chkBox
.Name = "testBox"
.Caption = "test"
.Left = 5
.Top = 10
End With
With updateTablesBtn
.Caption = "Update Tables"
.Height = 25
.Width = 76
.Left = 38
.Top = 30
End With
End Sub
Try this:
Dim chkBox As Control
For Each chkBox In formTableUpdate.Controls
If chkBox.Name = "testBox" Then
MsgBox chkBox.Caption & " has the value " & chkBox.Value
End If
Next chkBox

Populating Dynamic combobox

I have a number of controls that are added during runtime but I want to populate a combobox that is created during runtime based on answers received from the the other dynamic controls (its hard to word)!
I will try and explain via my code! During runtime the following controls are added to my userform:
Set cLabel = Me.Controls.Add("Forms.Label.1")
With cLabel
.Caption = "Do you study maths?"
.Font.Size = 8
.Font.Bold = False
.Font.Name = "Tahoma"
.Left = 38
.Top = mathslbl
.Width = 220
End With
Set cManagedOptionButtonYes= Me.Controls.Add("Forms.OptionButton.1")
With cManagedOptionButtonYes
.Caption = "Yes"
.Name = "fibreRingYes" & i
.GroupName = "fibreRing" & i
.Left = 160
.Top = mathsYes
.Width = 100
.Height = 15.75
End With
ReDim Preserve TextListBox(1 To i)
Set TextListBox(i).mathsGroupYes = cManagedOptionButtonYes
Set cStudentDropdown = Me.Controls.Add("Forms.Combobox.1")
With cStudentDropdown
.Name = "StudenDropdown1" & (i)
.Left = 50
.Top = studentCombobox
.Width = 130
.Height = 18
End With
ReDim Preserve TextListBox(1 To i)
Set TextListBox(i).studentdropdown1Group = cStudentDropdown
So during runtime the following controls are created, these controls ask whether the student studies maths or not and dependant on the answer the user gives the combobox will be populated. Below is the code that is trying to populate the combobox based on the users answer to the question:
Private Sub cManagedOptionButtonYes_Click()
Dim rng As Range
Dim cell As Range
Dim c As Range
With cStudentDropdown
Sheets("Students").Activate
For Each c In Sheets("Students").Range("C14:C86")
.AddItem c.Value
Next
End With
End Sub
When the code tries to execute i get the following error Object variable or with block variable not set and I can't figure out why this won't work for me!
assuming this is in the userform's code page:
Private Sub cManagedOptionButtonYes_Click()
'Dim rng As Range
'Dim cell As Range
Dim c As Range
With Me.cStudentDropdown 'Me. is not necessary, but i like to use it in order to have a dropdown menu with all functions and controls created on the form
'Sheets("Students").Activate
.clear
For Each c In Sheets("Students").Range("C14:C86")
'.AddItem c.Value 'should work (whatever its format i think)..., so try this :
'make sure no cell in the looping range returns a error result such as #N/A something like that
.additem
.list(.listcount-1) = c.value 'or try c.value2
Next
End With
End Sub
`

Create event handlers for multiple dynamic controls

I have a userform that creates two dynamic control buttons but I am having difficulty accessing the .name property of the dynamic control, which means I can't create the event handler correctly. Due to this problem I am unable to create event handlers. Below shows the code that creates the dynamic controls and also the code that I have written for the event handlers (which isn't functioning correctly)
Option Explicit
Public WithEvents cButton As MSForms.CommandButton
Private Sub TextBox1_Change()
If TextBox1 <> vbNullString Then
For i = 1 To TextBox1.Value
Set cButton = Me.Controls.Add("Forms.CommandButton.1")
With cButton
.Name = "CommandButton" & i
.Left = 150
.Top = buttonStartPosition
.Width = 300
.Height = 140
End With
Next i
End If
End sub
Private Sub cButton_Click()
If cButton.Name = "CommandButton1" Then
MsgBox "Button1"
ElseIf cButton.Name = "CommandButton2" Then
MsgBox "Button2"
End If
End Sub
Once this code is executed and the two buttons are on the screen, I press the first button (button1) and nothing happens but when I press the second button (button2) I receive the message "Button2". So how come I can't access the first button?
#user3538102 .. To your comment regarding Textbox's. Below is example is an example. I added Combo box select either CommandButton or TextBox and generate events. The code works but could be better.
I added combo box to select to dynamically generate object type.
In UserForm Activate event - Add combo drop down list
Private Sub UserForm_Activate()
ComboBox1.AddItem "CommandButton"
ComboBox1.AddItem "TextBox"
ComboBox1.ListIndex = 0
End Sub
In Class1 Class Module ..
Modified UserForm code ..
Option Explicit
Dim cObjs() As New Class1
Private Sub TextBox1_Change()
Dim i As Integer
Dim buttonStartPosition As Integer
Dim cObj As Object
buttonStartPosition = 30
If TextBox1 <> vbNullString Then
For i = 1 To TextBox1.Value
If ComboBox1.Value = "CommandButton" Then
Set cObj = Me.Controls.Add("Forms.CommandButton.1")
Else
Set cObj = Me.Controls.Add("Forms.TextBox.1")
End If
With cObj
.Name = ComboBox1.Value & i
.Left = 15
.Top = buttonStartPosition
.Width = 30
.Height = 14
End With
ReDim Preserve cObjs(1 To i)
If ComboBox1.Value = "CommandButton" Then
Set cObjs(i).ButtonGroup = cObj
Else
Set cObjs(i).TextGroup = cObj
End If
buttonStartPosition = buttonStartPosition + 14
Next i
End If
End Sub
I got the events for multiple buttons to work with help from .. JWalk Excel Tips
Below is the modification based on your code and the link provided.
Create a Class module called "Class1"
Add modified code to UserForm1..
Option Explicit
Dim Buttons() As New Class1
Private Sub TextBox1_Change()
Dim i As Integer
Dim buttonStartPosition As Integer
Dim cButton As CommandButton
buttonStartPosition = 30
If TextBox1 <> vbNullString Then
For i = 1 To TextBox1.Value
Set cButton = Me.Controls.Add("Forms.CommandButton.1")
With cButton
.Name = "CommandButton" & i
.Left = 15
.Top = buttonStartPosition
.Width = 30
.Height = 14
End With
ReDim Preserve Buttons(1 To i)
Set Buttons(i).ButtonGroup = cButton
buttonStartPosition = buttonStartPosition + 14
Next i
End If
End Sub

Error with creating command button during runtime

I have a module that creates command buttons during run-time. It will create the command buttons in a specified user-form. Program works fine, when I execute the module.
However when I use the user-form to call the module instead, I have a error stating
Run-time error '91':
Object variable or With block variable not set
Code
Sub AddButtonAndShow()
Dim Butn As CommandButton
Dim Line As Long
Dim objForm As Object
Dim i As Integer
Dim x As Integer
Set objForm = ThisWorkbook.VBProject.VBComponents("Current_Stock")
For i = 1 To 3
Set Butn = objForm.Designer.Controls.Add("Forms.CommandButton.1")
With Butn
.Name = "CommandButton" & i
.Caption = i
.Width = 100
.Left = 300
.Top = 10 * i * 2
End With
Next
For x = 1 To 3
With objForm.CodeModule
Line = .CountOfLines
.InsertLines Line + 1, "Sub CommandButton" & x & "_Click()"
.InsertLines Line + 2, "MsgBox ""Hello!"""
.InsertLines Line + 3, "End Sub"
End With
'
Next x
End Sub
Kindly advise.
Editted post: based on VBProject Form Components
Earlier post is for Excel Sheet buttons. I noticed for Form buttons you may set the caption by directly referring to the button itself. I tried out your code. Doesn't seem to find any errors. The only addtional things I did was adding the reference Library (MS VB Extensibility 5.3), Private scope to code and combining code into one with statement.
As per this Mr.Excel article, you need add do Events to run the code when VB Editor is closed. Your error seems to be very much alike to what's mentioned in the article.
Revised Code:
Sub AddButtonAndShow()
Dim Butn As CommandButton
Dim Line As Long
Dim objForm As Object
Dim i As Integer
Dim x As Integer
Dim code As String
Application.DisplayAlerts = False
DoEvents
On Error Resume Next
Set objForm = ActiveWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
objForm.Name = "thisform1"
For i = 1 To 3
Set Butn = objForm.Designer.Controls.Add("Forms.CommandButton.1")
With Butn
.Name = "CommandButton" & i
.Caption = i
.Width = 100
.Left = 100
.Top = (i * 24) + 10
Line = objForm.CodeModule.CountOfLines + 1
code = "Private Sub " & Butn.Name & "_Click()" & vbCr
code = code & "MsgBox ""Hello!""" & vbCr
code = code & "End Sub"
objForm.CodeModule.InsertLines Line, code
End With
Next
Application.DisplayAlerts = False
VBA.UserForms.Add(objForm.Name).Show
End Sub
Excel Command Button code:
Private Sub CommandButton3_Click()
Call AddButtonAndShow
End Sub
Output: Use an Excel Sheet button to open the newly created Form with buttons.
Initial post:
Please take a look at this post for reference: Excel VBA create a button beside cell.
Possible error due to (object doesn't support property or method), is within the Caption property. As it has to be set with theBttn.Object.Caption
Try this please:
With Butn
.Name = "CommandButton" & i
.Object.Caption = i
.Width = 100
.Left = 300
.Top = 10 * i * 2
End With