Find a value within a column, then change a value elsewhere on the same row - excel

I am working on a project with an Excel "database" to keep track of production of items. There have been cases of people scanning an item more than once, which causes problems when it's time to send to the client.
I have an alert popup, to prevent people from scanning an item more than once unless dealing with a rework. If the item is present in the "database", there is a MsgBox with vbYesNo buttons. If people click "Yes", it's a rework. If people click "No", it's an error and they exit the sub.
I need a way to handle the rework and have it change the values of the cells in the same row as the original item.
Here's the code I have so far.
Private Sub gbatchd_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer) 'Check DB for duplicate value
Set depo = dbgrids.Sheets("Deposition")
Set found = depo.Columns("A").Find(what:=valuetofind, LookIn:=xlValues, lookat:=xlWhole)
valuetofind = gbatchd.Text
FR = depo.Range("A" & Rows.Count).End(xlUp).Row
If KeyCode = 13 Then
For i = 1 To FR
If gbatch.Cells(i, 1).Value = valuetofind Then
MsgBox "This batch has already been deposited!" & vbCrLf & "Rework?", vbYesNo, "Rework?"
If answer = vbNo Then
Exit Sub
Else
depo.Cells(found.Row, 5).Value = "Rework"
End If
End If
Next
End If
End Sub

Setting aside any criticism of the solution's architecture, what your code is missing is the assignment to the answer variable:
answer = MsgBox("This batch has already been deposited!" & vbCrLf & "Rework?", vbYesNo, "Rework?")
Use Option Explicit and declare your variables with the appropriate types (check out this article).
A cleaned-up version of your code might look something like this:
Option Explicit 'At the very top of your module.
'... Other code ...
Private Sub gbatchd_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer) 'Check DB for duplicate value
Dim wsDepo As Excel.Worksheet
Dim rngFound As Excel.Range
Dim sValueToFind As String
Dim answer As VbMsgBoxResult
If KeyCode = KeyCodeConstants.vbKeyReturn Then
'Barcode reader has sent the Enter (Return) key.
'Attempt to find the value.
sValueToFind = Trim(gbatchd.Text)
Set wsDepo = dbgrids.Worksheets("Deposition")
Set rngFound = wsDepo.Columns(1).Find(What:=sValueToFind, LookIn:=xlValues, LookAt:=xlWhole)
If Not rngFound Is Nothing Then
'Value was found. Ask whether it is a rework.
answer = MsgBox("This batch has already been deposited!" & vbCrLf & "Rework?", vbYesNo, "Rework?")
If answer = VbMsgBoxResult.vbYes Then
wsDepo.Cells(rngFound.Row, 5).Value = "Rework"
End If
End If
'Cleanup.
Set rngFound = Nothing
Set wsDepo = Nothing
End If
End Sub

Related

method find of object range failed in vba

