How to pass control values between userform events? - vba

I'm struggling with a userform (called Label_Select) that I created.
I'm initializing the userform with some text boxes and check boxes and assigning some values in them.
Then I have a OK button on the userform that was created at design mode (I can create this button at runtime if that helps).
I need to use the text boxes and check boxes values in the code of the OK_Click, refer below.
Currently I get a "Sub or Function not defined" for the OK_Click sub.
How can I pass the text boxes and check boxes values between the userform initialize code and other click events of the userform?
Thank you for your responses
Private Sub UserForm_Initialize()
Dim LotBox(500) As MSForms.TextBox
Dim SensorCheckBox(500) As MSForms.CheckBox
For i = 1 To 4
For j = 1 To 4
k = i + (4 * j)
Set LotBox(k - 4) = Label_Select.Controls.Add("Forms.TextBox.1")
Set SensorCheckBox(k - 4) = Label_Select.Controls.Add("Forms.CheckBox.1")
With LotBox(k - 4)
.Top = 250 + i * 25
.Left = (j * 80) - 50
.Width = 40
.Height = 30
.Font.Size = 14
.Font.Name = "Calibri"
.SpecialEffect = fmSpecialEffectSunken
.Value = k
.AutoSize = True
End With
With SensorCheckBox(k - 4)
.Top = 246 + i * 25
.Left = (j * 80) - 8
.Height = 30
End With
If LotBox(k - 4).Value = " " Then
Label_Select.Controls.Remove LotBox(k - 4).Name
Label_Select.Controls.Remove SensorCheckBox(k - 4).Name
End If
Next j
Next i
End Sub
Private Sub OK_Click()
Worksheets("Sheet1").Cells(1,1)=LotBox(1).Value
Worksheets("Sheet1").Cells(2,1)=SensorCheckBox(1).Value
End Sub

Try making LotBox and SensorCheckBox public variables

You've declared LotBox and SensorCheckBox within UserForm_Initialize, so as soon as that sub ends they will both go out of scope.
Move them up to the top of the module as Global variables.

Related

How to capture event of multiple Dynamic control in VBA

From a previous post I learned a way to populate a userform with a grid of textboxes:
Dim Grid(1 To 10, 1 To 5) As MSForms.TextBox
Private Sub UserForm_Initialize()
Dim x As Long
Dim y As Long
For x = 1 To 10
For y = 1 To 5
Set Grid(x, y) = Me.Controls.Add("Forms.Textbox.1")
With Grid(x, y)
.Name = "TextBox_" & x & "_" & y
.Width = 50
.Height = 20
.Left = y * .Width
.Top = x * .Height
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
End With
Next y
Next x
End Sub
Now, I need to run certain code when I change the contents of any textbox in columns 5 and 6. But since the textbox won't exist until after Initialize is run, their Change events don't exist either.
So I need to either:
Write the change events in advance, since I know the names of the textboxes in advance.
Use an event that will trigger whenever I click any textbox, and be able to identify the textbox in question.
If the only way to do this is by using a class module, please explain it carefully, since I've never actually used one.
EDIT: The answers from #TinMan and #Storax work a little too well. The code reacts to every keystroke in the textbox, but I really need to wait until the user is finished typing. There's no "Exit" event for the textbox when it's in the class module. Any thoughts?
You'll need to create a class to listen for the changes.
Class: TextBoxListener
Public WithEvents TextBox As MSForms.TextBox
Public UserForm As Object
Private Sub TextBox_Change()
UserForm.TextBoxGridChange TextBox
End Sub
Userform
With a few modifications you can use the Grid() to hold the TextBoxListeners references.
Option Explicit
Private Grid(1 To 10, 1 To 5) As New TextBoxListener
Public Sub TextBoxGridChange(TextBox As MSForms.TextBox)
Debug.Print TextBox.Value
End Sub
Private Sub UserForm_Initialize()
Dim x As Long
Dim y As Long
For x = 1 To 10
For y = 1 To 5
With Grid(x, y)
Set .TextBox = Me.Controls.Add("Forms.Textbox.1")
Set .UserForm = Me
With .TextBox
.Name = "TextBox_" & x & "_" & y
.Width = 50
.Height = 20
.Left = y * .Width
.Top = x * .Height
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
End With
End With
Next y
Next x
End Sub
Just a simple example how the class could look like for the textboxes. I named the class clsTextBoxes
Option Explicit
Public WithEvents tb As MSForms.TextBox
' just to keep track of the box in the grid
Public x As Long
Public y As Long
' Just a simple example for the change event.
' you could use x and y to tell the different textboxes apart
Private Sub tb_Change()
Debug.Print tb.Text, x, y
End Sub
You have to adjust your code in the userform like that
Option Explicit
Dim Grid(1 To 10, 1 To 5) As MSForms.TextBox
' Collection to save all the textboxes in the grid
Dim colTxt As New Collection
Private Sub UserForm_Initialize()
Dim x As Long
Dim y As Long
Dim cTxt As clsTextBoxes
For x = 1 To 10
For y = 1 To 5
Set Grid(x, y) = Me.Controls.Add("Forms.Textbox.1")
' create an new clsTextBoxes
Set cTxt = New clsTextBoxes
' save a pointer to the just created textbox
Set cTxt.tb = Grid(x, y)
' store the postion
cTxt.x = x
cTxt.y = y
' add it to the collection
colTxt.Add cTxt
With Grid(x, y)
.Name = "TextBox_" & x & "_" & y
.Width = 50
.Height = 20
.Left = y * .Width
.Top = x * .Height
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
End With
Next y
Next x
End Sub
Look at the comments for a short explanation

