Excel VBA - Calling TextBox Exit Event on Userform manually? - vba

I'm building a userform where it has two text boxes to enter dates. Once the date is entered, I'm validating them when the Exit event fires. If the validation turns up that the user data isn't what is needed, the user is notified, the text box is cleared, and the focus is returned back to the textbox.
The issue comes if the user uses the mouse to select outside of the box, rather than Tab. If Tab is used, it fires perfectly and as expected, and the field is cleared and the focus is returned. If the mouse is used, it doesn't fire. According to this article, this is expected behavior (It's for Access, but I didn't see the similar relevant MSDN article for Excel.)
So instead I tried the AfterUpdate event. However, SetFocus doesn't work within an AfterUpdate event, I'm assuming because of the chain of events as outlined in the response to this question. Thus, I don't have a way to return the focus back to the textbox after it has fired. That thread had a suggestion as an alternate answer to SetFocus to another control and come back as a workaround, but that doesn't work for me, so I assume that may be an Access-specific workaround.
My last option I've considered is having the AfterUpdate event just call the Exit event, however the Exit event has a required argument (ByVal Cancel As MSForms.ReturnBoolean), which is how you cancel out of the exit and return the user to the textbox. As such, there isn't a value that you can pass to it that doesn't throw an error that I can find (the closest I found was passing Nothing but it failed out when trying to set it to True later to cancel the exit.)
Is there a way to achieve what I'm looking for here, or should I just stick to the AfterUpdate and ignore the SetFocus I'm trying to achieve?

I know that this was answered a few months back but giving an alternative solution. For any one who finds this question.
For validation of Excel Textbox data use the BeforeUpdate Event, it fires before the AfterUpdate Event and has the ability to prevent losing Focus on the control.
Rework the sample code to your requirements
Remember Cancel = True stops the control update to the control and it remains in focus.
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Cancel = doValidation(Textbox1.Text) 'Validation Route
End Sub
Private Function doValidation(strText) as Boolean
'Do Validation
if Valid then
doValidation = False
Else
msgBox "Not Valid"
doValidation = True
End if
End Sub
In my opinion this is the easiest way to validate an input on an Excel Userform Textbox
I can't right now find the correct MSDN article at this time, all Google wants to return is Access Results.

Exit event works on all the mouse clicks which fire up Enter for another Control on the Form. But When you click, directly on the form instead of any other control, nothing happens.
Here, use the ActiveControl property to determine about the last control you were in, before exiting and moving to user form.
Sample Code, rework it according to your requirement.
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Call doValidation(Me.TextBox1.Text) '/ Validation Routine when user leaves TextBox
End Sub
Private Sub UserForm_Click()
'/ If user clicked on the user form instead of ay other control
If Me.ActiveControl.Name = Me.TextBox1.Name Then
Call doValidation(Me.TextBox1.Text) '/ Validation Routine when user leaves TextBox
End If
End Sub
Private Sub doValidation(strText)
MsgBox strText
End Sub
Advise: For Date inputs, use DateTimePicker instead of TextBox, will save you from alot of trouble in future.

In VBA you can call any defined sub or function with the word Call Subname:
e.g. Call Textbox1_exit(params)
However from the somewhat confusing description I believe your problem is that you limit yourself to just a few event functions. I would suggest exploring all event functions and see which one is a good fit for your event fire.
Here is a list of events and their sequences in Access VBA:
https://msdn.microsoft.com/en-us/library/office/jj249049.aspx
and the order of form events:
https://support.office.com/en-us/article/Order-of-events-for-database-objects-e76fbbfe-6180-4a52-8787-ce86553682f9
I think for your application from the description you gave the lost_focus or got_focus for certain components might be useful.
Furthermore, you can manually set the focus to almost any component it is a built in method: compName.SetFocus()

Related

Listbox not displaying in UserForm

I'm trying to display a listbox in a UserForm from a separate sheet called "Fields". The problem is, the list will not display. It shows as a drop down arrow next to the cell, but not in the userform like I'm wanting.
Private Sub UserForm_Activate2()
On Error Resume Next
Me.ListBox2.Clear
For Each element In gFieldsListArr
Me.ListBox2.AddItem element
Next element
UserForm_initialize2
End Sub
Private Sub UserForm_initialize2()
For Each element In Split(gCellCurrVal2, ",")
For ii = 0 To ListBox2.ListCount - 1
If element = Me.ListBox2.List(ii) Then
Me.ListBox2.Selected(ii) = True
End If
Next ii
Next element
End Sub
TL;DR: You can't rename event handlers or change their member signature in any way*, because the correct member definition is defined by the event, not its handlers.
Watch the dropdowns at the top of the editor as you navigate between procedure scopes:
Whenever the left-side dropdown says (General), you're not inside an event handler.
Contrast with:
The left-side dropdown is listing all available interfaces and event sources; to handle the events of a form, you must pick UserForm from that dropdown, and then pick a member from the right-side dropdown.
When you do this, the VBE creates the procedure stubs for you, with the correct name and signature every time.
Whenever you navigate to what's intended to be an event handler and the left-side dropdown says (General), you're looking at dead code that isn't responding to any events.
* You may change the accessibility from Private to Public, but invoking an event handler directly is a design smell so there shouldn't be a need to do that. You may change the parameter names, but not their type; renaming handler parameters is a rather surprising thing to do though, and best avoided too. So yeah, best not change these member signatures in any way.

