I have a userform with multiple pages, each with textboxes that I want to make sure are numbers before I dump them back into a worksheet.
I have other normal userforms that do this:
Private Sub myTextBox_Exit(ByVal Cancel As MSForms.ReturnBoolean)
OnlyNumbers
End Sub
Private Sub OnlyNumbers()
If TypeName(Me.ActiveControl) = "TextBox" Then
With Me.ActiveControl
If Not IsNumeric(.Value) And .Value <> vbNullString Then
MsgBox "Sorry, only numbers allowed"
.Value = vbNullString
End If
End With
End If
End Sub
This works fine, but when I try to do something similar with this multipage userform it doesn't work.
I tried using
Me.ActiveControl.ActiveControl
but get a "Object doesn't support this property or method" run time error. This would work when the textboxes are inside a frame, but it seems like pages are not treated the same way.
Yeah, this one is tricky. The MultiPage control you can think of as the parent of the controls that sit on top of it. What you need to do is select the MultiPage control first, then select the active control from there.
It looks like:
Me.MultiPage1.Pages(Me.MultiPage1.Value).ActiveControl.Name
The Pages property allows you to select which page you want to select. You can get this by using the index of the MultiPage control (the Index starts at 1). Then you can call the ActiveControl and receive the expected control.
Hope it helps!
Related
I have created a userform and included a combobox populated with numbers 1 to x in userform.initialize and then added .setfocus and .dropdown commands. For some strange reason the combobox (with dropdown) appears on my lefthand screen outside the userform. The combobox also appears on the userform, but without the dropdown displayed. The screen combobox is active and if I click a number in the dropdown list the code accepts this input.
I have tried deleting the combobox and inserting another one with a different name, but the behaviour persists. If I remove the .dropdown command, the combobox appears correctly on the userform without the screen copy and I can click the userform box and display and use the dropdown list.
On reading an unrelated post, I tried adding .visible=false, followed by .visible=true before the .dropdown command, but that didn't stop the behaviour.
I have tried exporting, deleting and re-importing the userform, but the behaviour persists.
The code I am using (in userform_initialize sub) is:
With cbxGroup 'combobox
.Clear
For i = 1 To PlayGroups
.AddItem i
Next
.ListIndex = -1
.Visible = False
.Visible = True
.SetFocus
.DropDown
End With
Has anyone come across such behaviour before and can explain what has happened, and maybe how to fix it. I can just recreate the userform, but it seems a lot of unnecessary work. I am using Office 365
I can confirm the behaviour.
I strongly assume that this is related to the fact that you are using the Initialize-Trigger. When this trigger is executed, the form is still in the creation-process and some internal properties (eg the exact screen position) are likely not calculated. As a consequence, when calling DropDown, the Combobox is painted on the screen but not at the right position.
You can keep the code to fill the combobox in the Initialize-Trigger, but you should move the SetFocus and DropDown-commands to the Activate-Trigger
Private Sub UserForm_Initialize()
fillCombo
End Sub
Private Sub UserForm_Activate()
showCombo
End Sub
Sub fillCombo()
With Me.cbxGroup
.Clear
Dim i
For i = 1 To PlayGroups
.AddItem i
Next
.ListIndex = -1
End With
End Sub
Sub showCombo()
With Me.cbxGroup
.SetFocus
.DropDown
End With
End Sub
Hello I am trying to get the selected value from my ComboBox to work in a subroutine in Module1.
Private Sub UserForm_Initialize()
With ComboBox1
.AddItem "Monday"
.AddItem "Tuesday"
End With
End Sub
I'm basically trying to get the value I selected to be pasted onto "Sheet1". I can get this to work if I call "ComboBox1.value" in the UserForm1, but not Module 1 where it throws an error saying "ComboBox1.value" is not defined. I would appreciate any help!
Sub EmailGenerator()
UserForm1.Show
Worksheets("Sheet1").Range("O5").Value = ComboBox1.Value
End Sub()
The form is an object: it's an instance of the class UserForm1 - one that you didn't explicitly create yourself (see UserForm1.Show for everything that entails), but it's an object nonetheless.
There's an instance of a ComboBox control named ComboBox1, living in that UserForm1 object, and exposed on the form's public interface (exactly as if it were a public property of the form itself!) - that's how you're able to access the control from outside the form's code-behind (note: that's the simplest way to do UI, but there are better, more scalable ways that don't break encapsulation like that and leave the form responsible for its controls and the rest of the code blissfully unaware of the layout of the UI and what the specific controls are, see link above).
VBA doesn't know what ComboBox1 you're referring to, unless you qualify that member call with the object it belongs to, using the . dot operator:
UserForm1.ComboBox1
You could have a UserForm2 that also has a ComboBox1 control, and there could be 20 worksheets, each with their own ComboBox1 control: they can't live in global scope, and they don't.
Thus:
Worksheets("Sheet1").Range("O5").Value = UserForm1.ComboBox1.Value
Or better:
Public Sub EmailGenerator()
With New UserForm1
.Show '<~ form is modal, execution is blocked here until form is closed.
Worksheets("Sheet1").Range("O5").Value = .ComboBox1.Value
End With
End Sub
Try this approach, please:
With UserForm1.ComboBox1
.AddItem "Monday"
.AddItem "Tuesday"
.ListIndex = 0
End With
ActiveSheet.Range("I1").value = UserForm1.ComboBox1.value
No necessary to Show the form for doing that. But, if you do not select anything in combo, nothing will be returned in the cell. If you want to do that in consecutive steps, I would recommend to firstly check if the UserForm1.Visible = True. Only supposing that you want to manually change the combo value and only after that to collect values on the sheet.
But this approach is, at least, strange to me... I only tried to show you how it is possible, but I would not recommend it.
I have a Userform with a multipage object. In one of pages there is a textbox object where I want to add a placeholder when Enter event is not detected. Problem is I'm not figure out how to make reference to textbox from Enter and Exit events due to I have a multipage structure.
I tried to adapt the following approach but it works only for a Userform without Multipage structure.
Got it here: Text box prompt text in Excel VBA
Private Sub TextBox1_Enter()
TB_enter ActiveControl.Name
End Sub
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
TB_exit ActiveControl.Name
End Sub
Sub TB_enter(TB_name)
If Len(Me.Controls(TB_name).Tag) = 0 Then
Me.Controls(TB_name).Tag = Me.Controls(TB_name).Value
Me.Controls(TB_name).Value = vbNullString
End If
End Sub
Sub TB_exit(TB_name)
If Len(Me.Controls(TB_name).Value) = 0 Then
Me.Controls(TB_name).Value = Me.Controls(TB_name).Tag
Me.Controls(TB_name).Tag = vbNullString
End If
End Sub
Here is a video that shows how to do it when the Userform don't have a Multipage structure: https://www.youtube.com/watch?v=yJ4fnw1zmGU
Setting up properties Tag and Text of textbox I get the placeholder if use a properly Forecolor (&H8000000) but I can't make it works dynamically, that means: delete placeholder text when Enter event occurs and if lenght (Len) of the string inside textbox is zero when Exit event occurs must show the placeholder string again.
Any suggestions? Thanks in advance.
Problem: I am building a Userform that has a 'Submit' and 'Cancel' button. I want the entire form to clear any entered data and close the form if the user hits the 'Cancel' button but I also am trying to build in the same functionality if the user hits the red 'X' in the top right corner. I'm unclear where I need to unload the form. I currently have it placed within the btnCancel_Click() method and I'm able to launch the form, enter some data and hit Cancel and it will close the form down.
But when I try to re-launch the form a 2nd time I get an error (I attached a picture of that message) that says
"Run-Time error '-2177418105 (80010007): Automation Error - The Callee (server [not server application]) is not available and disappeared; all connections are invalid. The call may have executed.
If I remove Unload Me from btnCancel_Click() then the form can close and re-open just fine, but any data I entered the first time will still be on the form and isn't cleared properly. I'm wondering if this is an Unload Me error or do I need to reset all form controls when I initialize the form?
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' how was the form closed?
' vbFormControlMenu = X in corner of title bar
If CloseMode = vbFormControlMenu Then
' cancel normal X button behavior
Cancel = True
' run code for click of Cancel button
btnCancel_Click
End If
End Sub
'******************************************************************
Private Sub btnCancel_Click()
mbCancel = True
Me.Hide
Unload Me
End Sub
'*********************************************************************
Private Sub UserForm_Initialize()
'Populate values for 2 combo boxes
lastEmp = Sheets("Form_Ref").Cells(Rows.Count, 1).End(xlUp).Row
Me.cmbBoxEmpName.List = Sheets("Form_Ref").Range("A2:A" & lastEmp).Value
lastBld = Sheets("Form_Ref").Cells(Rows.Count, 2).End(xlUp).Row
Me.cmbBoxBuildingName.List = Sheets("Form_Ref").Range("B2:B" & lastBld).Value
End Sub
'******************************************************************
Public form As New CheckOutForm
Sub testFormOptions()
'Button pressed within Excel will start program and show the userform
form.Show
End Sub
This is the easiest quick and dirty solution:
Delete Public form As New CheckOutForm from the code. Then add it in the testFormOptions():
Sub testFormOptions()
Dim form As New CheckOutForm
form.Show
End Sub
Some not-that-good VBA books/tutorials would even go a bit like this, but this is brutal:
Sub testFormOptions()
CheckOutForm.Show
End Sub
Anyway, now the problem with the predefined values in the form is solved.
For the clean and not-so-easy solution, consider writing a MVC framework around the form:
https://codereview.stackexchange.com/questions/154401/handling-dialog-closure-in-a-vba-user-form
this blogpost (disclaimer - mine!), which pretty much says what the above link proposes, but it does not have the errors from the question.
the old StackOverflow tutorial for UserForms
If you execute Unload, you destroy the form object. With other words, your (global) variable form gets invalid and if you issue a new form.show, you get the runtime error.
When, on the other hand, you just unhide the form, the form-object stays valid (it's just currently not visible) and all controls keep their value.
Either you do some housekeeping by resetting all controls when a form is displayed (use the UserForm_Activate-event), or you have to create a new form-object every time you want to display it (I would strongly advice not to use the name form as variable name to avoid confusion).
Sub testFormOptions()
dim myForm as CheckOutForm
myForm.Show
End Sub
So what I'm trying to achieve is to display help text in a TextBox everytime a new field is selected (or gains focus). I am working with Excel 2013 and my Form has multiple tabs (multipage form).
So far here is what I know is possible: Everytime a field is selected, I can use one of the events (i.e. Click) to update the help text in help text box (just for info, help text is held on a worksheet and each field has a tag. I use this tag to pull the help text from the worksheet). What I cant figure out (or find on the web) is how to do this dynamically: so when a new field gets focus, maybe there is a form event I can use to get the ActiveControl and pass it to my sub? (which pulls the help text).
I've tried using Myform.Click (and Multipage.Click) event but that doesn't work when I click on a new field or tab to a new field
Please let me know if I can provide more information
Help much appreciated
Unless I misunderstand what you need, why not something like this?
Private Sub TextBox1_Enter()
UpdateHelp TextBox1
End Sub
Private Sub TextBox2_Enter()
UpdateHelp TextBox2
End Sub
Private Sub TextBox3_Enter()
UpdateHelp TextBox3
End Sub
Private Sub TextBox5_Enter()
UpdateHelp TextBox5 'this is on a multipage control
End Sub
Private Sub TextBox6_Enter()
UpdateHelp TextBox6 'this is on a multipage control
End Sub
Private Sub UpdateHelp(ByRef c As Control)
TextBox4.Text = c.Name
End Sub
You could pass ActiveControl, but for controls on a Multipage control the ActiveControl is the parent control and not the TextBox.