Microsoft ActiveX Controls

Is there a way to change the index value of a ActiveX Button that inserted onto a spreadsheet. I currently have four buttons and two are hidden and two are visible. I would like to re-order the them to not have a large gap between objects. I have some VBA code that runs when the document is opened to ensure that they are the right size and location. Because it loops through the OLEObjects Collection; it will not matter what order they are in on the spreadsheet they will always appear with a gap because of the index value in the OLE Object collection. Below is the code:
Private Sub Workbook_Open()
Application.ErrorCheckingOptions.EvaluateToError = False
ActiveWorkbook.Worksheets("SITE").Activate
Dim button As OLEObject
Dim name As String, top As Integer
top = 15
For Each button In ActiveWorkbook.Worksheets("SITE").OLEObjects
Debug.Print button.name & " " & button.ZOrder
name = button.name
If button.OLEType = xlButtonOnly And InStr(name, "btn") = 1 Then
With button
.Height = 21.75
.Width = 174.75
.Left = 1114.5
.top = top
End With
top = top + 30
End If
Next button
End Sub
If you give them proper names with an integer code in it reflecting their intended position (e.g.: "btn...01", "btn...02",...) then you could try this code (sorry for not being able to format it as code by now):
Private Sub Workbook_Open()
Application.ErrorCheckingOptions.EvaluateToError = False
ActiveWorkbook.Worksheets("SITE").Activate
Dim button As OLEObject
Dim name As String
Dim btnRnk As Long
For Each button In ActiveWorkbook.Worksheets("SITE").OLEObjects
name = button.name
If button.OLEType = xlButtonOnly And InStr(name, "btn") = 1 Then
btnRnk = CLng(Right(name,2))
With button
.Height = 21.75
.Width = 174.75
.Left = 1114.5
.top = 15 + (btnRank - 1) * 30
End With
End If
Next button
End Sub

RE: Getting the name of the object onFocus & Adding Caption to a Button dynamically Created

I have written VBA code for Dynamically creating textboxes and buttons. The following is the code when I hit an "Add" button on the userform.
Dim oTxtBox As Control
Dim oBrwsBtn As Control
Dim oCaption As Control
Dim oTxtLen As Integer
oTxtLen1 = TextBox1.Width
oTxtBrth1 = TextBox1.Height
oTxtPos1 = TextBox1.Left
oButLen = CommandButton1.Width
oButBrth = CommandButton1.Height
oTxtLen2 = TextBox2.Width
oTxtBrth2 = TextBox2.Height
If i = Empty Then
i = 1
End If
Set oTxtBox = Me.Controls.Add("Forms.TextBox.1")
Set oBrwsBtn = Me.Controls.Add("Forms.CommandButton.1")
Set oCaption = Me.Controls.Add("Forms.TextBox.1")
With oTxtBox
.Left = oTxtPos1
.Top = oTxtBrth1 + 18 + (oTxtBrth + 18) * (i - 1)
.Width = oTxtLen1
.Height = oTxtBrth1
End With
With oBrwsBtn
.Left = oTxtPos1 + oTxtLen1 + 18
.Top = oTxtBrth1 + 18 + (oTxtBrth + 18) * (i - 1)
.Width = oButLen
.Height = oButBrth
End With
With oCaption
.Left = oTxtPos1 + oTxtLen1 + 18 + oButLen + 18
.Top = oTxtBrth1 + 18 + (oTxtBrth + 18) * (i - 1)
.Width = oTxtLen2
.Height = oTxtBrth2
End With
i = i + 1
Q1 Now How to Edit the caption of the browse Button which I create dynamically No method .Caption with oBrWsBtn
And Q2: How to get the value when the focus is changed
For example When I click on 'TextBox1' Object. A variable should assign itself with the name (i. e. var(str) = focus object name)
Thanks in advance
Q1: Why don't you try defining the control type more specifically and see if that permits you to use the .Caption method. Don't understand why it's not working now, but maybe the Control object type doesn't have the .Caption method because not all controls have captions.
Try:
'at the top of the sub:
Dim oBrwsBtn as CommandButton
'then later
Set oBrwsBtn = Me.Controls.Add("Forms.CommandButton.1")
Another option to consider would be to create these buttons and just have them be invisible until needed. But that assumes you don't actually have a good reason to create them dynamically, which you may have.
Q2: Use a control_AfterUpdate sub:
'Dim this wherever appropriate for scope. Could be in the afterupdate sub if that works.
dim TextBox1_Value as string
Private Sub TextBox1_AfterUpdate()
TextBox1_Value = TextBox1.value
End Sub

