How to clear Textbox if case not found? - excel

I scan a barcode into an ActiveX textbox. It selects the relevant case and performs the calculation/event depending on the barcode. Every code is connected to an event.
One out of 100+ scans is not correctly decoded to the computer. As such, it does not match a case and does not make the textbox value "". It then appends to every other scan entering into the textbox. Aka "15 - FT - R" might scan in as "15 - FT -R".
I need the code to recognize this as a non case and delete it.
Since the barcode scans each character one at a time, nothing is equal to a case until the barcode value has completely entered the textbox.
Is there any way to tell if the barcode info is done being scanned?
My biggest challenge is how to stop the rest of the text from entering the box once it does not match a case.
My next biggest challenge is setting variables.
Private Sub TextBox1_Change()
Dim ws As Worksheet, v, e, f, g, k, i4
Set ws = Worksheets("Sheet1")
v = TextBox1.Value
e = 0
f = 0
g = 0
k = 0
i4 = 0
Select Case v
Case "15 - FT - R": f = 5
e = 11
k = 2
g = "15 - FT - R"
Case "150 - FT - C": f = 30
e = 11
k = 2
g = "150 - FT - C"
Case "R Waste": f = 4
e = 9
k = 2
g = "R Waste"
Case "C Waste": f = 4
e = 10
k = 2
g = "C Waste"
Case "Accident - 4": k = 5
'other cases here....
End Select
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'g = name of the item being used for the time stamp
'k = Case Selection
'i4 = Count for Cutting Station 1 timestamp, row reference
If k = 2 Then
'Coating Station
'accidental scan references for coating
ws.Cells(4, 4) = f
ws.Cells(5, 4) = e
ws.Cells(f, e) = ws.Cells(f, e) + 1
'adds master roll
i4 = ws.Cells(4, 30)
'count function
Cells(i4, 25).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i4, 26).Value = g
'formatting timestamp
TextBox1.Activate
TextBox1.Value = ""
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'k = Case Selection
'i4 = Count for Cutting Station 1 timestamp, row reference
ElseIf k = 5 Then
'Accidental scan
f = ws.Cells(4, 4)
e = ws.Cells(5, 4)
ws.Cells(f, e) = ws.Cells(f, e) - 1
i4 = ws.Cells(4, 30)
'count function
Cells(i4, 25).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i4, 26).Value = "Accident"
'formatting timestamp
TextBox1.Activate
TextBox1.Value = ""
End If
End Sub

Set TextBox properties:
EnterKeyBehavior TRUE
Multiline TRUE
Use this in your VBA _Change call back:
If Not Right(Me.Scan.Value, 1) = vbLf Then Exit Sub
In essence, we're now just looking for the LF character after enabling the multiline capability of the textbox.

Related

How to check if any sequential *pairs* of input are replicated between the two sets?

