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.
Related
Excel allows to start with a Modeless form and then display a Modal (but not the other way around)
I have an app with 4 Userforms : UF1 - Select a partner, UF2 - List existing transactions, UF21 - Display an existing transaction, UF22 - Make a new transaction. UF21 and UF22 both stem from UF2.
UF21 needs to be Modeless in order to display more than one transactions and compare side by side, therefore UF1, UF2 and UF21 are all Modeless. But I want UF22 to be Modal in order to issue one new transaction at a time.
My problem is that after I close UF22, even just ESCaping from the form right off the bat, all previous forms close. I should be able to return to UF2. If I make UF22 Modeless all is ok.
I have written a function to traverse the UserForms Collection and I am able to get a reference to the object of the Form I want to activate. So, I am able to return (in debug mode) to UF2 which is a listbox, activate the list box, but after the last pending statement both UF2 and UF1 close.
Is what I am trying to do impossible due to the nature of the Modal and Modeless forms or should I keep pushing for the correct code?
Since my original question is still open and my tested implementation of the proposed solution by #PeterT is not working properly, I include the code I have for the moment, based on #PeterT 's suggestion.
'===============
' Form UF1
'===============
Private Sub UserForm_Activate()
If ActivateUF22(FormID) = True Then Exit Sub
'.... more commands
End Sub
'============
' Form UF2
'============
Private Sub UserForm_Activate()
If ActivateUF22(FormID) = True Then Exit Sub
'.... more commands
End Sub
'----------------
Private Sub Cbn_OpenUF22_Click()
If ActivateUF22() = True Then
Exit Sub
Else
With New UF22
.Show vbModeless
End With
End If
End Sub
'================
' In a Module...
'================
Public Function ActivateUF22() As Boolean
Dim frm As Object
Set frm = GetFormFromID("UF22*") ' Custom function to get a form Object based on
' some criterion (FormID in a hidden TextBox)
If Not frm Is Nothing Then
' the only way I know to *Activate* an already .Show(n) form and compensate
' for the fact that the Close CommandButton may already have Focus
frm.TBx_UF22_CODE.SetFocus
frm.CBn_UF22_CLOSE.SetFocus
ActivateUF22 = True
Else
ActivateUF22 = False
End If
End Function
Well I finally managed to get the workaround to behave.
The remaining problem was the fact that clicking twice in a row on the same userform, besides the "Modal" one, would succeed and allow the user to break out.
I even tried the "AppActivate Application.caption" approach found in another SO thread but that didn't work either.
The only solution that works and does not bother me is to insert a MsgBox with a warning to the user, as such:
Public Function ActivateUF22() As Boolean
Dim frm As Object
Set frm = GetFormFromID("UF22*") ' Custom function to get a form Object based on
' some criterion (FormID in a hidden TextBox)
If Not frm Is Nothing Then
' the only way I know to *Activate* an already .Show(n) form and compensate
' for the fact that the Close CommandButton may already have Focus
frm.TBx_UF22_CODE.SetFocus
frm.CBn_UF22_CLOSE.SetFocus
ActivateUF22 = True
MsgBox("You cannot move away from this form until it is either completed or cancelled")
Else
ActivateUF22 = False
End If
End Function
Displaying the MsgBox does the trick internally, switches the focus to a different form from the one clicked and, upon return, the UserForm.Activate event fires normally and the ActivateUF22 function prevents the user from escaping the Pseudo-Modal form.
Thanks #PeterT for pointing me to a workaround. I managed to do what I set out to do, albeit in a different manner.
PS I still believe that there is a way to switch from a Modeless form to a Modal one. After all the MsgBox I use is obviously a Modal form and works just as I would like ;-)
EDIT: I'm using the ActiveX combo box.
I have been trying for a while to use different solutions that I've found here here and here but none of the examples seem to work to me. They don't explicitly make it clear where exactly to put
With Sheet1.ComboBox1
.AddItem "Paris"
.AddItem "New York"
.AddItem "London"
End With
and anywhere I try to put them, nothing gets added to my combo box.
Furthermore, many of these tutorials seem to be using Userforms. I'm not interested in having a userform, I simply want a combo box with a few options in my Excel spreadsheet, which depending on which value a user chooses in the combo box, a cell changes its value. All that I want to do is to write something like this:
Private Sub ComboBox1_Change()
.AddItem "Yes"
.AddItem "Average"
.AddItem "No"
End Sub
And then something along the lines of:
if ComboBox1 = "Yes"
then Range("D2").Value = 1
If you want the ComboBox to load when the worksheet activates use this in the Worksheet Object in VBA: (this may cause the ComboBox to load dupicate entries when switching back and forth between sheets.)
Private Sub Worksheet_Activate()
With ComboBox1
.AddItem "Paris"
End With
End Sub
Or you can place it in a standard module and call it when ever you need to: (this is my preferred method except I would use data validation, since its easier to maintain.)
Sub LoadCombo()
With Sheet1.ComboBox1
.AddItem "Paris"
End With
End Sub
So I need help finishing up a app lookup on elements from the periodic table. The idea if to have the user input the element in the combo box in Userform1 which has a drop down list. To then depending on the element chosen be directed to Userform2 that has a text box, and in that text box be given the atomic mass for each element . I need an example of how and where to write the code in either userfroms. This is what i have so far.
UserForm1 name is Element_LookUp
Userform2 Name is Element_LookUp_Result
Userform1 :
Private Sub CommandButton1_Click()
Unload Me 'Closes The Screen after the click
Element_LookUp_Result.Show 'Shows The result scrren in a new pop up
End Sub
Private Sub UserForm_Initialize()
' All 118 Elements will be shown on a drop down list
' The elements are in order ; autofill helps input the element.
ComboBox1.AddItem "Hydrogen"
ComboBox1.AddItem "Helium"
ComboBox1.AddItem "Lithium"
ComboBox1.AddItem "Beryllium"
ComboBox1.AddItem "Boron"
ComboBox1.AddItem "Carbon"
End Sub ' Not all the elements are listed below i just wanted to save time
UserForm 2 :
Private Sub UserForm_Terminate()
Unload Me 'Once the (X) is clicked the result screen goes away
Element_Lookup.Show 'Result scrren goes back to the input screen again
End Sub
As you're maintaining data from different userforms/modules, etc., I believe you're looking to have a global variable... At the top of the module for your userform (for the purpose of this post, will say UF1 is userform1, UF2 as userform2), you will put (not inside of a subroutine):
Public ElementName as String
Now, in your commandbutton1_click:
ElementName = Combobox1.Value
In UF2 initilize subroutine, you will put something like:
Textbox1.value = UF1.ElementName
The above example would be how to just pass the variable. You could also use ElementName such as:
Textbox1.Value = Application.Index(OutputRange,Application.Match(UF1.ElementName,LookupRange,0))
With that index/match you have used ElementName to find an output, where you would want the column for atomic mass.
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!
I have a combobox on my userform that should be changed by the vba codes, but I dont want any user to be able to type values, only the vb should have this power, the user should only be able to select values.
Any ideas?
As suggested by Chris, add the items and then set a default value for the box, however, don't set locked, by selecting the combobox in this box select the yellow option.
Just change the "Locked" property to True. It will prevent the user from changing the value: however VBA will still be able to. For example, the following code locks the ComboBox; then adds two values and selects one:
Private Sub UserForm_Initialize()
With ComboBox1
.Locked = True ' Prevents the user changing anything
.AddItem "Hello"
.AddItem "World"
.Value = "Hello" ' Sets the value with VBA
End with
End Sub