Check duplicate on multiple userform textbox value - excel

Im still working to improve my library booklist. This is previous question to check duplicate value while user entering the details (https://stackoverflow.com/a/60014470/6409413).
While Im testing this, I thinking its better and faster to create a "templist" on sheet2, then click a button on the userform to get all the details instead of typing or copy/pasting into the userform textbox. So,
Private Sub GetButton_Click()
With Me
.TitleTextBox.Value = Cells(ActiveCell.Row, "B").Value
.AuthorTextBox.Value = Cells(ActiveCell.Row, "C").Value
.CopyTextBox.Value = Cells(ActiveCell.Row, "D").Value
.ISBNTextBox.Value = Cells(ActiveCell.Row, "E").Value
.CallNoTextBox.Value = Cells(ActiveCell.Row, "F").Value
.PublicationTextBox.Value = Cells(ActiveCell.Row, "G").Value
End With
''Selection.EntireRow.Font.Strikethrough = True
End Sub
Then, once all the textbox filled, I want to check for the duplicate data on the main list. So, I try something like below:
Private Sub CheckButton_Click()
Dim FoundCell As Range
Dim Search As String
Dim ws As Worksheet
Set ws = Worksheets("booklist")
Search = TitleTextBox.Text
Set FoundCell = ws.Columns(2).Find(Search, LookIn:=xlValues, Lookat:=xlWhole)
On Error GoTo ErrMsg
If FoundCell Is Nothing Then
Title_checker.Caption = ChrW(&H2713)
Else
Title_checker.Caption = "Duplicate" & " " & FoundCell.Address
End If
FoundCell.Select
Exit Sub
ErrMsg:
MsgBox "Select booklist sheet!"
End Sub
Im learned from previous question, Im only can "find" once each time. But, I want to check on three data for the duplicate value which is title on column B, ISBN on column E and CallNo at column F. Im not sure how to implement this answer (https://stackoverflow.com/a/60014470/6409413) on my previous question into my new "CheckButton". COuld someone help?

Using the same Sub from the previous question:
Private Sub CheckButton_Click()
DupCheck TitleTextBox.Text, 2, Title_checker
DupCheck ISBNTextBox.Text, 5, ISBN_checker
DupCheck CallNoTextBox.Text, 6, CallNo_checker
End Sub
Sub DupCheck(txt, ColNo As Long, theLabel As Object)
Dim m
With Worksheets("booklist")
m = Application.Match(txt, .Columns(ColNo), 0)
If Not IsError(m) Then
theLabel.Caption = "Duplicate" & " " & .Cells(m, ColNo).Address
.Activate '<< added: select the sheet
.Rows(m).Select
Else
theLabel.Caption = ChrW(&H2713)
End If
End With
End Sub

Related

VBA Userform posting data twice....sometimes

I have a userform with a combobox on a sheet "PostHistory" that draws it's data from the "Staff" sheet. When you press Add on the userform it's suppose to locate the name on the Staff Sheet and replace the date next to the name. Occasionally, it will replace the date and the date next to the name below it. Using Excel 2016
Private Sub CommandButton7_Click()
Application.ScreenUpdating = False
Sheets("Staff").Visible = True
Sheets("Engine").Visible = True
Dim TargetRow As Integer
Dim nameRange As Range
Set nameRange = Sheets("Staff").Range("C3:C200")
TargetRow = Sheets("Engine").Range("D3").Value
Sheets("PostHistory").Range("B3").EntireRow.Insert Shift:=xlDown
Sheets("PostHistory").Range("B3").Value = txt_date
Sheets("PostHistory").Range("C3").Value = cb_staff
Sheets("PostHistory").Range("D3").Value = txt_post
Sheets("PostHistory").Range("E3").Value = txt_notes
If (Augment.txt_date.Text) = "" Then
GoTo Skip1
ElseIf IsNull(Augment.txt_date.Value) = False Then
End If
For Each cell In nameRange.Cells
If cell.Text = [cb_staff] Then
cell.Offset(0, -1).Value = txt_date
End If
Next
Skip1:
Unload Augment
Sheets("Staff").Visible = False
Sheets("Engine").Visible = False
Sheets("List").Visible = False
Application.ScreenUpdating = True
Augment.Show
End Sub
To start: I didn't find the reason why your code should write more than once. But I believe the code below will not write anything twice.
Private Sub CommandButton7_Click()
' 209
Dim nameRange As Range
Dim Fnd As Range
Dim Ctls() As String
Dim i As Integer
Ctls = Split("txt_Date,cb_Staff,txt_Post,txt_Notes", ",")
If Len(txt_Date) Then
With Worksheets("Staff")
Set nameRange = .Range(.Cells(3, 3), .Cells(.Rows.Count, 3).End(xlUp))
End With
Set Fnd = nameRange.Find(cb_Staff.Value, , xlValues, xlWhole)
If Not Fnd Is Nothing Then Fnd.Offset(0, -1).Value = txt_Date.Value
End If
With Worksheets("PostHistory")
.Rows(3).EntireRow.Insert Shift:=xlDown
With .Rows(3)
For i = 0 To UBound(Ctls)
.Cells(3 + i).Value = Me.Controls(Ctls(i)).Value
Me.Controls(Ctls(i)).Value = ""
Next i
End With
End With
End Sub
In principle, you don't need to unhide a sheet in order to read from or write to it. Also, if the sheet to which you write is hidden, there is no point in stopping ScreenUpdating. Finally, I did like the way you found to clear all controls but believe that it will interfere with your management of the list in the combo box. Therefore I showed you another method above.
Oh, yes. I created a userform called Augment with one combo box, 3 text boxes and one CommandButton7. I hope that is what you also have.

Edit (adjacent) cells with Find()

I'm writing a small macro for searching and sorting barcodes.
The idea is that barcodes are scanned into cell C1, then the macro is suppose to count the amount of times the same code is scanned. If the barcode is not already in the list (column B:B) it should add the new barcode in the list (column B:B).
I've managed utilised the Find() syntax, however I can't manage to edit any cells with it. Only thing I am able to do is MsgBox " " Ive tried:
Range("a5").Value = 5
It doesn't work
This is the code I currently have:
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("C1") = "" Then MsgBox "No input"
Dim barcodes As Range
Set barcodes = Range("B:B").Find(What:=Range("C1").Value, After:=Range("B2"), LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=True, MatchByte:=True, SearchFormat:=False)
If Not barcodes Is Nothing And Not Range("C1") = "" Then
MsgBox "Found"
End If
If barcodes Is Nothing And Not Range("C1") = "" Then
MsgBox "New product"
End If
End Sub
For MsgBox "Found" I want instead a code that counts the amount of times the same barcode has been scanned in the adjacent cell to the right.
And for Msgbox "New product" I want to write a part that adds the new code to the list in this case Column B:B
The the below will A) verify that you don't have a match (using IsError, which returns boolean) to determine if you need to add a value and start the scan count at 1, or B) if you need to find the previous entry (using Match()) and add to the counter:
If IsError(Application.Match(Cells(1,3).Value,Columns(2),0)) Then
lr = cells(rows.count,2).end(xlup).row
Cells(lr+1,2).Value = Cells(1,3).Value
Cells(lr+1,1).Value = 1
Else
r = Application.match(Cells(1,3).Value,Columns(2),0)
cells(r,1).value = cells(r,1).value + 1
End If
Edit1:
Updated column #s for second subroutine per comment from OP, while stripping out the first subroutine and rewording.
With this code you will need a sheet called "DataBase" where you will store each scan and later will be the source for example for a pivot table:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Barcode As String, i As Long, wsDB As Worksheet, LastRow As Long
Dim DictBarcodes As New Scripting.Dictionary 'You need to check the Microsoft Scripting Runtime reference for this to work
With Application
.EnableEvents = False
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Set wsDB = ThisWorkbook.Sheets("DataBase")
With Target
If .Range("C1") = vbNullString Then MsgBox "No input"
On Error Resume Next
'loop through all the barcodes and store them into a dictionary
For i = 1 To .Rows.Count
If .Cells(i, 2) = vbNullString Then Exit For 'skip the loop once a blank cell is found
DictBarcodes.Add .Cells(i, 1), i 'this will raise an error if there are duplicates
Next i
'If the value doesn't exist we add it to the list
If Not DictBarcodes.Exists(.Cells(1, 3)) Then
LastRow = .Cells(.Rows.Count, 2).End(xlUp).Row + 1
.Cells(LastRow, 2) = .Cells(1, 3)
End If
End With
'Either it exists or not, store it to the data base to keep tracking
With wsDB
.Cells(1, 1) = "Barcode"
.Cells(1, 2) = "Date Scan"
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(LastRow, 1) = .Cells(1, 3)
.Cells(LastRow, 2) = Now
End With
'Finally the output on the adjacent cell
Target.Cells(1, 4) = Application.CountIf(wsDB.Range("A:A"), Target.Cells(1, 3))
With Application
.EnableEvents = True
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub

Connect newly added Sheet to existing one

This is my first post in Stack Overflow so any mistake I make please just ignore.
So i made an button which runs the macro of an application inputbox, the name you enter in the inputbox will create a new sheet with the name you entered, it also will create a table on the new sheet. The name you put on the inputbox are the clients that newly came so i will have specific sheet with table for every client that comes.
On the other hand I got the Workers which will receive incomes from clients, I Got 4 Workers which have their own Sheet and Table of Incomes and Outcomes.
Now the question i am getting to is that, is it possible to creade a code on VBA that will say: If on the new sheet (inside the table, specificly: K8:K23, K28:K43, K49:K64) the name of the Worker is inserted, copy the name of the client and paste it into the existing sheet of the Worker.
The code i tried but did not work: (Only Check the First Sub and the end of line, the between code is just a bunch of macro for table to be created, that parts work, the problem of my code which is located at the end is that it does nothing, and yes I did an commend to the codes on purpose)
Sub KerkimiKlientit()
Dim EmriKlientit As String
Dim rng As Range, cel As Range
Dim OutPut As Integer
retry:
EmriKlientit = Application.InputBox("Shkruani Emrin e Klientit", "Kerkimi")
If Trim(EmriKlientit) <> "" Then
With Sheets("Hyrjet").Range("B10:B200")
Set rng = .Find(What:=EmriKlientit, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not rng Is Nothing Then
sheet:
Flag = 0
Count = ActiveWorkbook.Worksheets.Count
For i = 1 To Count
WS_Name = ActiveWorkbook.Worksheets(i).Name
If WS_Name = EmriKlientit Then Flag = 1
Next i
If Flag = 1 Then
ActiveWorkbook.Sheets(EmriKlientit).Activate
Exit Sub
Else
Sheets.Add(, Sheets(Sheets.Count)).Name = EmriKlientit
Call KrijimiTabeles(EmriKlientit)
Exit Sub
End If
Else
OutPut = MsgBox("Klienti nuk u gjet", vbRetryCancel + vbInformation, "Provoni Perseri")
If (OutPut = vbRetry) Then
GoTo retry:
ElseIf (OutPut = vbCancel) Then
Exit Sub
End If
Exit Sub
End If
End With
End If
If userInputValue = "" Then
OutPut = MsgBox("Rubrika e Emrit e zbrazet", vbRetryCancel + vbExclamation, "Gabim")
If (OutPut = vbRetry) Then
GoTo retry:
ElseIf (OutPut = vbCancel) Then
Exit Sub
End If
Else
GoTo retry:
End If
End Sub
Sub KrijimiTabeles(EmriKlientit As String)
'
' KrijimiTabeles Macro
'
'This was just an middle code, it was too long so I did not paste it. Not an important part tho.
'This is the part that does not work, it just does nothing for some reason, there are multiple codes here and I tried them all.
'Sub Formula(EmriKlientit As String, ByVal Target As Range)
'ActiveWorkbook.Sheets(EmriKlientit).Activate
'If Not Application.Intersect(Range("K8:K23"), Range(Target.Adress)) Is Nothing Then
'Call Formula1
'End If
'End Sub
'Dim LR As Long, i As Long
'Application.ScreenUpdating = False
'Dim Rng As Range
'For Each Rng In Range("K8:K23")
'Select Case Rng.Value
'Case "M"
'Worksheets(EmriKlientit).Range("K2").Copy
'Worksheets("Mustafa").Range("K6").PasteSpecial Paste:=xlPasteFormulas
'End Select
'Next Rng
'Application.ScreenUpdating = True
'For Each cel In Rng
'If cel.Value = "M" Then
'Worksheets(EmriKlientit).Range("K2").Copy
'Worksheets("Mustafa").Range("K6").PasteSpecial Paste:=xlPasteFormulas
'End If
'Next cel
'ActiveWorkbook.Sheets(EmriKlientit).Activate
'If Not Application.Intersect(Range("K8:K23"), Range(Rng.Adress)) Is Nothing Then
'With Sheets(EmriKlientit)
'With .Range("K8:K23")
'If .Text = "M" Then
'Worksheets(EmriKlientit).Range("K2").Copy
'Worksheets("Mustafa").Range("K6").PasteSpecial Paste:=xlPasteFormulas
'End If
'End With
'End With
'End If
'Flag = 0
'Count = ActiveWorkbook.Worksheets.Count
'For i = 1 To Count
'WS_Name = ActiveWorkbook.Worksheets(i).Name
'If WS_Name = EmriKlientit Then Flag = 1
'Next i
'If Flag = 1 Then
'ActiveWorkbook.Sheets(EmriKlientit).Activate
'For Each Cell In Sheets(EmriKllientit).Range("K8:K23")
'If Cell.Value = "M" Then
'Range("K2").Copy
'Worksheets("Mustafa").Range("K6").PasteSpecial Paste:=xlPasteFormulas
'End If
'Next
'End If
End Sub
Thank you
I hope I was clear enough,
Any help would be appreciated.
Welcome to StackOverflow - i agree that your question can be a bit more specific...
I think what you are trying to achieve is something between this lines:
Dim wsClient As Worksheet, wsMustafa As Worksheet
Dim i As Long
Dim fRow As Long, lRow As Long
Set wsClient = ActiveWorkbook.Sheets("Client")
Set wsMustafa= ActiveWorkbook.Sheets("Mustafa")
'you can assign this through better ways, but to start with...
fRow = 8
lRow = 23
For i = fRow To lRow
If wsClient.Range("K" & i).Value = "M" Then
wsMustafa.Range("K6").Value = wsClient.Range("K" & i).Value 'or .Formula if that's what you want
End If
Next i
Hope this helps, good luck.

Loop through all font colored cells in a range

I extracted the data according to ciriteria and marked them as blue. I'm looking for help with a Macro which would loop through all font colored cells (Blue) in a range.
I want to use only font colored cells in a range and mark in different color. And Msgbox show data that meet the criteria.
I had trouble finding information on looping through cells which contain only a specified colour. Anyone know how this could be done?
Dim i As Long
Dim LastRow As Integer
LastRow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Msg = "Data:"
For i = 1 To LastRow
If Cells(i + 1, 2).Value - Cells(i, 2).Value <> 0 Then
Cells(i, 2).Font.Color = vbBlue
Cells(i, 1).Font.Color = vbBlue
For Each Cell In Range("A:B")
If Cells(i, 1).Font.Color = vbBlue And Cells(i + 1, 1).Value - Cells(i, 1).Value > 4 Then
Cells(i, 2).Font.Color = vbGreen
Cells(i, 1).Font.Color = vbGreen
End If
Next
Msg = Msg & Chr(10) & i & " ) " & Cells(i, 2).Value & " : " & " --> " & Cells(i, 1).Value
End If
Next i
MsgBox Msg, vbInformation
There are multiple issues with your code:
Your loops are nested. You are searching through all the data every time you prepare one line. ==> Move the inner loop behind the loop you're coloring in.
The result message Msg = Msg & Chr(10) & i is constructed outside of the If Cells(i, 1).Font.Color = vbBlue And... condition, meaning that every line will be written into the result String. Move this part inside the 2nd loop, and the string should be contain only blue lines.
Also, please don't loop through For Each Cell In Range("A:B"). This will examine every cell in those columns, way beyond those who contain actual data. Use LastRow as in the first loop.
I believe you should be able to use the Find function to do this....
For example, select some cells on a sheet then execute:
Application.FindFormat.Interior.ColorIndex = 1
This will colour the cells black
Now execute something like:
Debug.Print ActiveCell.Parent.Cells.Find(What:="*", SearchFormat:=True).Address
This should find those cells. So you should be able to define your required Font with the FindFormat function.
BTW, make sure to test to see if the range returned is nothing for the case where it cant find any matches..
Hope that helps.
Edit:
The reason I would use the find method is because your code checks each cell in two columns. The Find method should be much quicker.
You will need to have a Do - While loop to find all cells in a range which is common with the Find function in VBA.
If you run this function, it should debug the address of any font matches that you are looking for - for a particular sheet. This should give you the idea...
Sub FindCells()
Dim rData As Range, rPtr As Range
Set rData = ActiveSheet.Range("A:B")
Application.FindFormat.Clear
Application.FindFormat.Font.Color = vbBlue
Set rPtr = rData.Find(What:="*", SearchFormat:=True)
If Not rPtr Is Nothing Then
Debug.Print rPtr.Address
End If
Application.FindFormat.Clear
Application.FindFormat.Font.Color = vbGreen
Set rPtr = rData.Find(What:="*", SearchFormat:=True)
If Not rPtr Is Nothing Then
Debug.Print rPtr.Address
End If
End Sub
Ok then - sorry keep getting distracted..
This code will search for cells with your fonts for a particular data range.
I believe you just need to implement your logic into the code...
Option Explicit
Public Sub Test()
Dim rData As Range
Set rData = Sheet1.Range("A:B")
Call EnumerateFontColours(rData, vbBlue)
Call EnumerateFontColours(rData, vbGreen)
End Sub
Public Sub EnumerateFontColours(ByVal DataRange As Range, ByVal FontColour As Long)
Dim rPtr As Range
Dim sStartAddress As String
Dim bCompleted As Boolean
Application.FindFormat.Clear
Application.FindFormat.Font.Color = FontColour
Set rPtr = DataRange.Find(What:="*", SearchFormat:=True)
If Not rPtr Is Nothing Then
sStartAddress = rPtr.Address
Do
'**********************
Call ProcessData(rPtr)
'**********************
Set rPtr = DataRange.Find(What:="*", After:=rPtr, SearchFormat:=True)
If Not rPtr Is Nothing Then
If rPtr.Address = sStartAddress Then bCompleted = True
Else
bCompleted = True
End If
Loop While bCompleted = False
End If
End Sub
Public Sub ProcessData(ByVal r As Range)
Debug.Print r.Address
End Sub

Excel VBA lookup issue

I'm new to excel VBA though I tried putting efforts but of no luck.
Problem Statement:
I have a sheet with Source (color white) row and Destination (color Yellow) row, for each source there is a corresponding destination row in next line. I have to look for an application name which user input at the beginning and will search throughout the sheet (more than 10000 rows) in column 6 and it must extract the source row also if found in destination and destination row also if found in source row in sheet2.
And also one cell may have many application name within it so it should trim all other app names from that cell and leave only the searched app name.
Here is the partial code i tried :
Sub GetInterfaceCounts()
Dim RANGEBOTTOM As String
Dim cell
Dim strAction As String
Dim intAdd As Integer
Dim strName As String
intAdd = 0
RANGEBOTTOM = "G700"
strName = InputBox(Prompt:="Please enter the application name.", _
Title:="Application Name", Default:="Application")
For Each cell In Range("G2:" & RANGEBOTTOM)
strAction = cell.Value
If InStr(1, strAction, strName) <> 0 Then
intAdd = intAdd + 1
End If
Next
MsgBox "Total number of " & strName & " counts are :" & CStr(intAdd)
GetMS4AppInventory (strName)
End Sub
Sub GetMS4AppInventory(strName As String)
Dim strAction
Dim intAdd As Integer
Dim RowIndex As Integer
RowIndex = 0
Sheets("Sheet1").Select
'For Each cell In Range("G2:G700")
With Worksheets("Sheet1").Range("G2:G700")
Set strAction = .Find(strName, LookIn:=xlValues)
'strAction = cell.Value
If Not strAction Is Nothing Then
Do
If InStr(1, strAction, strName) <> 0 Then
Rows(strAction.Row).Select
Selection.Copy
Sheets("MS4Inventory").Select
Rows(RowIndex + 1).Select
Selection.Insert Shift:=xlDown
Rows(RowIndex + 2).Select
Application.CutCopyMode = False
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Cells(RowIndex + 3, 1).Select
End If
Set strAction = .FindNext(strAction) //gets hanged here go to infinite loop
Loop While Not strAction Is Nothing
End If
End With
End Sub
If anybody could help me it will be great else manually doing seggregation of inventory will suck me.
Regards,
Vijay
When you use FindNext, you have to store the first found cell's address and compare it. strAction, in your example, will never be Nothing because FindNext will keep finding the first cell that had it.
I'm not sure how your white and yellow rows factor into this, but here's a basic structure for finding cells and copy their rows. Maybe you can modify it to your needs or clarify what your existing data looks like.
Sub GetInterfaceCounts()
Dim sName As String
Dim rFound As Range
Dim lCount As Long
Dim sFirstAdd As String
'Get the application name from the user
sName = InputBox(Prompt:="Please enter the application name.", _
Title:="Application Name", Default:="Application")
'if the user doesn't press cancel
If Len(sName) > 0 Then
'Find the first instance of the application
Set rFound = Sheet1.Columns(7).Find(sName, , xlValues, xlPart, , , False)
'if something was found
If Not rFound Is Nothing Then
'Remember the first address where it was found
sFirstAdd = rFound.Address
Do
lCount = lCount + 1
'Copy the entirerow to the other sheet
rFound.EntireRow.Copy _
rFound.Parent.Parent.Sheets("MS4Inventory").Cells(lCount, 1).EntireRow
'Find the next instance
Set rFound = Sheet1.Columns(7).FindNext(rFound)
'if we've looped around to the first found, then get out
Loop Until rFound.Address = sFirstAdd
End If
MsgBox "Total number of " & sName & " counts are :" & lCount
End If
End Sub

Resources