I have an Excel sheet with two sets of cells that require user input. The first set has 8 inputs, the second set has 5.
Let's say the Data Sets One and Two have user inputs of letters, like so:
DataSetOne(0) = A
DataSetOne(1) = B
DataSetOne(2) = C
DataSetOne(3) = D
DataSetOne(4) = E
DataSetOne(5) = F
DataSetOne(6) = G
DataSetOne(7) = H
DataSetTwo(0) = A
DataSetTwo(1) = B
DataSetTwo(2) = H
DataSetTwo(3) = D
DataSetTwo(4) = C
I need to check for replicated data. I only care if any two consecutive values are repeated, not just single values.
For example, Data Set One contains seven sequential "pairs" of input data:
Pair 1 = A, B
Pair 2 = B, C
Pair 3 = C, D
Pair 4 = D, E
Pair 5 = E, F
Pair 6 = F, G
Pair 7 = G, H
And similarly, Data Set Two has four additional pairs of data:
Pair 8 = A, B
Pair 9 = B, H
Pair 10 = H, D
Pair 12 = D, C
I need to see if any of these pairs match. Order does not matter - as long as two pairs have the same two individual inputs, I need to make a decision one way. If the pairs do not contain both matching values, then my decision goes a different way.
So in the above example, there are matches between:
Pair 1 and Pair 8
Pair 3 and Pair 12
To find the duplicates, i.e. values present in both of the lists, the easiest way to implement is to simply do a brute force search iterating over both lists. Depending on your application, this may be good enough.
For example:
Public Sub SO70184805_find_duplicates()
Dim DataSetOne(0 To 7) As String
Dim DataSetTwo(0 To 4) As String
Const Delimiter As String = ", "
DataSetOne(0) = "A"
DataSetOne(1) = "B"
DataSetOne(2) = "C"
DataSetOne(3) = "D"
DataSetOne(4) = "E"
DataSetOne(5) = "F"
DataSetOne(6) = "G"
DataSetOne(7) = "H"
DataSetTwo(0) = "A"
DataSetTwo(1) = "B"
DataSetTwo(2) = "H"
DataSetTwo(3) = "D"
DataSetTwo(4) = "C"
Dim PairsOne(0 To 6) As String
Dim PairsTwo(0 To 3) As String
Dim I As Integer
Dim S1 As Variant
Dim S2 As Variant
'Make the lists of pairs
Debug.Print "Pairs from the first list:"
For I = 0 To 6
If (DataSetOne(I) < DataSetOne(I + 1)) Then
PairsOne(I) = DataSetOne(I) & Delimiter & DataSetOne(I + 1)
Else
PairsOne(I) = DataSetOne(I + 1) & Delimiter & DataSetOne(I)
End If
Debug.Print (PairsOne(I))
Next I
Debug.Print
Debug.Print "Pairs from the second list:"
For I = 0 To 3
If (DataSetTwo(I) < DataSetTwo(I + 1)) Then
PairsTwo(I) = DataSetTwo(I) & Delimiter & DataSetTwo(I + 1)
Else
PairsTwo(I) = DataSetTwo(I + 1) & Delimiter & DataSetTwo(I)
End If
Debug.Print (PairsTwo(I))
Next I
Debug.Print
Debug.Print ("Duplicates:"):
Dim NumberOfDuplicates As Integer
NumberOfDuplicates = 0
For Each S1 In PairsOne
For Each S2 In PairsTwo
If (S1 = S2) Then
Debug.Print (S1)
NumberOfDuplicates = NumberOfDuplicates + 1
End If
Next
Next
End Sub
This is the output:
Pairs from the first list:
A, B
B, C
C, D
D, E
E, F
F, G
G, H
Pairs from the second list:
A, B
B, H
D, H
C, D
Duplicates:
A, B
C, D
Something along these lines, i'm heading off home now so can't do much more. I'll revisit later if possible. You'll need to add the scripting runtime reference to use the dictionary.
Sub datasets()
Dim datasetone(7) As String
Dim datasettwo(4) As String
Dim dicPairsOne As New Scripting.Dictionary
Dim dicPairsTwo As New Scripting.Dictionary
Dim l As Long
Dim strPair As String
datasetone(0) = "A"
datasetone(1) = "B"
datasetone(2) = "C"
datasetone(3) = "D"
datasetone(4) = "E"
datasetone(5) = "F"
datasetone(6) = "G"
datasetone(7) = "H"
datasettwo(0) = "A"
datasettwo(1) = "B"
datasettwo(2) = "H"
datasettwo(3) = "D"
datasettwo(4) = "C"
For l = 0 To UBound(datasetone) - 1
strPair = datasetone(l) & "," & datasetone(l + 1)
If Not dicPairsOne.Exists(strPair) Then
dicPairsOne.Add strPair, 1
Else
dicPairsOne(strPair) = dicPairsOne(strPair) + 1
End If
If Not dicPairsOne.Exists(StrReverse(strPair)) Then
dicPairsOne.Add StrReverse(strPair), 1
Else
dicPairsOne(StrReverse(strPair)) = dicPairsOne(StrReverse(strPair)) + 1
End If
Next l
For l = 0 To UBound(datasettwo) - 1
strPair = datasettwo(l) & "," & datasettwo(l + 1)
If Not dicPairsTwo.Exists(strPair) Then
dicPairsTwo.Add strPair, 1
Else
dicPairsTwo(strPair) = dicPairsTwo(strPair) + 1
End If
Next l
For l = 0 To dicPairsOne.Count - 1
If dicPairsTwo.Exists(dicPairsOne.Keys()(l)) Then
Debug.Print dicPairsOne.Keys()(l)
End If
Next l
End Sub

Create List of unique elements and display group membership parsed by commas and en-dash

