Validate a TextBox before the _Change event is fired - string

I've got a form that has 3 TextBox controls on it: stock code, quantity, certificate number. The stock code TextBox is set to focus automatically when the form is loaded.
I've also attached a bar code scanner to my PC, as the user wants to be able to either scan a bar code to populate the TextBox, or manually type the data in.
The labels being scanned contain two bar codes. One is a certificate number and the other a stock code.
The stock bar code has a prefix of "SBC/", whilst a certificate bar code is prefixed with "C/".
When the user scans a bar code, if the TextBox in focus is the stock code TextBox, then I want to run a check as below.
Private Sub txtStockCode_Change()
On Error GoTo errError1
If Len(txtStockCode.Text) >= 5 Then
If bChangeCode Then
If Left(txtStockCode.Text, 2) = "C/" Then
msgbox "You have scanned the certificate barcode; please scan the stock barcode."
txtStockCode.Text = ""
Else
bChangeCode = False
txtStockCode.Text = Replace(txtStockCode.Text, "SBC/", "")
txtStockCode.Text = Replace(txtStockCode.Text, "*", "")
End If
End If
End If
Exit Sub
Let's say the focus is currently on the stock code TextBox.
If the stock bar code is scanned, the following should happen:
Stock code length is greater than 5
Left 5 characters do not = "C/", so correct code has been scanned
TextBox text value is updated to remove all * and the prefix of "SBC/"
E.g. "SBC/A12-TR0*" becomes "A12-TRO"
and
Certificate number length is greater than 5
Left 5 characters do = "C/", so incorrect code has been scanned
MsgBox to user
TextBox value is reset to ""
However, no matter which code is scanned into the stock code TextBox, the value is never validated.
E.g. "SBC/A12-TR0*" remains as "SBC/A12-TR0*" and "C/29760" remains as "C/29760"
As the validation code is the same in the certificate TextBox, the same pattern is repeated vice versa.
Why are my values not updating, or how can I validate the input before the _Change is fired?
EDIT
I've now changed my code to
Private Sub txtStockCode_Change
If txtStockCode.Text <> "" Then
txtStockCode.Text = Replace(txtStockCode.Text, "SBC/", "")
txtStockCode.Text = Replace(txtStockCode.Text, "*", "")
End If
End Sub
But it still displays the prefix of SBC/, yet is removing the two * characters (at the start and end of the barcode as is required for the scanner to read it as a barcode)

You could try to set the barcode reader to return Enter key at the end of the scanned barcode and then use the Keypress event to check it and make your changes.
Sub txtStockCode_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
If Len(txtStockCode.Text) >= 5 Then
If bChangeCode Then
If Left(txtStockCode.Text, 2) = "C/" Then
msgbox "You have scanned the certificate barcode; please scan the stock barcode."
txtStockCode.Text = ""
Else
bChangeCode = False
txtStockCode.Text = Replace(txtStockCode.Text, "SBC/", "")
txtStockCode.Text = Replace(txtStockCode.Text, "*", "")
End If
End If
End If
End If
End Sub

Related

Cycle through a loop in VBA

I have a form in VBA where I want a combo box (cboIncluded) to change its dropdown values according to what's chosen in a different combo box(cboSelectParty).
It provides choices correctly the first time I choose something from cboSelectParty, and if I choose again from either my If or elseif.
My problem is, if I have chosen from either the if or elseif (Fun climb party or climbing party), if won't go back to giving me correct options if I choose anything else.
Private Sub cboSelectParty_AfterUpdate()
cboIncluded.Value = ""
If cboSelectParty.Value = "Fun Climb Party" Then
cboIncluded.List = Sheets("PartyImport").Range("N3:N4").Value
ElseIf cboSelectParty.Value = "Climbing Party" Then
cboIncluded.List = Sheets("PartyImport").Range("O3:O6").Value
Else
cboIncluded.Value = Application.WorksheetFunction.VLookup(cboSelectParty.Value,
Sheets("PartyImport").Range("E2:H37"), 4, False)
End If
End Sub

Inputbox selection causing: "Text is not valid." Error [duplicate]

