Excel VBA UserForm TextBox Does Not Recognise Exit - excel

Hopefully this is a simple one for somebody out there. I have an Excel VBA UserForm with a number of text boxes for the entry of parameters. In addition, there is an image on the userform. As the user clicks into a textbox, the image on the UserForm is changed by triggering the _Enter() event to show an image of the parameter in question. This works fine and is not a problem. However, as the user exits the textbox, I want the image to revert back to the original image. I've tried the Events for _Exit() and _AfterUpdate() to make this work and although it works fine if I update the parameter, it doesn't work if I don't update the parameter. In essence, the image changes as I enter the text box but doesn't change as I leave unless I update the value in the text box.
Does anybody have any ideas why this is so and what I might be able to do about it?
Update (with code as requested). I've now figured out that the textbox Exit event is not being triggered because I have more than one frame on my UserForm and I am clicking on a control in a different frame. I've made the following example.
and the following code;
Option Explicit
Dim TextBox1Data As Variant, TextBox2Data As Variant
Private Sub TextBox1_AfterUpdate()
TextBox1Data = TextBox1.Value
Debug.Print "AfterUpdate Textbox 1"
End Sub
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Debug.Print "Exit Textbox 1"
End Sub
Private Sub TextBox2_AfterUpdate()
TextBox2Data = TextBox2.Value
Debug.Print "AfterUpdate Textbox 2"
End Sub
Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Debug.Print "Exit Textbox 2"
End Sub
Private Sub UserForm_Initialize()
ComboBox1.List = Array("Item 1", "Item 2", "Item 3", "Item 4")
ComboBox1.Text = ComboBox1.List(1)
End Sub
If I click into TextBox1 and then click into either ComboBox1 or CheckBox1, the Exit event for TextBox1 is triggered. However, if I click into TextBox1 and then click into either CheckBox2 or CheckBox3, the event is not triggered. I assume that this is because the CheckBoxes are in a different frame. Is this the case? Is there a way of triggering an Exit event for a TextBox when moving from one frame to another?

It seems like this is a known problem - see Microsoft Q210734. Rather than use the Set Focus method suggested by MS, I've now added an Event for exiting the Frame where the textboxes are located, e.g. using my example code, I added the following;
Private Sub Frame1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Debug.Print "Exiting Frame"
End Sub
What happens now is that when moving from one control to another within Frame1, the normal Exit event for the control works as expected and when moving from Frame1 to Frame2, the Exit event for the frame works.
Hope this helps someone in the same predicament.

Related

Excel Userform Run-Time Error when trying to launch a 2nd time after initial 'Cancel' or close on red 'X'

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

Set focus on UserForm Textbox on tabbing from another Textbox

I have a Userform in Excel. It has 6 Textboxes, they are the only controls on the Userform with TabStop set to True.
I can tab and move through the textboxes. I cannot get SetFocus to work on Events fired when moving between the Textboxes. I can put a CommandButton on the userform with Userform16.Textbox1.Setfocus and it works as expected to move the focus to Textbox1.
I set up a simple test event (see below) to move the textbox focus back up to TextBox1 when Textbox2 is entered. It moves focus to Textbox3 when I tab out of TextBox1.
Private Sub TextBox2_Enter()
Cancel = True
UserForm16.TextBox1.SetFocus
End Sub
By putting a Stop in the above, I can see that the event is firing as expected, but it will not allow me to control the focus the next control.
I get the same results with or without the Cancel = True statement in the sub.
I set up a simple test event (see below) to move the textbox focus back up to TextBox1 when Textbox2 is entered, it actually moves focus to Textbox3 when I tab out of TextBox1.
You can't set focus to another control in the _Enter() event. If you try to then the code will move focus to control which has the next TabIndex
For example
Let's say you have 5 textboxes with the following TabIndex
TextBox1 (TabIndex 0)
TextBox2 (TabIndex 1)
TextBox3 (TabIndex 3)
TextBox4 (TabIndex 4)
TextBox5 (TabIndex 2)
Now if you have this code
Private Sub TextBox2_Enter()
TextBox3.SetFocus
End Sub
The moment you press TAB from TextBox1, the focus will move to TextBox5 (and not TextBox3) as it has the next TabIndex.
Also Cancel = True will not have any effect because it is not an argument of _Enter() like it is of say Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Edit
BTW, the only time the focus will come back to Textbox1 in your scenario is when there are only two TextBoxes in the form.
I know this is old but this answered my question and I can't comment. However, Stan in reference to your comment on June 8, 2017 I believe you were looking for something like the code below which will highlight the text in the text box when you use it with Cancel = True. I use it in the textbox exit event. This will be the indication to the user that the text box is selected.
With Me.TextBox1
.Value = "Full Name"
.SelStart = 0
.SelLength = Len(.Text)
.SetFocus
End With
Cancel = True
While it is true that _Enter() event can not handle .SetFocus, the _KeyDown() event can! And thats a pretty good workaround, you just need to monitor if the TAB key was pressed.
So the code would look like something similar where TextBox1 is the one you leave and TB2 is the one you enter;
Private Sub TextBox2_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 9 Then TextBox1.SetFocus 'where 9 is the KeyCode for the TAB button
End Sub

VBA Excel Exiting after update event fires enter event

