I have a label object called Lb1. and a sub:
Private Sub Lb1_Click()
call function(Lb1)
End Sub
But I want to use this function in all other click objects, with a variable as an argument, a variable that should point to the clicked object itself. I dont want to change the argument manually for every click object.
Is there a method in VBA, to identify the clicked object and return the object?
Thank you very much!
Related
When writing a VBA code, I tried to call a Combobox_Change Sub (not Private Sub), which is located in 'Sheet2' of another workbook called 'wb2'.
Call wb2.Sheet2.ComboBox_Change
However, the program returns the runtime error 438. Am I missing anything or can someone proovide a fix? Thanks!
Run-time error 438: Object doesn't support this property or method
Event handlers do one thing: they handle events. That's why they're Private: they never need to be explicitly invoked by any other code - they're invoked by their respective event source, period.
C++
C#
Delphi
If it's bad practice in every language I could be bothered to find a SO post about this for, then why would it be any different in VBA? Hint: it's not, the reasons why explicitly invoking an event handler is a bad idea, are completely language-agnostic (provided your language has a concept of "event").
Don't make them Public and then invoke them explicitly. Instead, have that other code toggle the state of the control, and let the control fire its event - assuming an ActiveX/MSForms control:
Dim ctrl As MSForms.ComboBox
Set ctrl = wb.Worksheets("Sheet2").OLEObjects("ComboBox1").Object
ctrl.Value = Not ctrl.Value
If you don't want to toggle the control's state, only to invoke its handler, then pull the handler's implementation out - instead of this:
Private Sub ComboBox_Change()
'do stuff
End Sub
Do this:
Private Sub ComboBox_Change()
DoStuff
End Sub
Public Sub DoStuff()
'do stuff
End Sub
And then invoke DoStuff like you would any other macro-in-another-workbook.
Note that the Call keyword is completely redundant.
I have a VBA Excel application with about 200ish buttons. I want them all to change one textbox called "Name" with the caption of the button pressed. I did blur some stuff from the image as these boxes are all real peoples name. How can I do this without having to create 200+ functions?
An example is let's say I have 3 buttons. The three values are foo1, foo2, and foo3. When I click any of the buttons, let's say I click foo2, I want the TextBox to update the value to foo2. I know how to do this but how do I do it without having to manually write a function for all 3 buttons. The textbox value will always be the button value. Now imagine it is 200+ buttons.
Thanks!
Here is how I'd approach it. First add a class module and call it buttonClass:
Option Explicit
Public WithEvents aCommandButton As msforms.CommandButton
Private Sub aCommandButton_Click()
MsgBox aCommandButton.Name & " was clicked"
End Sub
Then in your userform initiation event, use code similar to:
Dim myButtons() As buttonClass
Private Sub UserForm_Initialize()
Dim ctl As Object, pointer As Long
ReDim myButtons(1 To Me.Controls.Count)
For Each ctl In Me.Controls
If TypeName(ctl) = "CommandButton" Then
pointer = pointer + 1
Set myButtons(pointer) = New buttonClass
Set myButtons(pointer).aCommandButton = ctl
End If
Next ctl
ReDim Preserve myButtons(1 To pointer)
End Sub
This will wire up all of your command buttons to display their name on click. You can tweak the logic in the buttonClass to be fancier. Or you can tweak the logic in the initialize event to include on certain buttons (expanding on the "If" part).
Hope that helps!
If i was going to do this (and I'm not sure I would), I would create and populate each button through a loop, which also set up a link to one event handler which could determine what to do.
If each button is created manually and already exist, then I think you need to update them manually.
Another possibility, is to catch another higher-level event such as mouse click and then, from the information provided by that event, work out which button was pressed.
This has to be an obvious thing to do, but I want to use the name of a command button that is pressed in excel as a variable in a macro. The macro would be as simple as setting the value of a cell to the name of the button; So if button captioned "10" is pressed the cells value would be "10", the same macro needs to work for all numeral button captions/names.
Again, sorry if this is obvious!
Try this, works with Forms buttons but not ActiveX buttons.
Sub Button1_Click()
If Not IsError(Application.Caller) Then
Dim obj2 As Object
Set obj2 = ActiveSheet.Shapes.Item(Application.Caller)
Debug.Print obj2.AlternativeText
End If
End Sub
but your question asked about command buttons (the ActiveX variety) and this is more involved, we need to find the shape and then drill in via OLEFormat and two layers of IDispatch to get a reference to the command button, then we use WithEvents to fire event handler.
Option Explicit
'* Inside Sheet module
Private WithEvents mcmd As MSForms.CommandButton
Private Sub Initialise()
Dim obj As Object
Set obj = Me.Shapes.Item("CommandButton1")
Set mcmd = obj.OLEFormat.Object.Object
End Sub
Private Sub mcmd_Click()
Debug.Print mcmd.Caption
End Sub
Sadly you need to initialise code like this for every command button I think.
There's a lot of information and a lot that you can do with userforms but I can't really find a standard way to use them. Let's say I have a userform with a standard dropdown list that asks someone to choose a fruit. In the userform code I will put the below code after adding a combo box called fruitcombo:
Private Sub UserForm_Initialize()
userform1.fruitcombo.AddItem "Peach"
userform1.fruitcombo.AddItem "Pear"
userform1.fruitcombo.AddItem "Grape"
End Sub
I will also add a commandbutton which will be labeled "Submit" and in that event:
Private Sub Submit_Click()
Me.Hide
End Sub
That's where it starts to get hazy. What's the best way to capture the answer that was selected? One way I can think would be to make a global variable called fruitanswer and then instead of the Me.Hide we can skip straight to Unload Me
Ex:
Private Sub Submit_Click()
fruitanswer = fruitcombo.value
Unload Me
End Sub
Or we can have fruitanswer as a private variable in the module where the userform is called and then unload it in there. There are also multiple ways to initialize the userform. I'm also wondering the best way to initialize it. The Show method will automatically initialize it, but the Hide method WON'T automatically de-initialize it. For that, the Unload statement is necessary. So does anyone initialize it before calling the Show method using the Load statement?
Ex:
Load userform1 'Any point to including this?
userform1.show
'user chooses a fruit and clicks submit button
'userform is hidden by commandbutton but not unloaded yet
fruitanswer = fruitcombo.value
Unload userform1
Out of these options, which is the best method? Is there anything to make it more efficient?
You can wrap the whole thing in a single function call:
strFruit = UserForm1.GetFruit()
Then, in your UserForm, have it do the work of displaying and unloading itself like so:
Private bOK As Boolean
Public Function GetFruit() As String
bOK = False
Me.Show vbModal
If bOK Then GetFruit = ComboBox1.Text
Unload Me
End Function
Private Sub cmdOK_Click()
bOK = True
Me.Hide
End Sub
Private Sub cmdCancel_Click()
Me.Hide
End Sub
This assumes you have buttons named cmdOK and cmdCancel and a combobox named ComboBox1.
Since Show() is being called modally, the code after it won't execute until the form is closed or hidden. When either button is clicked (or the form is closed by other means) then the code continues, the selected text is returned (if OK was clicked), and the form unloads itself.
The beauty of doing it this way is that your calling code doesn't need to worry about instantiating and destroying the form each time it's called. It's just a single statement to load the form and get the return value.
Of course, you'll need to add the code to populate the combobox with whatever items you wish to display.
When I call SetFocus for my textbox, it throws this error:
Run-time error '438':
Object doesn't support this property or method.
Is SetFocus readily available in Excel 2013 or do I have to patch or update any component of my Excel?
I think Setfocus() probably never throw an error like that!!
Object doesn't support this property or method (Error 438)
This method or property does not exist for this OLE automation object. See the object's documentation for more information on the object and to check the spellings of properties and methods.
Here you have a method SetFocus(), So you need to know when this method does not exist!
In Office 2013 if object or one of its containers is not visible or enable, it throw this error:
Run-time error '2110':
Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus.
And as I tested making loop by raising Enter Event is also don't throw error, And also for similar using SetFocus() method:
Private Sub TextBox1_Enter()
TextBox2.SetFocus
End Sub
Private Sub TextBox2_Enter()
TextBox1.SetFocus
End Sub
And I can't figure any other reason !
Please see this answer: https://www.vbforums.com/showthread.php?646411-RESOLVED-How-can-I-make-setfocus-ot-Textbox-in-vba
You are using Excel after all, but you have the textbox on a worksheet rather than a userform.
Setfocus will work for textboxes on a Userform, but as you have discovered, not if they are on the actual worksheet.
Instead of setfocus try activate:
Private Sub CommandButton1_Click()
TextBox1.Activate
End Sub