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
Related
I have an Outlook userform to show selected emails.
Since listboxes cannot have text in the column-headers, I adapted the solution proposed here.
My Problem:
After intialization of the form, the header-box is at a wrong position and with a wrong size. Some checks show, that the correct values are allocated by the function createListboxHeader() - and without error. But checking the header-box's position and size after that function (back in initialization), the values are wrong - prove of what I see.
Sometimes it works correctly, but most of the times not.
Code:
Public Sub createListboxHeader(lstBody As ListBox, arrHeaders)
Dim lstHeader As ListBox
Dim i As Integer
'create new listbox for the header
Set lstHeader = Me.Controls.Add("Forms.ListBox.1","NameOnlyForTesting")
With lstBody
'ensure properties of body-listbox
.ColumnHeads = False
.ZOrder (1)
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
End With
With lstHeader
'properties of header-listbox
.BackColor = RGB(200, 200, 200)
.Enabled = False
.ZOrder (0)
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
'make column equal
.ColumnCount = lstBody.ColumnCount
.ColumnWidths = lstBody.ColumnWidths
'add header elements
.AddItem
For i = 0 To UBound(arrHeaders)
.List(0, i) = arrHeaders(i)
Next i
'positioning of header-listbox
.Height = 10
.Width = lstBody.Width
.Left = lstBody.Left
.Top = (lstBody.Top - lstHeader.Height) - 0
Debug.Print lstBody.Width, lstHeader.Height ' <-- show both '400'
End With
End Sub
Usage:
Private Sub UserForm_Initialize()
'find emails
Dim selEmails As Outlook.Selection
Set selEmails = getSelectedEmails() 'function not displayed here at StackOverflow
'show emails in List-Box
Call printSelectedEmailsInList(selEmails)
End Sub
Private Sub printSelectedEmailsInList(selectedEmails As Outlook.Selection)
Dim objEmail As Outlook.MailItem
Dim intCounter As Integer
Dim arrHeaders() As Variant
With Me.lstSelectedEmails
'configure listbox
.Clear
.ColumnCount = 5
.ColumnWidths = "70;100;100;200;100"
'configute header (AFTER body!)
arrHeaders = Array("Date", "From", "To", "Subject", "Folder")
Call createListboxHeader(Me.lstSelectedEmails, arrHeaders)
MsgBox Me.Controls("NameOnlyForTesting").Width '<-- shows'78' instead of '400'
'fill list with emails
intCounter = 0
For Each objEmail In selectedEmails
.AddItem
.List(intCounter, 0) = objEmail.SentOn
.List(intCounter, 1) = objEmail.SenderName
.List(intCounter, 2) = objEmail.To
.List(intCounter, 3) = objEmail.Subject
.List(intCounter, 4) = objEmail.Parent.Name
intCounter = intCounter + 1
Next
End With
End Sub
I solved my problem, by changing:
Private Sub UserForm_Initialize()
[...]
End Sub
to:
Private Sub UserForm_Activate()
[...]
End Sub
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
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
I dynamically defined checkboxes, which are added to the userform on runtime.
Sub Userform_Initialize()
For i = 1 To 4
Set Chk = Frame4.Controls.Add("Forms.Checkbox.1", "Checkbox" & i)
With Chk
.top = 84 + k
.left = 336
.Width = 100
.Height = 18
.Caption = "Add item"
.Visible = True
End With
k = k + 24
Next i
End Sub
Public WithEvents Chk As MSForms.CheckBox
Private Sub Chk_Click()
MsgBox Chk
End Sub
For some reason, the event doesn't respond. Does anyone have an idea as to why? I need the boolean of the checkbox. That means when the user clicked on a dynamic checkbox, then I see "True" returned in the msgbox.
Add a class module to your project, name it as you want (say "ChkBox"), and put this code in it:
Public WithEvents Chk As MSForms.CheckBox
Private Sub Chk_Click()
MsgBox Chk.Value
End Sub
In your userform code, add this
Dim myChks(1 To 4) As New ChkBox '<--| this must be at the very top of your userform code pane
Sub Userform_Initialize()
Dim i As Long, k As Long
With Me.Frame4.Controls
For i = 1 To 4
With .Add("Forms.Checkbox.1", "Checkbox" & i)
.Top = 84 + k
.Left = 336
.Width = 100
.Height = 18
.Caption = "Add item"
.Visible = True
Set myChks(i).Chk = .Parent.Item(.Name)
End With
k = k + 24
Next i
End With
End Sub
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