The current function I use to collect text InputBox can't accept more than 255 characters apparently, and I need to be able to collect more than that? Is there a parameter or different function I can use to increase this limit?
To be pedantic, the Inputbox will let you type up to 255 characters, but it will only return 254 characters.
Beyond that, yes, you'll need to create a simple form with a textbox. Then just make a little "helper function" something like:
Function getBigInput(prompt As String) As String
frmBigInputBox.Caption = prompt
frmBigInputBox.Show
getBigInput = frmBigInputBox.txtStuff.Text
End Function
or something like that...
Thanks BradC for the info that. My final code was roughly as follows, I have a button that calls the form that I created and positions it a bit as I was having some issues with the form being in the wrong spot the everytime after the first time I used.
Sub InsertNotesAttempt()
NoteEntryForm.Show
With NoteEntryForm
.Top = 125
.Left = 125
End With
End Sub
The userform was a TextBox and two CommandButtons(Cancel and Ok). The code for the buttons was as follows:
Private Sub CancelButton_Click()
Unload NoteEntryForm
End Sub
Private Sub OkButton_Click()
Dim UserNotes As String
UserNotes = NotesInput.Text
Application.ScreenUpdating = False
If UserNotes = "" Then
NoteEntryForm.Hide
Exit Sub
End If
Worksheets("Notes").ListObjects("Notes").ListRows.Add (1)
Worksheets("Notes").Range("Notes").Cells(1, 1) = Date
Worksheets("Notes").Range("Notes").Cells(1, 2) = UserNotes
Worksheets("Notes").Range("Notes").Cells(1, 2).WrapText = True
' Crap fix to get the wrap to work. I noticed that after I inserted another row the previous rows
' word wrap property would kick in. So I just add in and delete a row to force that behaviour.
Worksheets("Notes").ListObjects("Notes").ListRows.Add (1)
Worksheets("Notes").Range("Notes").Item(1).Delete
NotesInput.Text = vbNullString
NotesInput.SetFocus ' Retains focus on text entry box instead of command button.
NoteEntryForm.Hide
Application.ScreenUpdating = True
End Sub
I don't have enough rep to comment, but in the sub form_load for the helper you can add:
me.AutoCenter = True
Outside of that form, you can do it like this:
NoteEntryForm.Show
Forms("NoteEntryForm").AutoCenter = True
My Access forms get all confused when I go from my two extra monitors at work to my one extra monitor at home, and are sometimes lost in the corner. This AutoCenter has made it into the form properties of every one of my forms.

Problem with multiline string in userform

I am having a issue with multiline stings in a userform.
When a user selects a option, the code checks if the selected answer matches the correct answer and then shows if right or wrong. But in either case the code says it is wrong.
Example of a option is:
If you see the string, brush it off sideways
Place icepack/cold flannel to reduce swelling
Elevate area to reduce bloodflow
Private Sub OptionButton1_Click()
rowNum = Selection.Row - Selection.ListObject.Range.Row
DeclareVars
Column = examtable.ListColumns("Right ans").DataBodyRange(rowNum)
CorrectAns = examtable.ListColumns("Right ans").DataBodyRange(rowNum).Offset(0, Column)
RightWrong.Visible = True
If OptionButton1.Caption = CorrectAns Then
RightWrong.BackColor = &HFF00&
RightWrong.Caption = "Right"
Else
RightWrong.BackColor = &HFF&
RightWrong.Caption = "Wrong"
End If
End Sub
What i am expecting is that if correct, shows right, or wrong if incorrect
If I understand correctly you have multiple option buttons below one another? Option button one will always have the same caption. If it is selected it can become true (indicated by the black dot), but the caption will not change.
Lets say it looks like this
two option buttons
Then the upper is called OptionButton1, the lower OptionButton2.
You can check
If OptionButton1 then
RightWrong.BackColor = &HFF00&
RightWrong.Caption = "Right"
Else
RightWrong.BackColor = &HFF&
RightWrong.Caption = "Wrong"
End if
You could use a combobox (these are the drop down menus).
You could populate it with an array of the strings you want to test and ask if the answers concur.
When loading the user form use
Private Sub UserForm_Activate()
ComboBox1.list = Array("brush it off sideways", "Place icepack/cold flannel to reduce swelling", "Elevate area to reduce bloodflow")
End Sub
this will look as followed
The user form with the list open
Then you can say combobox.value = CorrectAns

