Reputation: 1202
I am new to VBA. I have a textbox that is being populated by bar code scanner using Excel. There are different values on the form, for example:
608001F
608001
001IN
I need to check if the code contains 'F' and then do a certain action, otherwise do another action. I do this on Textbox_Change()
function, which is causing the 608001
code to be triggered first. How can I make it trigger the code with the 'F' in it first?
My code looks like this (edited for brevity, so excuse if any syntax errors):
Private Sub TextBox1_Change()
Value = TextBox1.Value
If Value <> "" Then
If (Len(Value) = 7 And Right(Value, 1) = "F") Then
ActiveCell.Value = Value
ActiveSheet.Cells(ActiveCell.Row + 1, 1).Select
TextBox1.Value = ""
TextBox1.Activate
ElseIf (Len(Value) = 6 Or (Len(Value) = 5 And (Right(Value, 2) = "IN" Or Right(Value, 2) = "EM"))) Then
ActiveCell.Value = Value
Selection.Offset(0, 1).Select
TextBox1.Value = ""
TextBox1.Activate
Else
'Do nothing
End If
End Sub
EDIT
I decided to clarify what is happening better. When using the _Change() function, the condition when I reach character 6 is fulfilled first, meaning the the code is seen as 608001 instead of 608001F as should be the case.
Upvotes: 0
Views: 6270
Reputation: 120
Something like this perhaps then? EDITED after better understanding the problem (see reply comments below):
Private m_previousBarcodeString As String
Private m_isFirstBarcodeEntered As Boolean
Private Sub UserForm_Initialize()
m_isFirstBarcodeEntered = True
' Some test data only. You don't need to use the rest of this
' method code below as you have a barcode scanner.
Dim barcodesArray(2) As String
barcodesArray(0) = "608001F"
barcodesArray(1) = "608001"
barcodesArray(2) = "001IN"
Dim barcodeIndex As Integer
Dim barcodeCount As Long
Dim charIndex As Integer
Dim charCount As Integer
barcodeCount = UBound(barcodesArray)
For barcodeIndex = 0 To barcodeCount
charCount = Len(barcodesArray(barcodeIndex))
For charIndex = 1 To charCount
TextBox1.Text = TextBox1.Text & Mid(barcodesArray(barcodeIndex), charIndex, 1)
Next charIndex
TextBox1.Text = ""
Next barcodeIndex
End Sub
Private Sub TextBox1_Change()
If (m_isFirstBarcodeEntered = True) Then
m_isFirstBarcodeEntered = False
Else
If Len(TextBox1.Text) = 0 Then
MsgBox "Was '" & m_previousBarcodeString & "' ending in 'F'?: " & _
UCase(isValidBarcode(m_previousBarcodeString))
Else
m_previousBarcodeString = TextBox1.Text
End If
End If
End Sub
Private Function isValidBarcode(ByVal singleBarcodesString As String) As Boolean
isValidBarcode = False
If Len(singleBarcodesString) = 7 Then
If UCase(Right(singleBarcodesString, 1)) = "F" Then
isValidBarcode = True
End If
End If
End Function
Upvotes: 0
Reputation: 12665
After clarifying with OP, the problem is this:
A possible solution coming to my mind is a timer which is waiting for the code scanner to write the code into the box, then running the code. Basically:
... to remember if the countdown has started yet or not.
Dim started As Boolean
... add the standard code to a macro which is not related to a Change
event:
Private Sub TextBox1_Change_Personal() '<-- not triggered if TextBox1 is changed!
Value = TextBox1.Value
If Value <> "" Then
If (Len(Value) = 7 And Right(Value, 1) = "F") Then
ActiveCell.Value = Value
ActiveSheet.Cells(ActiveCell.Row + 1, 1).Select
TextBox1.Value = ""
TextBox1.Activate
ElseIf (Len(Value) = 6 Or (Len(Value) = 5 And (Right(Value, 2) = "IN" Or Right(Value, 2) = "EM"))) Then
ActiveCell.Value = Value
Selection.Offset(0, 1).Select
TextBox1.Value = ""
TextBox1.Activate
Else
'Do nothing
End If
started = False '<-- reset control variable for next code
End Sub
... when the code scanner will start writing into the textbox, you "activate a countdown" (basically, you schedule your personal macro to start in 3 seconds). So, before the 3 seconds run, the code scanner will have finished to write the code and you don't fall into the same mistake.
Private Sub TextBox1_Change()
If started = False Then
Application.OnTime TimeSerial(Hour(Now()), Minute(Now()),Second(Now())+3), "TextBox1_Change_Personal"
started = True '<-- deactivating control variable to avoid re-scheduling each time
End If
End Sub
Of course, the 3 seconds
are a mock value; your code scanner might be much faster in writing the value into the box (in that case, decrease to 1 second for example) or slower (in that case, increase to 5 seconds for example).
Dim started As Boolean
Private Sub TextBox1_Change()
If started = False Then
Application.OnTime TimeSerial(Hour(Now()), Minute(Now()),Second(Now())+3), "TextBox1_Change_Personal"
started = True '<-- deactivating control variable to avoid re-scheduling each time
End If
End Sub
Private Sub TextBox1_Change_Personal() '<-- not triggered if TextBox1 is changed!
Value = TextBox1.Value
If Value <> "" Then
If (Len(Value) = 7 And Right(Value, 1) = "F") Then
ActiveCell.Value = Value
ActiveSheet.Cells(ActiveCell.Row + 1, 1).Select
TextBox1.Value = ""
TextBox1.Activate
ElseIf (Len(Value) = 6 Or (Len(Value) = 5 And (Right(Value, 2) = "IN" Or Right(Value, 2) = "EM"))) Then
ActiveCell.Value = Value
Selection.Offset(0, 1).Select
TextBox1.Value = ""
TextBox1.Activate
Else
'Do nothing
End If
started = False '<-- reset control variable for next code
End Sub
Upvotes: 1
Reputation: 12665
If I understood your problem, it seems you don't want the Change
event to be triggered until you don't give some sort of confirmation to say "I finished inserting the value".
In that case, what I might suggest is to write the code using a " "
separator (i.e. until you don't press SpaceBar
to confirm the successful insertion, nothing happens). In order to reach this, all you need is adding two new lines of code (see edit below):
Private Sub TextBox1_Change()
Value = TextBox1.Value
If Value <> "" Then
If Right(Value,1) = " " Then '<-- new line
If (Len(Value) = 7 And Right(Value, 1) = "F") Then
ActiveCell.Value = Value
ActiveSheet.Cells(ActiveCell.Row + 1, 1).Select
TextBox1.Value = ""
TextBox1.Activate
ElseIf (Len(Value) = 6 Or (Len(Value) = 5 And (Right(Value, 2) = "IN" Or Right(Value, 2) = "EM"))) Then
ActiveCell.Value = Value
Selection.Offset(0, 1).Select
TextBox1.Value = ""
TextBox1.Activate
Else
'Do nothing
End If
End If '<-- new line
End If
End Sub
Like that, your code will work like this:
1) You write 608001
...
Before: The Len() = 6
condition was triggered so you didn't have the time to eventually type the F
in;
Now: waiting for user confirmation
2) You write 608001F
...
Before: The Len() = 7
would have been triggered, but you didn't have the time to type the last char F
;
Now: waiting for user confirmation
3) Press SpaceBar
--> the code starts running and you will not confuse the 6 char
string with the 7 char
string any longer. Please note that pressing the SpaceBar
means "I'm submitting my barcode". Which means, you can replace the SpaceBar character with any other of the Chr()
collection (Enter
, a number, a letter etc.).
Upvotes: 0
Reputation: 93
You can use the InStr()
function to find if a character exists in the string, the function returns 0 if the character doesn't exist. Then simply check if the return value is greater than 0.
This simple example should give you a clue.
Sub lookForF()
Dim inVal As String
inVal = Range("A4").Value
If InStr(1, inVal, "F") > 0 Then
'Your code here when F exists
Else
'Your code here for other case
End If
End Sub
Upvotes: 0
Reputation: 120
Is it so that the string below is all in the same, single textbox?
608001F
608001
001IN
If so, use the SPLIT() function, passing in vbcrlf in order to get an array of each barcode, each line of text & loop through them.
If you're meaning the textbox only holds one of those codes at a time and 608001 replaces 608001F, then use a private variable in order to store the previous textbox value.
Private m_earlierBarcodeVal As String
Private Sub UserForm_Initialize()
m_earlierBarcodeVal = TextBox1.Text
End Sub
Private Sub TextBox1_Change()
MsgBox "Old value= " & m_earlierBarcodeVal & vbCrLf & _
"New value= " & TextBox1.Text
m_earlierBarcodeVal = TextBox1.Text
End Sub
Upvotes: 0