I'm an Excel VBA newbie and I'm trying to figure out how to create a unique list of names in one column with associated group names in the next column.
For example, the Name "cds" is a member of the following groups: "group1","group3","group4","group5", and "group6".
I would like the output to show:
|Column D | Column E |
cds group1, group3–group6
I did find a Macro on a different message board that displays the unique element with the associated Group Number(s) instead of Group Name(s). Membership in consecutive group numbers are represented by the en-dash, otherwise group numbers are separated by commas.
The sample output below shows a list of Names and the associated Group Number which I have copied and pasted from another spreadsheet. The Macro creates the output found in Column D and Column E. Given the key shown in Columns G and H, Is it possible to replace the associated group numbers in Column E with the "Group Name" found in Column H? Thanks for your help!
|Column A | Column B | Column C | Column D | Column E | Column F | Column G | Column H |
Row 1 NAME GROUP # NAME (UNIQUE) GROUP(#s) Group # (Key) Group Name (Key)
Row 2 cds 1 abc 1, 9-10 1 group1
Row 3 cds 3 cds 1, 3, 4-6 2 group2a
Row 4 cds 4 xyz 7-8 3 group3
Row 5 cds 5 zzz 10 4 group4b
Row 6 cds 6 5 group5
Row 7 abc 10 6 group6
Row 8 abc 9 7 group7
Row 9 xyz 7 8 group8_1
Row 10 xyz 8 9 group9_Z
Row 11 zzz 10 10 group10A
Here is the associated code I used:
Sub OrganizeByNumber()
Dim a, i As Long, e, x, temp, buff
a = Range("a2").CurrentRegion.Value
With CreateObject("Scripting.Dictionary")
For i = 2 To UBound(a, 1)
If Not .exists(a(i, 1)) Then
Set .Item(a(i, 1)) = _
CreateObject("System.Collections.ArrayList")
End If
.Item(a(i, 1)).Add a(i, 2)
Next
For Each e In .keys
.Item(e).Sort
x = .Item(e).ToArray
temp = x(0) & Chr(150)
If UBound(x) > 0 Then
For i = 1 To UBound(x)
If x(i) - x(i - 1) = 1 Then
buff = x(i)
Else
temp = temp & buff
If temp Like "*" & Chr(150) Then temp = Left$(temp, Len(temp) - 1)
temp = temp & ", " & x(i) & Chr(150)
buff = ""
End If
Next
If buff <> "" Then
temp = temp & buff
Else
temp = Left$(temp, Len(temp) - 1)
End If
.Item(e) = Array(e, temp)
Else
.Item(e) = Array(e, Replace(temp, Chr(150), ""))
End If
Next
Range("d2").Resize(.Count, 2).Value = _
Application.Transpose(Application.Transpose(.items))
End With
End Sub
It's just a matter of replacing the code numbers in the string with the matching group name.
I used the VLookup worksheet function, but, depending on the size of your data and the speed with which it runs, there are faster routines (especially with a sorted list).
Since the original code did not output the names in sorted order, I did not do that. But it should be fairly simple to implement. One way would be use the SortedList object.
Edit: As pointed out by #T.M. in the comments below, there is a bug in the routine. The bug is actually in your original code, which I unfortunately assumed was working.
I didn't go into it in detail, but under certain circumstances, the buff variable is not getting cleared.
I have changed the code below to ensure buff is always cleared after processing; and I also added some code to sort the output by Name. The sorting code is taken from the link in the comments below.
EDIT2: Code added to remove instances where Name/Group# might be duplicated.
Option Explicit
Sub OrganizeByNumber()
Dim a, b, i As Long, e, x, temp, buff
Dim d As Object
a = Range("a2").CurrentRegion.Value
b = Range("g2").CurrentRegion.Value
Set d = CreateObject("Scripting.Dictionary")
With d
For i = 2 To UBound(a, 1)
If Not .exists(a(i, 1)) Then
Set .Item(a(i, 1)) = _
CreateObject("System.Collections.ArrayList")
End If
.Item(a(i, 1)).Add a(i, 2)
Next i
For Each e In .keys
.Item(e).Sort
deDupArrList .Item(e)
x = .Item(e).ToArray
'temp = x(0) & Chr(150)
temp = WorksheetFunction.VLookup(x(0), b, 2, False) & Chr(150)
If UBound(x) > 0 Then
For i = 1 To UBound(x)
If x(i) - x(i - 1) = 1 Then
'buff = x(i)
buff = WorksheetFunction.VLookup(x(i), b, 2, False)
Else
temp = temp & buff
If temp Like "*" & Chr(150) Then temp = Left$(temp, Len(temp) - 1)
'temp = temp & ", " & x(i) & Chr(150)
temp = temp & ", " & WorksheetFunction.VLookup(x(i), b, 2, False) & Chr(150)
buff = ""
End If
Next i
If buff <> "" Then
temp = temp & buff
Else
temp = Left$(temp, Len(temp) - 1)
End If
.Item(e) = Array(e, temp)
Else
.Item(e) = Array(e, Replace(temp, Chr(150), ""))
End If
buff = ""
Next e
sortDict d
Range("d2").Resize(.Count, 2).Value = _
Application.Transpose(Application.Transpose(.items))
End With
End Sub
Sub sortDict(dict As Object)
Dim i As Long, key, al
'With CreateObject("System.Collections.SortedList")
Set al = CreateObject("System.Collections.SortedList")
With al
For Each key In dict
.Add key, dict(key)
Next
dict.RemoveAll
For i = 0 To .keys.Count - 1
dict.Add .getkey(i), .Item(.getkey(i))
Next
End With
End Sub
Sub deDupArrList(arrList As Object)
Dim i As Long
For i = arrList.Count - 1 To 0 Step -1
If arrList.indexof(arrList(i), 0) <> i Then arrList.removeat i
Next i
End Sub

