Excel VBA Textbox_Exit Event Handler - excel

At a road block here. Simple user form using three text boxes, one for user id, two to enter serial number using hand scanner. User loads excel file, userform.show loads, user enters id then simple validation to verify numberic number, then focus set on first textbox, user scans barcode to input serial number, again simple validation to ensure numeric and length, same with last textbox, scan serial number, validate first textbox entry matches second textbox entry.
Hand scanner is used to input serial number and also returns a "return carriage" character; e.g. enter button press after serial number scan.
Using "return carriage" to fire textbox_exit event handler. Issue is very intermittent but consistent. I load userform, input data, when record is complete, data is transferred to object worksheet. However, when troubleshooting, I initially open workbook and userform, create a few records, save, and close. Everything works well and data is recorded and archived. Issue generally arises when i load workbook a second time, enter data for one record, save, and begin second record. Once serial number is entered into first textbox, exit event never fires using "return carriage". I can manually transfer focus to other objects; e.g. diff textbox, but the overall operation is not as expected.
I have tried inserting application.eventhandler=true commands, different event handlers, as well as numerous code changes; e.g. exit sub at end of IF statements, to make this work.
Thought I would reach out to the community for some feedback. FYI, issues still arises if I simulate hand scanner using copy/paste and enter key.
Example of exit event handler for first serial textbox below.
Private Sub SerialIn_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Cancel = False
If Not IsNumeric(SerialIn.Value) Then 'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
MsgBox Msg, vbCritical, "Warning" 'display msg
Cancel = True 'stop user from changing focus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
Exit Sub
Else
If Not Len(SerialIn.Value) = 19 Then 'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
MsgBox Msg, vbCritical, "Warning"
Cancel = True 'stop user from changing focus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
Exit Sub
Else
SerialInTime.Caption = Now 'record date and time
'Image1.Picture = LoadPicture(StopLightYellow) 'display yellow WIP stop light
Me.SerialOut.SetFocus
Exit Sub
End If
End If
End Sub
New code:
Private Sub SerialIn_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Cancel = ValidateSerialIn(SerialIn)
End Sub
Function ValidateSerialIn(ByVal TextBox As Object) As Boolean
If Not IsNumeric(SerialIn.Value) Then 'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning" 'display msg
SerialIn.SetFocus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
ValidateSerialIn = True
Else
If Not Len(SerialIn.Value) = 19 Then 'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning"
'Cancel = True 'stop user from changing focus
SerialIn.SelStart = 0 'highlight user text
SerialIn.SelLength = Len(SerialIn.Value) 'select user text
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
ValidateSerialIn = True
Else
SerialInTime.Caption = Now 'record date and time
'Image1.Picture = LoadPicture(StopLightYellow) 'display yellow WIP stop light
ValidateSerialIn = False
End If
End If
End Function
Third go using Tim's TextBox_Change solution:
Private Sub SerialIn_Change()
Dim v
v = ScannedValue1(SerialIn.Text)
If Len(v) > 0 Then
If Not IsNumeric(v) Then 'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning" 'display msg
SerialIn.Text = vbNullString
Else
If Not Len(v) = 19 Then 'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong! Serial number was incorrect." _
& vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning"
SerialIn.Text = vbNullString
'Image1.Picture = LoadPicture(StopLightRed) 'display red stop light
Else
SerialInTime.Caption = Now 'record date and time
'Image1.Picture = LoadPicture(StopLightYellow) 'display yellow WIP stop light
SerialOut.SetFocus
End If
End If
End If
End Sub
'check if a value ends with vbcrlf or vblf
' - if yes strip that off and return the rest
' - otherwise returns empty string
Function ScannedValue1(vIn) As String
Dim rv As String
If Right(vIn, 2) = vbCrLf Then
ScannedValue1 = Replace(vIn, vbCrLf, "")
ElseIf Right(vIn, 1) = vbLf Then
ScannedValue1 = Replace(vIn, vbLf, "")
End If
End Function