Save SM37 rows with sorting via GUI Script?

The following SAP GUI Script for SAP 740 saves the SM37 list to a text file.
Before saving the list, I'd like to sort the list by Start date and Start time.
I can display the popup to select Sort fields. On left side there is a table control with current Sort columns (job name, created by, progress, scheduled start date, scheduled start time), on right side there is a table control with all possible Sort columns, each of these left and right Sort columns can be selected, and between the two table controls there are buttons to move Sort columns from left to right or vice versa.
Now, to select Sort columns, I have to select rows of table controls, but I don't know how to do it. Can you help me?
Public Sub RunSM37Cancelled()
Dim W_Ret As Boolean
W_Ret = Attach_Session
If Not W_Ret Then
Exit Sub
End If
On Error GoTo disperr
objSess.findById("wnd[0]").maximize
objSess.findById("wnd[0]/tbar[0]/okcd").Text = "sm37"
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/txtBTCH2170-JOBNAME").Text = "*"
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/txtBTCH2170-USERNAME").Text = "*"
objSess.findById("wnd[0]/usr/txtBTCH2170-USERNAME").SetFocus
objSess.findById("wnd[0]/usr/txtBTCH2170-USERNAME").caretPosition = 1
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/chkBTCH2170-SCHEDUL").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-READY").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-RUNNING").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-FINISHED").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-ABORTED").Selected = True
objSess.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").Text = Format(Now()-1,"mm/dd/yyyy")
objSess.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").SetFocus
objSess.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").caretPosition = 10
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").Text = Format(Now(), "mm/dd/yyyy")
objSess.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").SetFocus
objSess.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").caretPosition = 10
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/tbar[1]/btn[8]").press
objSess.findById("wnd[0]/usr/lbl[80,10]").SetFocus
objSess.findById("wnd[0]/usr/lbl[80,10]").caretPosition = 5
objSess.findById("wnd[0]").sendVKey 2
objSess.findById("wnd[0]/usr/lbl[91,10]").SetFocus
objSess.findById("wnd[0]/usr/lbl[91,10]").caretPosition = 4
objSess.findById("wnd[0]").sendVKey 2
' Display sort dialog (41 = Ctrl+Shift+F5 = menu Edit > Sort in ascending order)
objSess.findById("wnd[0]/tbar[1]/btn[41]").press
' <<<< Here, how to select lines in left and right table controls?
' Downloading the file
fileobjSess.findById("wnd[0]/mbar/menu[5]/menu[5]/menu[2]/menu[1]").Select
objSess.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").Select
objSess.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").SetFocus
objSess.findById("wnd[1]/tbar[0]/btn[0]").press
objSess.findById("wnd[1]/usr/ctxtDY_PATH").Text = ffilepath
objSess.findById("wnd[1]/usr/ctxtDY_FILENAME").Text = ffilename
objSess.findById("wnd[1]/usr/ctxtDY_FILENAME").caretPosition = 8
objSess.findById("wnd[1]/tbar[0]/btn[11]").press
Exit Sub
disperr:
MsgBox "Error occured while retrieving data", vbCritical + vbOKOnly
End Sub
To select a row by its position in a table control, you need to determine the name of the table control, then use the method tableControl.getAbsoluteRow(row) to get the instance of the row, and set its property Selected = True. Example :
tableControl = objSess.findById("wnd[1]/usr/tblSAPLSKBHTC_FIELD_LIST_820")
tableControl.getAbsoluteRow(6).Selected = True
Now, to answer your specific question (ALV sorting in SM37), you also need to press additional buttons to select the Sort fields.
The Sort dialog screen is made of two table controls. You may first press the button "Hide all fields" to move all fields to the right table control (fields not selected), then select the fields on the right table control (as explained in the first paragraph) and press the buttons "Show sel. fields (Ctrl+F3)" and "Copy (Enter)".
You need to know the row number of the field you want to select in the right table control. In an ABAP 7.52 system, these fields are listed in this sequence (first one is row 1, second one is row 2 and so on):
Job name
Spool list
Job documentation
created by
status
start date
start time
duration
...
You also need to know the name of the right table control. For that, you may select the menu System > Status, double click the number of "screen/dynpro" which displays the technical names of screen elements. In your case, you see TC_FIELD_LIST_820. You also see that the screen belongs to the program SAPLSKBH.
The final program would look like this:
ffilepath = "your path here"
ffilename = "Test.txt"
With objSess
.findById("wnd[0]").Maximize
.findById("wnd[0]/tbar[0]/okcd").Text = "/nsm37"
.findById("wnd[0]").sendVKey 0
.findById("wnd[0]/usr/txtBTCH2170-JOBNAME").Text = "*"
.findById("wnd[0]/usr/txtBTCH2170-USERNAME").Text = "*"
.findById("wnd[0]/usr/chkBTCH2170-SCHEDUL").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-READY").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-RUNNING").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-FINISHED").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-ABORTED").Selected = True
.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").Text = Format(Now() - 1, "mm/dd/yyyy")
' .findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").Text = Format(Now() - 1, "dd/mm/yyyy")
.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").Text = Format(Now(), "mm/dd/yyyy")
' .findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").Text = Format(Now(), "dd/mm/yyyy")
.findById("wnd[0]/tbar[1]/btn[8]").press
' Display sort dialog (41 = Ctrl+Shift+F5 = menu Edit > Sort in ascending order)
.findById("wnd[0]/tbar[1]/btn[41]").press
' Remove all previous sort fields (press pushbutton named "APP_FL_ALL")
.findById("wnd[1]/usr/btnAPP_FL_ALL").press
' Select sort field(s) (row 6=start date, row 7=start time)
with .findById("wnd[1]/usr/tblSAPLSKBHTC_FIELD_LIST_820")
.getAbsoluteRow(6).Selected = True
.getAbsoluteRow(7).Selected = True
end with
' Press pushbutton "Show sel. fields"
.findById("wnd[1]/usr/btnAPP_WL_SING").press
' Press key "Enter" (corresponds to pushbutton "Copy (Enter)")
.findById("wnd[1]/tbar[0]/btn[0]").press
' Downloading the file
.findById("wnd[0]/mbar/menu[5]/menu[5]/menu[2]/menu[1]").Select
.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").Select
.findById("wnd[1]/tbar[0]/btn[0]").press
.findById("wnd[1]/usr/ctxtDY_PATH").Text = ffilepath
.findById("wnd[1]/usr/ctxtDY_FILENAME").Text = ffilename
.findById("wnd[1]/tbar[0]/btn[11]").press
End With

