All,
I have the below code which creates a dynamic userform based on a list located in an excel worksheet. (Please see picture below)
When the user selects submit I would like to extract all the answers from the user form into an excel file.
Does anyone know how I would do this as I have hit a brick wall in thoughts, the user form to my knowledge has to be built via vba as the list of Project ID & UR can vary from 1 line to thousands of lines.
Any help would be much appreciated.
Sub addLabel()
UserForm6.Show vbModeless
Dim theLabel As Object
Dim ComboBox1 As Object
Dim CommandApp As Object
Dim CommandCan As Object
Dim buttonheight As Long
Dim labelCounter As Long
For Each c In Sheets("Sheet1").Range("A1:A100")
If c.Value = "" Then Exit For
Set theLabel = UserForm6.Controls.Add("Forms.label.1", "Test" & c, True)
With theLabel
.Caption = c
.Left = 10
.Width = 50
.Height = 20
.Font.Size = 10
If c.Row = 1 Then
.Top = 34
Else
.Top = 25 + (20 * (c.Row - 1)) + 9
End If
End With
Set ComboBox1 = UserForm6.Controls.Add("Forms.combobox.1", "Test" & c, True)
With ComboBox1
.AddItem "Approved"
.AddItem "Partially Approved"
.AddItem "Not Approved"
.Left = 190
.Width = 120
.Height = 20
.Font.Size = 10
If c.Row = 1 Then
.Top = 30
Else
.Top = 30 + (20 * (c.Row - 1))
buttonheight = 30 + (20 * (c.Row - 1))
End If
End With
Next c
For Each c In Sheets("Sheet1").Range("B1:B100")
If c.Value = "" Then Exit For
Set theLabel = UserForm6.Controls.Add("Forms.label.1", "Test" & c, True)
With theLabel
.Caption = c
.Left = 90
.Width = 70
.Height = 20
.Font.Size = 10
If c.Row = 1 Then
.Top = 34
Else
.Top = 25 + (20 * (c.Row - 1)) + 9
End If
End With
Next c
With UserForm6
.Width = 340
.Height = buttonheight + 90
End With
Set CommandApp = UserForm6.Controls.Add("Forms.Commandbutton.1", "Test" & c, True)
With CommandApp
.Caption = "Submit"
.Left = 10
.Width = 140
.Font.Size = 10
.Top = buttonheight + 30
End With
Set CommandCan = UserForm6.Controls.Add("Forms.Commandbutton.1", "Test" & c, True)
With CommandCan
.Caption = "Cancel"
.Left = 170
.Width = 140
.Font.Size = 10
.Top = buttonheight + 30
End With
End Sub
You will need create variables to hold references to the newly created CommandButtons. By adding the WithEvents modifier you will be able to receive the CommandButton events.
Naming the controls after cell values is problematic. A better solution is to use the MSForms Control Tag property to hold your references. In my example below I add a qualified reference to the target cell.
Changed the subroutines name from addLabel to something more meaningful Show_UserForm6.
Combobox values as they are added.
Userform6 Module
Option Explicit
Public WithEvents CommandApp As MSForms.CommandButton
Public WithEvents CommandCan As MSForms.CommandButton
Private Sub CommandApp_Click()
Dim ctrl As MSForms.Control
For Each ctrl In Me.Controls
If TypeName(ctrl) = "ComboBox" Then
Range(ctrl.Tag).Value = ctrl.Value
End If
Next
End Sub
Private Sub CommandCan_Click()
Unload Me
End Sub
Refactored Code
Sub Show_UserForm6()
Const PaddingTop = 34, Left1 = 10, Left2 = 90, Left3 = 190
Dim c As Range
Dim Top As Single
Top = 34
With UserForm6
.Show vbModeless
For Each c In Sheets("Sheet1").Range("A1:A100")
If c.Value = "" Then Exit For
With getNewControl(.Controls, "Forms.Label.1", Left1, 50, 20, Top)
.Caption = c.Value
.Tag = "'" & c.Parent.Name & "'!" & c.Address
End With
With getNewControl(.Controls, "Forms.Label.1", Left2, 50, 20, Top)
.Caption = c.Offset(0, 1).Value
.Tag = "'" & c.Parent.Name & "'!" & c.Offset(0, 2).Address
End With
With getNewControl(.Controls, "Forms.ComboBox.1", Left3, 120, 20, Top)
.List = Array("Approved", "Partially Approved", "Not Approved")
.Tag = "'" & c.Parent.Name & "'!" & c.Offset(0, 2).Address
.Value = c.Offset(0, 2).Value
End With
Top = Top + 20
Next
Set .CommandApp = getNewControl(.Controls, "Forms.Commandbutton.1", 10, 140, 20, Top + 10)
With .CommandApp
.Caption = "Submit"
End With
Set .CommandCan = getNewControl(.Controls, "Forms.Commandbutton.1", 170, 140, 20, Top + 10)
With .CommandCan
.Caption = "Cancel"
End With
End With
End Sub
Function getNewControl(Controls As MSForms.Controls, ProgID As String, Left As Single, Width As Single, Height As Single, Top As Single) As MSForms.Control
Dim ctrl As MSForms.Control
Set ctrl = Controls.Add(ProgID)
With ctrl
.Left = Left
.Width = Width
.Font.Size = 10
.Top = Top
End With
Set getNewControl = ctrl
End Function
Generally I'd set up classes and collections to hold references to your new controls.
It can work with your current set up though. First off I'll suggest an aesthetic change:
Set the size of your frame to a static size that fits on your screen and add the two command buttons outside of this.
Size the frame so it sits inside the bounds of your form.
Change the ScrollBars property to 2 - fmScrollBarsVertical.
In your code:
Add a new variable
Dim fme As Frame
Set fme = UserForm6.Frame1
Update your references to UserForm6 so they reference fme instead when you add the labels and combobox:
Set theLabel = fme.Add("Forms.label.1", "Test" & c, True)
.
.
Set ComboBox1 = fme.Controls.Add("Forms.combobox.1", "Test" & c, True)
.
.
Set theLabel = fme.Controls.Add("Forms.label.1", "Test" & c, True)
Outside your final loop add this line of code (you may have to play around with the maths to get the correct scroll height):
fme.ScrollHeight = buttonheight + 90
Remove the code that adds the two command buttons (as they're now static outside of the frame).
Now your whole form should sit on the page and you can scroll through the controls.
Double-click your command button to add a Click event to it:
Private Sub CommandButton1_Click()
Dim ctrl As Control
Dim x As Long
For Each ctrl In Me.Frame1.Controls
If TypeName(ctrl) = "ComboBox" Then
x = x + 1
ThisWorkbook.Worksheets("Sheet2").Cells(x, 1) = ctrl.Value
End If
Next ctrl
End Sub
The code will go through each combobox on the form and copy the selected value to Sheet2 in the workbook.
Edit:
All the code incorporating the changes I made.
Sub addLabel()
UserForm6.Show vbModeless
Dim theLabel As Object
Dim ComboBox1 As Object
Dim CommandApp As Object
Dim CommandCan As Object
Dim buttonheight As Long
Dim fme As Frame
Dim c As Variant
Dim labelCounter As Long
Set fme = UserForm6.Frame1
For Each c In Sheets("Sheet1").Range("A1:A100")
If c.Value = "" Then Exit For
Set theLabel = fme.Add("Forms.label.1", "Test" & c, True)
With theLabel
.Caption = c
.Left = 10
.Width = 50
.Height = 20
.Font.Size = 10
If c.Row = 1 Then
.Top = 34
Else
.Top = 25 + (20 * (c.Row - 1)) + 9
End If
End With
Set ComboBox1 = fme.Controls.Add("Forms.combobox.1", "Test" & c, True)
With ComboBox1
.AddItem "Approved"
.AddItem "Partially Approved"
.AddItem "Not Approved"
.Left = 190
.Width = 120
.Height = 20
.Font.Size = 10
If c.Row = 1 Then
.Top = 30
Else
.Top = 30 + (20 * (c.Row - 1))
buttonheight = 30 + (20 * (c.Row - 1))
End If
End With
Next c
For Each c In Sheets("Sheet1").Range("B1:B100")
If c.Value = "" Then Exit For
Set theLabel = fme.Controls.Add("Forms.label.1", "Test" & c, True)
With theLabel
.Caption = c
.Left = 90
.Width = 70
.Height = 20
.Font.Size = 10
If c.Row = 1 Then
.Top = 34
Else
.Top = 25 + (20 * (c.Row - 1)) + 9
End If
End With
Next c
fme.ScrollHeight = buttonheight + 90
End Sub
I want to add n number of text box and one command button during run time of the user form in excel - vba .
While the number 'n' , i am getting through a cell value .
I want to store the data entered ( in the dynamically during run time created text box when the user clicks on Submit button that is also run time created )
in excel sheet .
For i = 1 To ssheet.Cells(2, 2).Value
Set txtB1 = Controls.Add("Forms.TextBox.1")
With txtB1
.Name = "d" & i
.Height = 25
.Width = 150
.Left = 105
.Top = 20 + 10 * i * 4
End With
Set cCont = Controls.Add("Forms.CommandButton.1", "Button", True)
With cCont
.Caption = "Submit"
.Top = 60 + 10 * ssheet.Cells(2, 2).Value * 4
.Left = 105
End With
Here i am able to display as required but unable to trigger the users button click and store values in excel sheet .
So create a userform and add the command button in design time like below
Add the following code in the user form
Private Sub CommandButton1_Click()
For i = 1 To ssheet.Cells(2, 2).Value
ssheet.Cells(i, 5).Value = Controls("d" & i).Value
Next i
Unload UserForm1
End Sub
Private Sub UserForm_Initialize()
If ssheet.Cells(2, 2).Value > 0 Then
For i = 1 To ssheet.Cells(2, 2).Value
Set txtB1 = Controls.Add("Forms.TextBox.1")
With txtB1
.Name = "d" & i
.Height = 25
.Width = 150
.Left = 10
.Top = 30 * (i - 1) + 5
End With
Next i
With CommandButton1
.Caption = "Submit"
.Top = 30 * (i - 1) + 5
.Left = 10
End With
With Me
.Width = 200
.Height = 200
.ScrollTop = 0
.KeepScrollBarsVisible = fmScrollBarsVertical
.ScrollBars = fmScrollBarsVertical
.ScrollHeight = 30 * i + 5
End With
Else
CommandButton1.Visible = False
End If
End Sub
You can then call the userform from workbook module
Private Sub Workbook_Open()
UserForm1.Show
End Sub
When you load the form, the text boxes will be created and aligned based on B2 cell's value
Read all the rows for one column & display on textbox(s) which are created at run time.I am turning over to seek you assistance for below after several attempts which didn't help.
Name
ABC
AB
ABCEF
GHFD
I want all the rows from excel sheet to be shown in textbox just as they appear in sheet for a particular column.I am creating 4 textbox(s) that represent columns & 11 textbox(s) that represent rows. For the first column, I want the data to be displayed as it is in sheet. I am successful in creating text box as per my requirement but not able to display data as per needs. Thanks a ton for help
Public Sub UserForm_Initialize()
Set sh = ThisWorkbook.Sheets("Testing")
sh.Range("F21").Activate
With sh
fatalcount = WorksheetFunction.CountIf(Range("F:F"), "Fatal")
Majorcount = WorksheetFunction.CountIf(Range("F:F"), "Major")
Minorcount = WorksheetFunction.CountIf(Range("F:F"), "Minor")
End With
For jrow = 1 To 11
For i = 0 To 4
Set txtB1 = WtmsFrm.Controls.Add("Forms.TextBox.1")
With txtB1
.Name = "chkDemo" & i
.Height = 20
.Width = 5 + 50 + 5
.Left = 10 + 50 * i + 2
.Top = 15 * jrow + 10
.ControlTipText = "Type of Bug"
End With
Next i
Next jrow
For Each tbox In Frm.Controls
' For counter = 2 To 11
If tbox.Name = "chkDemo" Then
tbox.Value = Sheets("sheet1").Cells(counter, 2).Value ' failing code
tbox.ControlTipText = "Name"
ElseIf tbox.Name = "chkDemo1" Then
tbox.Value = 1
ElseIf tbox.Name = "chkDemo2" Then
tbox.Value = 2
ElseIf tbox.Name = "chkDemo3" Then
tbox.Value = 3
ElseIf tbox.Name = "chkDemo4" Then
tbox.Value = 4
End If
' Next counter
Next
' Initialise the followings
Frm.txtFatal.Value = fatalcount
Frm.txtMajor.Value = Majorcount
Frm.txtMinor.Value = Minorcount
Frm.txtTotoal.Value = fatalcount + Majorcount + Minorcount
End Sub
I don't see you create a textbox named "chkDemo". They all have a number appended. As you take tbox from all controls, there might be a control on your sheet somewhere named "chkDemo" but which is not a textbox. Neither do I see counter declared or initialized. That might also let the code fail.
Note also that with .Name = "chkDemo" & i you give the same name to textboxes because you are also in a For jrow loop.
Could any one direct me in right direction for the following code? I want to create a text box at run time by row & column.The following creates only a row & not multiple rows. I want the columns to remain same & just keep increasing rows. Thanks in advance :)
Dim txtB1 As Control
Dim i
For i = 0 To 4
Set txtB1 = UserForm.Controls.Add("Forms.TextBox.1")
With txtB1
.Name = "chkDemo" & i
.Height = 20
.Width = 50
.Left = 30 * i * 2
.Top = 15
.ControlTipText = "Type of Bug"
End With
Next i
You need a For loop for each dimension (rows and columns).
Dim txtB1 As Control
Dim i, jrow
For jrow = 1 To 5
For i = 0 To 4
Set txtB1 = UserForm.Controls.Add("Forms.TextBox.1")
With txtB1
.Name = "chkDemo" & i
.Height = 20
.Width = 50
.Left = 50 * i + 2
.Top = 20 * jrow + 15
.ControlTipText = "Type of Bug"
End With
Next i
Next jrow
Result:
I created a userform with a multipage. On one of the multipages I have a combination of TextBoxes and ComboBoxes. There are a total of 9 Boxes next to each other. They are all control sourced to the excel sheet behind it. When a user enters data into the the first box, it dynamically creates another 9 boxes which correspond to the next row. This process repeats. Now, the 9th box is a TextBox which the visibility is set to false. The 8th box is a ComboBox. If the value in the 8th box is "Existing" Then the visibility of the 9th Box is True.
This is how I'm dynamically created the additional TextBoxes/ComboBoxes:
Private Sub Worksheet_Change(ByVal Target As Range)
Select Case Left(Target.Address, 2)
Case Is = "$A"
Dim cCntrl As Control
Dim i As Integer
For i = 0 To 8
//skipping to case 7 and 8
Case Is = 7
Set cCntrl = UserForm1.Frame13.Controls.Add("Forms.ComboBox.1", "Login" & i & Target.Row + 1, True)
With cCntrl
.Width = UserForm1.ComboBox240.Width
.Height = UserForm1.ComboBox240.Height
.Top = (10 + UserForm1.ComboBox240.Height) * (Target.Row - 1)
.Left = UserForm1.ComboBox240.Left
.ControlSource = "'Multi Branch'!" & Chr(65 + i) & Target.Row + 1
.List = Worksheets("Setup").Range("BILLING").Value
.Style = fmStyleDropDownList
End With
Case Is = 8
Set cCntrl = UserForm1.Frame13.Controls.Add("Forms.TextBox.1", "Login" & i & Target.Row + 1, True)
With cCntrl
.Width = UserForm1.TextBox287.Width
.Height = UserForm1.TextBox287.Height
.Top = (10 + UserForm1.TextBox287.Height) * (Target.Row - 1)
.Left = UserForm1.TextBox287.Left
.ControlSource = "'Multi Branch'!" & Chr(65 + i) & Target.Row + 1
.Name = "BTwo" & (Target.Row - 1)
.Visible = False
End With
End Select
Next
Here is how I am currently changing the visibility:
Case Is = "$H"
If Target.Value = "Existing" Then
UserForm1.Controls("BTwo" & Target.Row - 2).Visible = True
Else
If Target.Row = 2 Then Exit Sub
UserForm1.Controls("BTwo" & Target.Row - 2).Visible = False
End If
End Select
This method technically works, but only after I leave the 8th box. This seems like an OnExit sort of move. The first row i simply did an onchange event which works fine. Any thoughts as to how I can change the visibility on change WITHOUT having to select another box?