Let's say I had a combobox1, 2, 3 and a textbox1 on a userform. After update event was associated to combobox1. When Tab key was pressed after update event was fired (filling comboboxes 2 and 3). In the code of this event, just before exit sub there was textbox1.setfocus to skip entering other coboboxes in the tab order (combobox 1,2,3, textbox1). It worked just fine.
When I added another combobox that is now combobox2, the tab order was changed to 1,2,3,4.
After update is still associated to combobox1 and textbox1.setfocus is last line before exit sub. Unfortunately when exit sub line for after update is executed, it fires combobox3 enter event and moves focus to combobox3. It's more incomprehensible because tab order is combobox1,2,3,4 so it skips the tab order as well.
When I debuged code, the focus to textbox1 was set as it should but still just when exit sub is executed, code line is moved to combobox3 enter event...
Any tips appreciated.
in your userform code pane act as follows:
a userform scoped Boolean variable
hence, place this before any Sub/Function code
Dim SetTextBox1Focus As Boolean
in your ComboBox1_AfterUpdate() event handler place:
Private Sub ComboBox1_AfterUpdate()
If (condition that checks if the data entered in combobox1 exists in the database) is True Then
...
your code to fill comboboxes 2, 3 ad 4
...
Me.TextBox1.SetFocus
SetTextBox1Focus = True '<--| "flag" TextBox1 to receive the focus
End If
End Sub
add an Enter event handler for all userform controls whose tab index is in between ComboBox1 and TexBox1
for instance, assuming those are ComboBox2, ComboBox3 and ComboBox4
Private Sub ComboBox2_Enter()
CheckSetTextBox1Focus
End Sub
Private Sub ComboBox3_Enter()
CheckSetTextBox1Focus
End Sub
Private Sub ComboBox4_Enter()
CheckSetTextBox1Focus
End Sub
add the following CheckSetTextBox1Focus() Sub
Sub CheckSetTextBox1Focus()
If SetTextBox1Focus Then
Me.TextBox1.SetFocus
SetTextBox1Focus = False
End If
End Sub

Userform showing when not wanted, not called for

im having some weird things happen with some code in excel
Private Sub CommandButton2_Click()
Dim thiswb As Workbook
Set thiswb = ActiveWorkbook
Call EnterDataToSS(thiswb)
Me.Hide
BeamNoFind.Show vbModal
End Sub
the called code basically drops some values into a spreadsheet.
any left over values are populated to LISTBOX1 on BeamNoFind Userform.
Then on the BeamNoFind userform there is a button and the LISTBOX1. when you select and item from listbox1, and click the button, a third userform opens (VBMODELESS) to allow placement of the value.
below is the code of the button to show the third userform.
Private Sub CommandButton2_Click()
Dim Selected_Length As String
Dim Selected_Name As String
Dim Selected_Length_index As Integer
Selected_Length_index = BeamNoFind.ListBox1.ListIndex
With BeamNoFind.ListBox1
If .ListIndex > -1 Then
Selected_Name = .Column(0, .ListIndex)
Selected_Length = .Column(1, .ListIndex)
CellInputForm.beam_length_label.Caption = Selected_Name & " [ " & Selected_Length & " ] "
BeamNoFind.Hide
'ChngDataSrc.Hide
'Unload ChngDataSrc
CellInputForm.Show vbModeless
Else
MsgBox "No selection", vbExclamation, "Oops!"
End If
End With
End Sub
the weird thing is, when i click the button to show my modeless userform, to place the data in a cell, the initial macro is being triggered that drops you into the first userform.
Where i have the commented code 'ChngDataSrc.Hide' and 'Unload ChngDataSrc' are my attempts to stop the userform from displaying when i dont want it to.
When i unload the form, i then get an error instead of the form displaying, the error is with the initial macro:
Sub get_scheduling_data(control As IRibbonControl)
ChngDataSrc.Show
End Sub
It has something to do with vbModeless because if i replace "vbModeless" from "CellInputForm.Show vbModeless" line with "vbModal", it shows correctly, without the unwanted form (ChngDataSrc). but then the function of the form (select cell, press ok button, value placed in selected cell) is gone.
I found a solution, but its not a real solution,
i placed
ChngDataSrc.Hide in the Activate sub of the CellInputForm userform.
So when CellInputForm.show vbModeless is run, and the ChngDataSrc userform pops up unwantedly, it is then hidden again.
Id rather find out why it is being showed in the first place, but this fix seems to work for now.

Validate VBA drop down on click

I have a drop down select list in a VBA form I would like to validate as soon the user clicks on it. It needs to check that a pre-requisite drop down has been filled already.
This is to avoid the user jumping ahead on the form because there are certain fields that need to be filled out first. My attempt so far is not working:
Private Sub cbo_moduleName_Click()
If Len(cbo_moduleCode.Value) = 0 Then
MsgBox ("Please select a module code")
Exit Sub
End If
End Sub
It seems the Click event is activated only when the box's value is changed with the mouse, not every time it is physically clicked on. Try this:
Private Sub cbo_moduleName_Enter()
If Len(cbo_moduleCode.Value) = 0 Then
MsgBox ("Please select a module code")
cbo_moduleCode.SetFocus
Exit Sub
End If
End Sub

Resources