If you want to detect the "Enter" from the scanner then use the Change event to check if the textbox value ends with vbCrLf or vbLf (in that order): if it does, then trigger the "scan" action.
Note you need to set your textbox to "multiline=true" and "EnterKeyBehaviour = true" in order for the Change event to capture the enter key.
Private Sub TextBox1_Change()
Dim v
v = ScannedValue(TextBox1.Text)
If Len(v) > 0 Then
TriggerScanAction v
TextBox1.Value = ""
End If
End Sub
'check if a value ends with vbcrlf or vblf
' - if yes strip that off and return the rest
' - otherwise returns empty string
Function ScannedValue(vIn) As String
Dim rv As String
If Right(vIn, 2) = vbCrLf Then
ScannedValue = Replace(vIn, vbCrLf, "")
ElseIf Right(vIn, 1) = vbLf Then
ScannedValue = Replace(vIn, vbLf, "")
End If
End Function
'execute some action triggered by a scanned value
Sub TriggerScanAction(v)
MsgBox "You scanned " & v
End Sub

The Exit event has more to it than meets the eye. On most forms, one enters a value in a textbox and then clicks "OK", a command button. Tbx.Exit event occurs. It also occurs if you click anywhere else, such as a button to close the form. In your system the CR triggers the event as well, and that would appear to be the problem.
When a CR or TAB is entered in your Tbx the form's tapping sequence takes over. The exit occurs, followed by the enter event of the next control in your tapping order. (Compare that to the manual change of focus that occurs when the user determines the next control.)
So, the solution should be not to use the Exit event but to let the CR initiate a change of focus, using the tapping order setting, which lands the focus on an "OK" button, then let that button's Enter event trigger its Click event (if it doesn't do that by default).
You probably want a cycle there, where the CR triggers the worksheet entry and the focus comes back to the Tbx. That's one more reason not to use the Exit event because you don't want an entry made in the worksheet when you exit the Tbx to close the form.
However, perhaps your form doesn't have or need an "OK" button. In that case I would recommend the BeforeUpdate event of the Tbx. Both Exit and BeforeUpdate occur in close succession. The sequence isn't important however (though that's not the reason why I forgot it :-)) but their nature. Use the exit event in the context of form control, setting focus or reacting to focus change. BeforeUpdate obviously refers to data. Each of these events is fine tuned to its own task and therefore does it better than the other.

Related

Userform button not working when typing in a textbox vba

I have a userform where you have to enter data into textboxes and then press a button to put the data into the sheet. When I'm typing into the last textbox and I'm done, I click the button and it doesn't respond. Also, I have noticed that my cursor keeps blinking inside the last textbox so I guess there's a problem there (while focused not able to click a button)?
In total I have 4 textboxes, 3 of them use data validation after their value has been updated. The last one does not have data validation.
The weird thing is that, next to the "next button", I have a button to clear the fields and that one works just fine. Below an image from my userform with a little bit of explanation because it's in another language (Dutch). Can anyone help me? Thanks!
The code used for the "next" button is:
Note: the data gets validated not only when they updated the value of the textbox, but also an extra time when they click the next button.
Private Sub AddNextBtn_Click()
AddValueMod.AddDisplayOverview
End Sub
Sub AddDisplayOverview() 'This sub is in the "AddValueMod" module
'Check if information is valid via a function
If AddInformationValid("AccountSelector", True) And AddInformationValid("Date", True) And AddInformationValid("Amount", True) And AddInformationValid("Description", True) Then
'If valid, retrieve entered values
Dim account, dDate, amount, description As String
account = main.AddAccountSelector.Value
dDate = main.AddDateInput.Value
amount = main.AddValue.Value
description = main.AddDescription.Value
'Ask for sheet-writing-confirmation
overview = MsgBox("Kloppen volgende gegevens (kijk goed na!)?" & vbCrLf & vbCrLf & "Rekening: " & account & vbCrLf & "Datum: " & dDate & vbCrLf & "Bedrag: " & amount & vbCrLf & "Beschrijving: " & description & vbCrLf & "Vermeerdering/vermindering: Waarde wordt vermeerderd", vbYesNo + vbQuestion, "Kloppen volgende gegevens?")
If overview = vbYes Then
'Write data to sheet
AddValueMod.AddEnterDataIntoSheet
End If
End If
End Sub
And for the "clear fields" button:
Private Sub AddClearFieldsBtn_Click()
AddValueMod.AddClearFields (True)
End Sub
Sub AddClearFields(askForConfirmation As Boolean) 'This sub is in the "AddValueMod" module
grey = RGB(128, 128, 128)
'If askForConfirmation = True, ask for confirmation before clearing fields
If askForConfirmation = True Then
confirmationMessage = MsgBox("Bent u zeker dat u de velden wilt leegmaken?" + vbCrLf + "U zal terug opnieuw moeten beginnen.", vbYesNo + vbQuestion, "Velden leegmaken?")
If confirmationMessage = vbYes Then
'Clear fields
main.AddAccountSelector.Value = ""
main.AddDateInput.Value = ""
main.AddValue.Value = ""
main.AddDescription.Value = ""
End If
ElseIf askForConfirmation = False Then
'Clear fields
main.AddAccountSelector.Value = ""
main.AddDateInput.Value = ""
main.AddValue.Value = ""
main.AddDescription.Value = ""
End If
'Reset the textboxes' borders (they change if an input error occurred)
main.AddAccountSelectorError.Visible = False
main.AddAccountSelector.BorderStyle = fmBorderStyleSingle
main.AddAccountSelector.BorderColor = grey
main.AddDateInputError.Visible = False
main.AddDateInput.BorderStyle = fmBorderStyleSingle
main.AddDateInput.BorderColor = grey
main.AddValueError.Visible = False
main.AddValue.BorderStyle = fmBorderStyleSingle
main.AddValue.BorderColor = grey
main.AddDescriptionError.Visible = False
main.AddDescription.BorderStyle = fmBorderStyleSingle
main.AddDescription.BorderColor = grey
End Sub
P.S.: I've already tried a possible solution with IsCancel = True/False that I found online in this article. It's possible it didn't work because the article is not quite related to my problem but I felt like I should mention it :).
You did not provide all relevant code. AddInformationValid() and AddEnterDataIntoSheet are missing.
However, if the AddInformationValid() returns False on any item, the behaviour is just as you describe. In AddDisplayOverview() there will be no error message, the AddEnterDataIntoSheet sub will be bypassed and on return from the button handler the cursor remains flashing in the last entry field.
You need to verify and correct the AddInformationValid() Function.
I also strongly recommend to show an error message if the data validation fails.

Ensure user inputs text in INPUT Box in CAPS

I have a input box that the user needs to put in some specific text. The text must be in uppercase. But when i run the code and insert the text in lower case, it still runs.
HERE:
KnownError = InputBox(PayRatesTable.ListColumns("Name").DataBodyRange(i) & " is showing "
& PayRatesTable.ListColumns("Hourly or Salary").DataBodyRange(i) & " for role " &
PayRatesTable.ListColumns("All Roles").DataBodyRange(i) & ". Please type KNOWN ERROR (All
CAPS) to
continue.")
If StrPtr(KnownError) = 0 Then
MsgBox "Process Aborted"
Exit Sub
End If
If KnownError <> "KNOWN ERROR" Then
MsgBox "Please type KNOWN ERROR (All CAPS) to continue or cancel to stop the
proccess"
GoTo HERE
End If
Any ideas on how to force the use of uppercase??

Excel VBA stop code where conditions are met

I'm struggling getting my code to work.
I have a button on the excel sheet that when triggers
checks required fields value is 0, if not then message box and end code
checks if the reference number already exists on a master tab, if the reference exisits, message box and end code
if 1 and 2 pass then perform a copy and paste as values for 3 ranges then message box.
I've tried a number of options but can't get it to work
Function Mand() As Boolean
'checks that mandatory fields have been updated
If Sheets("INPUT").Range("C11") > 0 Then MsgBox "Mandatory Fields Missing" & vbNewLine & "Changes Not Saved!"
Mand = True
End Function
Function RecEx() As Boolean
'checks that the reference number does not exisit on the High Level master list
dup = WorksheetFunction.CountIf(Sheets("High_Level_List").Columns(1), Sheets("INPUT").Range("C17"))
If dup > 0 Then MsgBox "This Record Exists!!!" & vbNewLine & "If saving an update, use the Save Changes button"
RecEx = True
End Function
Sub RegisterNewRec()
' checks 2 functions, if either are TRUE then exit, otherwise update master
If Mand Then Exit Sub
If RecEx Then Exit Sub
End If
Dim rng As Range
Set rng = Sheets("INPUT").Range("AO2:CX2")
Sheets("High_Level_List").Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(rng.Rows.Count, rng.Columns.Count).Cells.Value = rng.Cells.Value
'more code that updates master
MsgBox "Record added to Master"
End Sub
As I said in my comment, the End If doesn't need to be there:
If Mand Then Exit Sub
If RecEx Then Exit Sub
^ How the code should look
Alternatively you could use:
If Mand Or RecEx Then Exit Sub
You also need to make sure that you only set your function to True if the above is true by including the End If block:
Function Mand() As Boolean
If Sheets("INPUT").Range("C11") > 0 Then
MsgBox "Mandatory Fields Missing" & vbNewLine & "Changes Not Saved!"
Mand = True
End If
End Function
Function RecEx() As Boolean
dup = WorksheetFunction.CountIf(Sheets("High_Level_List").Columns(1), Sheets("INPUT").Range("C17"))
If dup > 0 Then
MsgBox "This Record Exists!!!" & vbNewLine & "If saving an update, use the Save Changes button"
RecEx = True
End If
End Function
The problem is that you were setting the RecEx and the Mand to true either way.

How to take text from a cell and input it into VBA?

What I am trying to do is basically you click a button, it brings up the Excel MailEnvelope to send an email, and you can then send it off to the relevant button email address'.
However one of the email addresses needs to be modifiable by the end user.
So I want a drop down where you select said email, and it then inputs that into the VBA code.
I know basically nothing about VBA and I could not find a way of doing this by searching around the web.
I figured I need some way of setting a variable to read a cell (the drop down cell), and then input that into the MailEnvelope Item.CC but I was struggling.
Any help would be appreciated.
This is what I have so far;
Sub Send_Range_Email()
' Select the range of cells on the active worksheet.
ActiveSheet.Range("B6:D302").Select
' Show the envelope on the ActiveWorkbook.
ActiveWorkbook.EnvelopeVisible = True
' Set the optional introduction field thats adds
' some header text to the email body. It also sets
' the To, CC and Subject lines.
With ActiveSheet.MailEnvelope
.Introduction = ""
.Item.To = "Email 0"
.Item.Subject = "Email Tracker Results"
.Item.CC = "Email 1" & text input here & "Email 2"
End With
End Sub
When using formulas, if you want to put a variable in there, just break it apart and add in the variable. As commented,
.Item.CC = "email 1" & "," & Range("A1").Value & ", " & "Email 2"
So to make super clear, say we want to add A1's value in this string: str = The man lives in STATE all the time by doing str = "The man lives in " & Range("A1").Value & " all the time"

Vba want user to force fill form when not filled programme should not continue futher

I have a form that a user should fill and if certain fields are not filled the form should not continue further but it still does may be I am not see some thing help please
this is under the button presed If Me.cbTyreNsf.value = " " Then
MsgBox "You must complete the Wheel Nsf value", vbCritical
Exit Sub
End If
If Me.cbTyreNsR.value = "" Then
MsgBox "You must complete Wheel Nsr value", vbCritical
Exit Sub
End If
the function called
Call CheckifRecordExistOnWheelTable
the code for the function
Select Case avar
Case "NULL"
Call insertWheel
Case Else
Call updateWheel
End Select
and the code for the function called by the function
nssf = Me.cbTyreNsf.value
Select Case nssf
Case "0"
MsgBox " Please enter the NSF tyre value", vbCritical
Me.cbTyreNsf.SetFocus
' MsgBox "about to exit"
Exit Sub
Case Else
nsf = CInt(nssf)
End Select
any help please i have been on it for 24 hours counting tried every thing
This can be a problem:
nssf = Me.cbTyreNsf.value
it does not pass any value to nssf if there is no value in the cbTyreNsf. (try msgbox(nssf) at that point. It will give you blank message box). If you want to test it using your current select case then you can try checking length of the value which will be 0 for empty cbTyreNsf.
nssf =Len(Me.cbTyreNsR.value)

Resources