I have written a code that finds all the dye word and sum all the dye word value.
Here is the code
Dim name As String
name = "dye"
Dim findDyeRange As Range
Set findDyeRange = Range("Q10:S61")
Set firstDyeWord = findDyeRange.Find(name)
If firstDyeWord Is Nothing Then
msgbox "nothing found"
Else
firstDyeValue = firstDyeWord.Offset(0, 1).Value
Set secondDyeWord = findDyeRange.FindNext(firstDyeWord)
If secondDyeWord.Address = firstDyeWord.Address Then
MsgBox firstDyeValue
Exit Sub
Else
secondDyeValue = secondDyeWord.Offset(0, 1).Value
Set thirdDyeWord = findDyeRange.FindNext(secondDyeWord)
If thirdDyeWord.Address = firstDyeWord.Address Then
MsgBox firstDyeValue + secondDyeValue
Exit Sub
Else
thirdDyeValue = thirdDyeWord.Offset(0, 1).Value
Set fourthDyeWord = findDyeRange.FindNext(thirdDyeWord)
If fourthDyeWord.Address = firstDyeWord.Address Then
MsgBox firstDyeValue + secondDyeValue + thirdDyeValue
Exit Sub
Else
fourthDyeValue = fourthDyeWord.Offset(0, 1).Value
Set fifthDyeWord = findDyeRange.FindNext(fourthDyeWord)
If fifthDyeWord.Address = firstDyeWord.Address Then
MsgBox firstDyeValue + secondDyeValue + thirdDyeValue + fourthDyeValue
Exit Sub
Else
fifthDyeValue = fifthDyeWord.Offset(0, 1).Value
Set sixthDyeWord = findDyeRange.FindNext(fifthDyeWord)
If sixthDyeWord.Address = firstDyeWord.Address Then
MsgBox firstDyeValue + secondDyeValue + thirdDyeValue + fourthDyeValue + fifthDyeValue
Exit Sub
Else
sixthDyeValue = sixthDyeWord.Offset(0, 1).Value
MsgBox firstDyeValue + secondDyeValue + thirdDyeValue + fourthDyeValue + fifthDyeValue + sixthDyeValue
End If
End If
End If
End If
End If
End If
the code runs well. But when I removes the msgbox and set a code then it throws an error.
I want this code
If firstDyeWord Is Nothing Then
Range("A9").value = 7
But it throws error "method find of object range failed in vba"
Help Please!
According to the documentation of the Range.Find method you must at least specify the parameters LookIn, LookAt, SearchOrder and MatchByte when using Find() otherwise it uses what ever was used last by either VBA or the user interface.
Since you cannot know what your users used last in the user interface your search might randomly work and randomly come up with wrong results. Therefore always specify all of these 4 parameters to make it reliable.
Additionally you must specify in which workbook/worksheet your ranges are. Otherwise Excel guesses and it might guess the wrong sheet.
Make sure to declare all your variables properly. I recommend always to activate Option Explicit: In the VBA editor go to Tools › Options › Require Variable Declaration.
Public Sub Example()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'set your workbook and worksheet!
Dim name As String
name = "dye"
Dim findDyeRange As Range
Set findDyeRange = ws.Range("Q10:S61") 'specify in which sheet the range is
Dim firstDyeWord As Range
Set firstDyeWord = findDyeRange.Find(What:=name, LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, MatchByte=False)
If firstDyeWord Is Nothing Then
'dye was NOT found
ws.Range("A9").Value = 7 'specify in which sheet the range is
Else
'do something else if dye was found
End If
End Sub
// Edit (see comment)
If this is used in an event like Worksheet_Change you need to turn off events before writing to a cell. Otherwise this will trigger another event which will trigger another event … and you get stuck in an endless loop of events, which cannot work:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'set your workbook and worksheet!
Dim name As String
name = "dye"
Dim findDyeRange As Range
Set findDyeRange = ws.Range("Q10:S61") 'specify in which sheet the range is
Dim firstDyeWord As Range
Set firstDyeWord = findDyeRange.Find(What:=name, LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, MatchByte=False)
If firstDyeWord Is Nothing Then
'dye was NOT found
On Error Goto REACTIVATE_EVENTS 'in any case of error reactivate events
Application.EnableEvents = False 'disable events or .Value = 7 triggers another change event.
ws.Range("A9").Value = 7 'specify in which sheet the range is
Application.EnableEvents = True 'make sure you never leave events disabled otherwise they will stay off until you restart Excel.
Else
'do something else if dye was found
End If
Exit Sub
REACTIVATE_EVENTS:
Application.EnableEvents = True
If Err.Number <> 0 Then Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext 'show error message if there was an error.
End Sub

VBA listbox updates