Function deletes lines it shouldn't

When I execute this it will delete the "Refined" lines and when I comment this function out it the "Refined" lines don't get deleted. I inherited this code and I have added every section to has "Refined" because I'm attempting to add extra products besides "gas" and "oil" but I really don't know VBA or programming. I've just been winging it and it's mostly worked except this section.
My question is what's wrong with what I added to the code? I edited or added every line that has the word "refined" in it. It works as intended for oil and gas but will always delete the refined column. When it executes data for oil, gas, and refined populates the worksheet but it will instantly delete all the refined columns that it pulled in.
I don't have the proficient to rewrite it as a different do until loop without some sort of code template.
This function checks the Current Prices tab for any columns that are duplicates of the day before or weekends and deletes the column
Function PricesCleanup() As Boolean
Dim r, c As Integer
Dim removeCount As Integer
Dim removeColumn As Boolean
Dim isGas, isOil, isRefined As Boolean
c = FIRSTDATA_COL
removeCount = 0
Do Until IsEmpty(ws_currentprices.Cells(COMMODITY_ROW, c)) 'check every col of prices
'Start at the row of the first date and reset remove flag
r = FIRSTDATE_ROW
removeColumn = True
'Check each column, at least until there is a discrepancy between prices so we know it's not a holiday
Do Until ((r > 12 And IsEmpty(ws_currentprices.Cells(r, c))) Or r > 60 Or Not removeColumn)
'If the prices don't match, we know it's not a holiday
If (ws_currentprices.Cells(r, c) <> ws_currentprices.Cells(r, c + 1)) Then
'If the first row is empty or matches second row, it's likely due to near EoM index shifting and requires special handling
If r = FIRSTDATE_ROW Then
If IsEmpty(ws_currentprices.Cells(r, c)) Then
'Oil index swap
removeColumn = False
End If
If (ws_currentprices.Cells(r, c) = ws_currentprices.Cells(r + 1, c) And ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Gas") Then
'Gas index swap so clear cell and allow to continue but only if within the last few workdays of the month
If (DateDiff("d", WorksheetFunction.WorkDay(ws_currentprices.Cells(r, BUCKET_COL), -1), ws_currentprices.Cells(ASOFDATE_ROW, c)) > -3) Then
ws_currentprices.Cells(r, c).ClearContents
End If
End If
Else
'Not index related and no match, so don't remove column
removeColumn = False
End If
End If
r = r + 1
Loop
'Check for weekend dates or dates from prior month
If Weekday(ws_currentprices.Cells(ASOFDATE_ROW, c)) = 1 Or Weekday(ws_currentprices.Cells(ASOFDATE_ROW, c)) = 7 Or Month(ws_currentprices.Cells(ASOFDATE_ROW, c)) <> Month(ws_currentprices.Cells(ASOFDATE_ROW, BUCKET_COL)) Then
removeColumn = True
End If
'Remove column if flagged
If removeColumn Then
removeCount = removeCount + 1
ws_currentprices.Columns(c).EntireColumn.Delete
c = c - 1
End If
'Copy up spot price
If Not IsEmpty(ws_currentprices.Cells(FIRSTDATE_ROW, c)) Then
ws_currentprices.Cells(SPOT_ROW, c) = ws_currentprices.Cells(FIRSTDATE_ROW, c)
ElseIf Not IsEmpty(ws_currentprices.Cells(FIRSTDATE_ROW + 1, c)) Then
ws_currentprices.Cells(SPOT_ROW, c) = ws_currentprices.Cells(FIRSTDATE_ROW + 1, c)
Else
ws_currentprices.Cells(SPOT_ROW, c) = ""
End If
c = c + 1
Loop
'Check if any columns are left and return bool value
isGas = False
isOil = False
isRefined = False
c = FIRSTDATA_COL
Do Until IsEmpty(ws_currentprices.Cells(COMMODITY_ROW, c))
If (ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Gas") Then
isGas = True
ElseIf (ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Oil") Then
isOil = True
ElseIf (ws_currentprices.Cells(MARKETTYPE_ROW, c) = "Refined") Then
isRefined = True
End If
c = c + 1
Loop
If (isGas And isOil And isRefined) Then
PricesCleanup = True
Else
PricesCleanup = False
End If
End Function

Why does this vba macro ignores the value after an if else?

I have two columns, the first one is a date with Year/Month format and the other a numerical value of an evaluation that i have done. I want to get the average value for each month with a macro( i need to do it so many times an a lot of data on it). So, i decided to create an array of dates and a Matrix of evaluation results. The goal is to group all numeric values by date and get the average per month. The problem is that this code ignores the value when the actual and last cells are different.
Dim i As Integer 'number of rows
Dim J As Integer 'manage row change
Dim G As Integer 'manage column change
Dim Fecha(48) As String
Dim Matriz_FI(100, 100) As Double
'-------------------------------------------------------------- --
J = 0
G = 0
For i = 2 To 10
If i = 2 Then
Matriz_FI(J, G) = Sheets("Nueva Database").Cells(i, 11).Value
Fecha(J) = Sheets("Nueva Database").Cells(i, 3).Value
G = G + 1
Else
If (Sheets("Nueva Database").Cells(i, 3).Value = Sheets("NuevaDatabase").Cells(i - 1, 3).Value) Then
'Column change in Matriz_FI
Matriz_FI(J, G) = Sheets("Nueva Database").Cells(i, 11).Value
G = G + 1
MsgBox ("Same")
Else
'Row change in Matriz_FI
J = J + 1
Fecha(J) = Sheets("Nueva Database").Cells(i, 3)
G = 0
Matriz_FI(J, G) = Sheets("Nueva Database").Cells(i, 11).Value
MsgBox ("Different")
End If
End If
Next
End Sub

Generation of sequential serial number based on prefix value

We have prefix defined already (say ABC, GIJ, THK, JLK ...so on) and want to create a sequential number when a user wants to generate a number for each of these prefix like given below:
ABC0000 , ABC0001 , ABC0002 ...ABC9999 same for GIJ0000 , GIJ0001 , GIJ0002 ...GIJ9999.
Given below is the code written for the above logic, but it does not achieve the requirement:
Private Sub CommandButton1_Click()
With ComboBox1.Value
Dim a, b As String
Dim i, j, k, l, x, q, m, temp As Long
a = ComboBox1.Text
i = Application.WorksheetFunction.Match(a, Range("A1:A1000"), 0)
j = Cells(i, 2)
l = j * 1000
For q = 2 To 100
For m = 2 To 100
If Cells(q, m).Value < 0 Then
k = m
End If
Next
Next
x = l
If Cells(i, GC).Value = temp Then
click = click + 1
Else
click = 0
End If*
Cells(i, GC) = x + click
TextBox1.Text = x + click
temp = Cells(i, GC).Value
End With
GC = GC + 1
End Sub
VBA does not seem necessary for this. Assuming you have your prefixes in separate cells in ColumnA starting in Row1, put in B1:
=A1&TEXT(COUNTIF(A$1:A1,A1)-1,"0000")
and double-click its fill handle.
From your code, I assume that you have a ComboBox named ComboBox1, a CommandButton named CommandButton1 and a TextBox named TextBox1, all on a UserForm, and with ComboBox1 filled with the possible values for prefixes.
The following code will put the next available code(1) for the selected prefix into the TextBox.
Private Sub CommandButton1_Click()
Dim a As String
Dim i As Long, j As Long
a = ComboBox1.Text
i = Application.WorksheetFunction.Match(a & "9999", Range("A1:A1000"), 1)
j = CLng(Mid$(Cells(i, 1).Value, Len(a) + 1)) + 1
TextBox1.Text = a & Format(j, "0000")
End Sub
Your code is also doing a lot of unnecessary stuff.
(1) only if data is sorted.

Resources