Revert a Checkbox value in the ChkBoxGroup_Click event

I have multiple checkboxes created, and I would like to prompt the users when they CLICK on the checkbox. They can only change the value of the check box with the correct PIN. If they enter a incorrect PIN, the checkbox will revert back to it's original value.
However every time when it try to revert the checkbox value, it seems like it recursively calling the ChkBoxGroup_Click() event until a correct password is entered.
Private Sub ChkBoxGroup_Click()
Dim ValidatePIN_RNT As Boolean
ValidatePIN_RNT = ValidatePIN()
If Not ValidatePIN_RNT Then
ChkBoxGroup.Value = Not ChkBoxGroup.Value
Exit Sub
End If
End Sub
It also work now! I found a post from excelforum.com that the application.enable events setting controls ONLY Workbook and Worksheet events. And from the post it suggested to use global variable. It worked for me!!

In a VBA Userform, which event is triggered when exiting a filed

I'm using Microsoft Office Professional Plus (64 bit) on a Windows 10 (64 bit) platform. I have a subroutine that is processed when I make a change to a Userform field called MyDate. It's called Private Sub MyDate_AfterUpdate(). It's the second field on a form. It works fine as long as the contents of the MyDate field are edited. However, if the user doesn't need to update the contents of the MyDate field because they accept the default of the field and just presses the tab key past that second field, I'd still like the subroutine to be executed. What event can I use to activate code when I simply tab through the field and don't necessarily edit the contents? Thanks for looking at this.
If you look at the top of the code panes, you'll notice two dropdowns. The left one contains all interfaces and event providers you can implement in that class (a UserForm is a class).
Select your MyDate control from that dropdown; the right-side dropdown is now listing every event you could handle for this MyDate control:
In this particular case, the Exit event seems a good candidate:
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'make Cancel.Value = True to prevent exiting the control.
'...ideally... make that conditional...
End Sub
By consistently using these dropdowns to let the VBE generate event handler procedures for you (instead of typing them up from memory), you avoid getting it wrong... and getting an event handler signature wrong can do anything from literally nothing at all, to compile errors if you're lucky, or weird and hard-to-diagnose behavior if you're less lucky.

Button Click vs ShortCut Key (ALT) Event firing order

I have a Save button on a form with a shortcut key set (ALT+S).
In my datagrid in the cellvalidated event I make a determination if I can enable or disable this button for the users.
Similar to the old VB6 problem of Event firing order....
If the button was currently enabled, but user puts invalid data in the datagrid cell. If they Click on the button, the cell validated event fires, disables the button - no issue. When, instead, they input the bad data, and do ALT+S, the cell validated event fires, but in this case the Button_Click event still fires.
Any way to prevent this? Basically if the use the ALT+, I don't want the Click event to fire.
If everything else fails - there is this method (in pseudo-code)
Class Form
private _validated as Boolean
sub Cell_validate
' validate here and set
_validated = true/false
end sub
sub Button_Click
If not _validated then Return
' have your save logic here
end sub
End class
This way you will protect your code from executing actual logic of Button_Click when button disabled.

Access VBA Spell Check One Field of a Subform

I am trying to make a memo field be spell checked when it leaves the field, and when it leaves the subform to the main form. I want to have this done automatically without having a click button, as I need the data to be as accurate and error-free as possible.
In the main form I have used this code to spell check a title field once you move off the field.
Private Sub DetailedTitle_Exit(Cancel As Integer)
'This code works to spellcheck the title after leaving.
With Me!DetailedTitle
If Len(.Value) > 0 Then
DoCmd.SetWarnings False
.SelStart = 1
.SelLength = Len(.Value)
DoCmd.RunCommand acCmdSpelling
.SelLength = 0
DoCmd.SetWarnings True
End If
End With
End Sub
This works well, as users will 99% of the time moving from this field to another field in the main form. This does not work when I use in on the subform even when I use the on exit field event AND the on exit subform event. It seems to work, but if you click around it will actually give an error. I wasn't smart enough to note the error, and I have since removed the code.
I would also not be opposed if I could get it to loop thought the subform, as it is a continuous form, but only that one field.
Any advice or tips would be welcome. I just recently learned of the Do.Cmd.RunCommand acCmdSpelling, but there seems to be a lack of content in regards to subforms. Thanks.
I did some research: http://www.pcreview.co.uk/threads/run-the-spell-check-through-code.1636292/
One user mentions that the control you want to check has to be in focus.
Sub subformMemo_OnExit()
Me.subformMemo.setfocus
DoCmd.RunCommand acCmdSpelling
End Sub
On the other hand this code creates the problem that you cannot leave the control because you will always setfocus on it again.
Does this help?