How can I user isnumeric and not isnumeric functions together?

I have a stock program over Excel integrated with Barcode reader.
With the following code, I could read numeric barcodes to textbox without any problem.
Barcode code like 101010 or 8693457248273
If Not IsNumeric(TextBox2.Value) Then
TextBox2.SetFocus
TextBox2.SelStart = 1
TextBox2.SelLength = Len(TextBox2.Text)
Cancel = True
Else
End If
When I try to read barcodes as 730MT30151, above code line not works.
But if I delete Not expression inside of the above code. It works.
However this time I could not read numeric barcodes.
If IsNumeric(TextBox2.Value) Then
TextBox2.SetFocus
TextBox2.SelStart = 1
TextBox2.SelLength = Len(TextBox2.Text)
Cancel = True
Else
End If
So I just want to mix both two codes but I could not achieve it.
Does anybody help me to solve this problem?
This code basically means cancel (Cancel = True) all inputs that contain text (Not IsNumeric).
If Not IsNumeric(TextBox2.Value) Then
TextBox2.SetFocus
TextBox2.SelStart = 1
TextBox2.SelLength = Len(TextBox2.Text)
Cancel = True
Else
End If
Actually the code is a limitation to numbers only. So if you now want to allow numbers and letters just remove that (limitation) code completely.
If you want to keep the selection and focus stuff just keep this lines:
TextBox2.SetFocus
TextBox2.SelStart = 1
TextBox2.SelLength = Len(TextBox2.Text)

Resources