i have below VBA code to update long list(1000) of part userform listbox with constant changes to design.
i need help with below 2 issues i am facing with code,
1)somehow, it is only updating only 1st selected item under multiselect listbox. can you pl help to check what is the issue with it to get all selected items updated by command button?
also, there are number of duplicates that i want to updates as well. however, below code updates only one and not other duplicate. can you pl help to correct code so it can update duplicates as well?
Private Sub cmdaction_Click()
Dim t, t1 As String
Dim vrech As Range, lColumn As Range
Dim sh As Worksheet
Dim i As Long
Dim selItem As String
Set sh = ThisWorkbook.Sheets("part bump")
Set lColumn = sh.Range("P1:AZA1").Find(Val(txtchangenumber.Value), , xlValues, xlWhole)
'Set lcolumn1 = sh.Range("F4:F1000")
If UserForm3.txtchangedescrption.Value = "" Then
MsgBox "Please enter Change Description"
Exit Sub
End If
If UserForm3.txtchangenumber.Value = "" Then
MsgBox "Please enter Change Number"
Exit Sub
End If
If UserForm3.cmbaction.Value = "" Then
MsgBox "Please Select part Action"
Exit Sub
End If
If lColumn Is Nothing Then
MsgBox "Change number not found"
Exit Sub
End If
With UserForm3.lstDatabase
For i = 0 To UserForm3.lstDatabase.ListCount - 1
If UserForm3.lstDatabase.Selected(i) = True Then
Set vrech = sh.Range("H4:H250").Find(.Column(7, i), , xlValues, xlWhole)
If Not vrech Is Nothing Then
Select Case cmbaction.Value
Case "RP"
t = Chr(Asc(Mid(.List(i, 7), 2, 1)) + 1)
t1 = Mid(.List(i, 7), 1, 2) & t & Mid(.List(i, 7), 4, 1)
Intersect(vrech.EntireRow, lColumn.EntireColumn) = t1
MsgBox "Selected parts 'RP' Action completed"
Case "RV"
Intersect(vrech.EntireRow, lColumn.EntireColumn) = .List(i, 7)
MsgBox "Selected parts 'RV' Action completed"
Case "DP"
Intersect(vrech.EntireRow, lColumn.EntireColumn) = "Deleted"
vrech.EntireRow.Font.Strikethrough = True
MsgBox "Selected parts 'DP' Action completed"
End Select
End If
End If
Next i
End With
End Sub
Upon further investigation I found that your handling of the Selected property is correct. I have deleted my advice in this regard and apologize for my hasty comment.
I have also re-examined your code and regret, I can't find a reason why it shouldn't deal with all selected items. without access to your workbook i don't have the ability to test and can't help you further.
Your second complaint is caused by this line of code.
Set vrech = sh.Range("H4:H250").Find(.Column(7, i), , xlValues, xlWhole)
It will find the first instance and no others. If you want the search to be repeated a loop will be required that repeats the search. Look up "VBA Find & FindNext MSDN" and you will find code samples how to construct the loop.
Note that in Dim t, t1 As String only t1 is a string. t is defined as a variant by virtue of not having a specified data type. This doesn't appear to be your intention.
I also noted your unusual use of Application.Intersect. Intersect(vrech.EntireRow, lColumn.EntireColumn) should be the equivalent of the simpler Sh.Cells(vrech.Row, lColumn), and it's recommended to specify the Value property when assigning a value to it.

Insert a row in a data table at a special position under conditions