Add click event to optionbutton

I have a Outlook 2013 macro where I made a form pop up. All objects (buttons, textboxes, optionsbuttons) get added by the code behind in a form.Load() event.
The form has two option buttons with yes/no. If no is pressed then some other buttons, textboxes should be disabled. My question is how to archieve that a event handler is added to these two buttons?
My programmatically added buttons:
y = y + 30
x = 230
Set btnOppYes = Me.Controls.Add("Forms.OptionButton.1", "btnOppYes")
With btnOppYes
.Caption = "Ja"
.Left = x
.Top = y
.Width = 110
.GroupName = "OppYesNo"
End With
x = x + 110
Set btnOppNo = Me.Controls.Add("Forms.OptionButton.1", "btnOppNo")
With btnOppNo
.Caption = "Nein"
.Left = x
.Top = y
.Width = 110
.GroupName = "OppYesNo"
.Value = True
End With
I tried to add this code, but with no success. There's no msgbox like "test", when I click on the option button:
Sub btnOppYes_Click()
MsgBox ("test")
End Sub
The event isn't associated with the button when its added dynamically and Outlook doesn't allow access to the CodeModule like Excel does. Here is a workaround.
Paste this code in your userform
Dim clsbtnOpp As New Class1
Private Sub UserForm_Initialize()
Dim btnOppYes As MSForms.OptionButton
Dim btnOppNo As MSForms.OptionButton
y = y + 30
x = 230
Set btnOppYes = Me.Controls.Add("Forms.OptionButton.1", "btnOppYes")
With btnOppYes
.Caption = "Ja"
.Left = x
.Top = y
.Width = 110
.GroupName = "OppYesNo"
End With
Set clsbtnOpp.btnOppYes = btnOppYes
x = x + 110
Set btnOppNo = Me.Controls.Add("Forms.OptionButton.1", "btnOppNo")
With btnOppNo
.Caption = "Nein"
.Left = x
.Top = y
.Width = 110
.GroupName = "OppYesNo"
.Value = True
End With
Set clsbtnOpp.btnOppNo = btnOppNo
End Sub
And create a new class called Class1 and paste this code in it
Public WithEvents btnOppYes As MSForms.OptionButton
Public WithEvents btnOppNo As MSForms.OptionButton
Private Sub btnOppYes_click()
MsgBox "You clicked yes"
UserForm1.TextBox1.Enabled = True
End Sub
Private Sub btnOppNo_click()
MsgBox "You clicked no"
UserForm1.TextBox1.Enabled = False
End Sub
Run your form and test. You can play around with this and tailor it to your needs

adding controls to a container programmatically

I have made a user control that contains a panel and i want to add another control that i made to it. All of this i want it to be realised programmatically.
Actualy i wanted to create a Calandar, sizable columns, and cells.
I Want to add my cells to my columns. then add my columns to my Calendar object.
Here is the code i created for the momment..
Creating the columns:
Private Sub CreateColumns()
For i = 0 To Calendar.GetUpperBound(0)
ASFColumns(i) = New ASFcolumn
With ASFColumns(i)
.Width = 252
.Visible = True
.Left = 250 * i + i + 2
.Top = 35
End With
Me.Controls.Add(ASFColumns(i))
'AddHandler Calendar(i, j).Click, AddressOf ClickOnCells
Next
End Sub
Adding my cells to it
For i = 0 To Calendar.GetUpperBound(0)
For j = 0 To Calendar.GetUpperBound(1)
Calendar(i, j) = New ASFmultiTaskCell
With Calendar(i, j)
.Width = 250
.Visible = True
.Left = 250 * j + j + 2
.Top = 33 * i + i + 70
.BringToFront()
End With
'Me.Controls.Add(Calendar(i, j))
ASFColumns(i).Controls.Add(Calendar(i, j))
AddHandler Calendar(i, j).Click, AddressOf ClickOnCells
Next
Next
Thank you
I'm not quite sure what you are trying to do, so I assumed some things. I created Calendar as a 2d array of ASFmultiTaskCell, which is a user control. The follow code sucessfully add the user controls to either a Form or a Panel/Group Box. The event works too.
Dim Calendar(2, 3) As ASFmultiTaskCell
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i = 0 To Calendar.GetUpperBound(0)
For j = 0 To Calendar.GetUpperBound(1)
Calendar(i, j) = New ASFmultiTaskCell
With Calendar(i, j)
.Width = 250
.Visible = True
.Left = 250 * j + j + 2
.Top = 33 * i + i + 70
.BringToFront()
End With
Me.Controls.Add(Calendar(i, j))
GroupBox1.Controls.Add(Calendar(i, j))
AddHandler Calendar(i, j).Click, AddressOf ClickOnCells
Next
Next
End Sub
Private Sub ClickOnCells()
End Sub