I've been working on the development of a tool that is supposed to help me manage some projects.
I have a table of data called t_data.
This data table contains every projects. Each project is devided on quarters (Q1 2019, Q2 2019, Q3 2019, etc.). Each quarter is devided on deliverables (not always the same number of deliverables so not the same amount of rows for each quarter).
I have a form in another sheet (name of the sheet: MENU!) that permits to add a new deliverable to a Quarter of a project, and where I put the necessary inputs so that I can find the good raw where I should insert my deliverable. The inputs are the project's name (in MENU!D10) and the quarter concerned by the deliverable (in MENU!D12).
Here is my code :
Sub ajouter_un_livrable()
'
' ajouter_un_livrable Macro
' Ajoute un livrable en fonction de son challenge et de son trimestre.
'
Dim result As Variant
match_formula = "EQUIV(1;(t_data[Associated_challenge] = MENU!$D$10)*(t_data[Associated_quarter] = MENU!$D$12);0)"
result = Evaluate(match_formula)
numero_ligne = CLng(result)
numero_ligne = numero_ligne - 2003
Worksheets("TRT RTI Challenges").Rows(numero_ligne).insert
'Set datasheet = Worksheets("TRT RTI Challenges").ListObjects("t_data")
'With datasheet
'.Cells(numero_ligne, 10).Select
'Selection.ListObject.ListRows.Add (numero_ligne)
'Set myNewDeliverable = .ListRows.Add(numero_ligne)
'End With
'
End Sub
You'll notice I'm french ehe
numero_ligne sounds to return the number 2015 because I have an error 2015... great !
I don't know how to manage the EVALUATE. How can I take its value into a variable ? I've tried a lot of things, consult a lot of forums but nothing's working :'(
Do you have an idea of how I could solve my issue ?
Thanks a lot to the one or those that will help me or at least try. :D
I believe something like this should work for you:
Sub ajouter_un_livrable()
Dim wsInput As Worksheet
Dim rProjects As Range
Dim rQuarters As Range
Dim rFound As Range
Dim vProject As Variant
Dim vQuarter As Variant
Dim sProjectCell As String
Dim sQuarterCell As String
Dim sFirst As String
Dim bMatch As Boolean
sProjectCell = "D10"
sQuarterCell = "D12"
On Error Resume Next
Set wsInput = ActiveWorkbook.Worksheets("MENU")
Set rProjects = Range("t_Data").ListObject.ListColumns("Associated_challenge").DataBodyRange
Set rQuarters = Range("t_Data").ListObject.ListColumns("Associated_quarter").DataBodyRange
On Error GoTo 0
If wsInput Is Nothing Or rProjects Is Nothing Or rQuarters Is Nothing Then
MsgBox "Unable to find a worksheet named 'MENU' or unable to find a table named 't_Data' in this workbook.", , "Error"
Exit Sub
End If
vProject = wsInput.Range(sProjectCell).Value
vQuarter = wsInput.Range(sQuarterCell).Value
If Len(vProject) = 0 Then
wsInput.Select
wsInput.Range(sProjectCell).Select
MsgBox "Input for Project is required.", , "Error"
Exit Sub
ElseIf Len(vQuarter) = 0 Then
wsInput.Select
wsInput.Range(sQuarterCell).Select
MsgBox "Input for Quarter is required.", , "Error"
Exit Sub 'No data
End If
bMatch = False
Set rFound = rProjects.Find(vProject, rProjects.Cells(rProjects.Cells.Count), xlValues, xlWhole, , xlNext, False)
If Not rFound Is Nothing Then
sFirst = rFound.Address
Do
If LCase(rQuarters.Worksheet.Cells(rFound.Row, rQuarters.Column).Value) = LCase(vQuarter) Then
bMatch = True
Exit Do
End If
Set rFound = rProjects.FindNext(rFound)
Loop While rFound.Address <> sFirst
If bMatch Then
rFound.EntireRow.Insert
'Row inserted, proceed with what you want to do with the inserted row here
End If
Else
MsgBox "Unable to find matching row for :" & Chr(10) & "Project: " & vProject & Chr(10) & "Quarter: " & vQuarter, , "Error"
End If
End Sub

check in- check out sytem using a barcode scanner

I'm trying to create a check in/out system at a lab I work at. I'm not to experienced at using VBA. I was able to tinker with some formulas to get it to do what I wanted, but I wasn't fully successful in getting all the steps I wanted done.
So what I'm trying to do is check in samples using a barcode followed by a date in the cell right next to it.
I want this formula to apply to A2000 so I can check in multiple samples. I'm using an input box and I want this input box to be able to detect matched samples and place them in the checked out column C followed by a date in the cell right next to it.
I would appreciate any help you guys can give me.
Here's the code I am currently using.
Private Sub Worksheet_Activate()
Dim myValue As Variant
Dim code As Variant
Dim matchedCell As Variant
myValue = InputBox("Please scan a barcode")
Range("A2").Value = myValue
Set NextCell = Cells(Rows.Count, "A").End(xlUp)
If NextCell.Row > 1 Then NextCell = NextCell.Offset(1, 0)
Set matchedCell = Range("a2:a2000").Find(what:=code, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=True)
If myValue = True Then Paste ("C2;C2000")
If Not matchedCell Is Nothing Then matchedCell.Offset(-1, 1).Value = Now
End Sub
To add data safety, I would differentiate the Check-In and the Check-Out process.
I'm not sure how you get the Code from the scanner ? Copied to prompt automatically ?
Anyway, below is my solution:
1.Transform your table into an excel table (CTRL+T) and name it "STORE_RECORDS" as below:
2.Create a module and paste following code:
Option Explicit
Sub Check_In()
Dim Code As String: Code = InputBox("Please scan a barcode", "Scan procedure")
If Code = "" Then MsgBox ("No code scanned"): Exit Sub
Dim NbChIn As Integer: NbChIn = Application.CountIf(Range("STORE_RECORDS[CHECK-IN]"), Code)
Dim NbChOut As Integer: NbChOut = Application.CountIf(Range("STORE_RECORDS[CHECK-OUT]"), Code)
If NbChIn > NbChOut And NbChIn > 0 Then
MsgBox ("This item is already Checked-In" & Chr(10) & "Please check it out and retry"): Exit Sub
Else
Cells(Rows.Count, 1).End(xlUp).Offset(1, 0) = Code
Cells(Rows.Count, 1).End(xlUp).Offset(0, 1) = Now
End If
End Sub
Sub Check_Out()
Dim Code As String: Code = InputBox("Please scan a barcode", "Scan procedure")
If Code = "" Then MsgBox ("No code scanned"): Exit Sub
Dim NbChIn As Integer: NbChIn = Application.CountIf(Range("STORE_RECORDS[CHECK-IN]"), Code)
Dim NbChOut As Integer: NbChOut = Application.CountIf(Range("STORE_RECORDS[CHECK-OUT]"), Code)
If NbChIn = NbChOut And NbChIn > 0 Then
MsgBox ("This item is already Checked-Out" & Chr(10) & "Please check it in and retry"): Exit Sub
Else
If Range("STORE_RECORDS[CHECK-IN]").Find(Code, , , xlWhole, , xlPrevious) Is Nothing Then MsgBox ("No match, ask Carlos !"): Exit Sub
Range("STORE_RECORDS[CHECK-IN]").Find(Code, , ,xlWhole , , xlPrevious).Offset(0, 2) = Code
Range("STORE_RECORDS[CHECK-IN]").Find(Code, , ,xlWhole , , xlPrevious).Offset(0, 3) = Now
End If
End Sub
3.Link Check-In and Check-Out buttons to respective procedures and you should be good to go.

Is it possible to increase the 256 character limit in excel validation drop down boxes?

I am creating the validation dynamically and have hit a 256 character limit. My validation looks something like this:
Level 1, Level 2, Level 3, Level 4.....
Is there any way to get around the character limit other then pointing at a range?
The validation is already being produced in VBA. Increasing the limit is the easiest way to avoid any impact on how the sheet currently works.
I'm pretty sure there is no way around the 256 character limit, Joel Spolsky explains why here: http://www.joelonsoftware.com/printerFriendly/articles/fog0000000319.html.
You could however use VBA to get close to replicating the functionality of the built in validation by coding the Worksheet_Change event. Here's a mock up to give you the idea. You will probably want to refactor it to cache the ValidValues, handle changes to ranges of cells, etc...
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ValidationRange As Excel.Range
Dim ValidValues(1 To 100) As String
Dim Index As Integer
Dim Valid As Boolean
Dim Msg As String
Dim WhatToDo As VbMsgBoxResult
'Initialise ValidationRange
Set ValidationRange = Sheet1.Range("A:A")
' Check if change is in a cell we need to validate
If Not Intersect(Target, ValidationRange) Is Nothing Then
' Populate ValidValues array
For Index = 1 To 100
ValidValues(Index) = "Level " & Index
Next
' do the validation, permit blank values
If IsEmpty(Target) Then
Valid = True
Else
Valid = False
For Index = 1 To 100
If Target.Value = ValidValues(Index) Then
' found match to valid value
Valid = True
Exit For
End If
Next
End If
If Not Valid Then
Target.Select
' tell user value isn't valid
Msg = _
"The value you entered is not valid" & vbCrLf & vbCrLf & _
"A user has restricted values that can be entered into this cell."
WhatToDo = MsgBox(Msg, vbRetryCancel + vbCritical, "Microsoft Excel")
Target.Value = ""
If WhatToDo = vbRetry Then
Application.SendKeys "{F2}"
End If
End If
End If
End Sub

Resources