Object problems with .Find() method

JimSnyder

Board Regular
Joined
Feb 28, 2011
Messages
125
First of all, I am working on a macro in Excel 2003 on a Windows XP box. I work in Excel and VBA once in a while.

This macro was written by me months ago and has worked fine running daily. The users have asked for new features and that is where I am having problems.

An error log is generated in one tracking system and exported as type ".log". My macro imports it into sheet1 of a template workbook and distributes the errors to each of the factories to review. The errors are part of a training tracking system and the latest addition is to get rid of all the previously existing errors. To do this, I placed 29,703 errors on sheet2 to compare each imported log file against.

The spreadsheet has over 50 columns, so I chose the few key columns to concatenate and placed them out beyond the 50 columns in a column of their own. The formula for cells in that column is the same on sheet1 and sheet2. It is simply "=CONCATENATE(A4,B4,AM4)".

The errors I am battling are mismatched types and Object or With variable not declared. I am off for the day, so I will respond in the morning to any additional questions.

Here are the declarations:

Code:
    ' Declare macro wide variables
    Dim currentRow As Integer, sheetIndex As Integer
    Dim rowCount As Long, lastRow As Long
    Dim pctDone As Single
    Dim Filename As String, currentCell As String
    Dim curCell As Range, curRange As Range, tarRange As Range, tarCell As Range

And here is the problem section of code:

Code:
    ' ============================== Compare errors to baseline errors ================================================
    ' Update progress bar
    ProgressBar.LabelCaption = "Comparing errors to baseline..."
    ProgressBar.FrameRibbon.Caption = "0%"
    ProgressBar.LabelRibbon.Width = 0
    DoEvents
 
    ' Copy concatenation formula into sheet1 after import
    ActiveWorkbook.Sheets(2).Activate             ' Get formula
    Range("AT1").Select
    Selection.Copy
    ActiveWorkbook.Sheets(1).Activate             ' Paste formula
    Columns("AT").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
    Range("A1").Select
 
    ' Get a count of rows from the old errors sheet for looping
    ActiveWorkbook.Sheets(2).Activate             ' Get formula
    Set curRange = Range([AT1].End(xlUp), [AT65536].End(xlUp))
    rowCount = curRange.Rows.Count
    Set tarCell = Cells(1, 46)
 
    ' Find each row in Sheet2 and delete from Sheet1
    For rowIndex = 1 To rowCount
 
        ' Calculate the percent done and update and ribbon
        pctDone = sheetIndex / Sheets.Count
        With ProgressBar
            .FrameRibbon.Caption = Format(pctDone, "0%")
            .LabelRibbon.Width = pctDone * .FrameRibbon.Width
        End With
 
        ActiveWorkbook.Sheets(2).Activate             ' Get current row
        currentCell = (Cells(rowIndex, "AT").Value)
        ActiveWorkbook.Sheets(1).Activate
        Set tarRange = Range([AT1].End(xlUp), [AT65536].End(xlUp))
 
        ' Search sheet1 for every occurrence of the row
        With tarRange
'            Set tarCell = .Find(What:=currentCell, After:=ActiveCell, LookIn:=xlValues, _
                LookAt:=xlWhole, SearchOrder:=xlByRows).Offset(-1, 0)
'            Set tarCell = .Find(What:=currentCell, _
                                After:=Cells(1, 46), _
                                LookIn:=xlValues, _
                                LookAt:=xlWhole, _
                                SearchOrder:=xlByRows, _
                                SearchDirection:=xlNext, _
                                MatchCase:=False)
            Set tarCell = .Find(What:=currentCell, _
                                LookIn:=xlValues)
            If Not tarCell Is Nothing Then
                firstAddress = c.Address
                tarCell.Offset(1, 0).EntireRow.Delete
 
                ' Loop until every copy of the row is deleted
                Do
                    Set tarCell = .FindNext(tarCell)
                Loop While Not tarCell Is Nothing And tarCell.Address <> firstAddress
            End If
        End With
 
    Next rowIndex
 
    ' Hide the old errors sheet
    ActiveWorkbook.Sheets(2).Activate             ' Hide from users
    ActiveWindow.SelectedSheets.Visible = False
 
    ' Delete the concatenation column from sheet 1
    ActiveWorkbook.Sheets(1).Activate             ' Return home
    Columns("AT:AT").Select                       ' Delete the work column
    Selection.Delete Shift:=xlToLeft
    Range("A1").Select
    Application.Wait (Now + TimeValue("0:00:01")) ' Show completion

As the code sits, I am returning no errors, but also am finding "nothing". I can eyeball a watch and the spredsheet and verify that the data is there and matches. When I use more detailed "Find" instructions, it dies on the "Find".
 

Excel Facts

Back into an answer in Excel
Use Data, What-If Analysis, Goal Seek to find the correct input cell value to reach a desired result
One question, where in all that code are you getting the error(s)?

Just having a quick look at the code I can see quite a few places there could be problems.

It's mostly unqualified references and the use of Activate/Select etc.

If the problem is why Find those could be the culprits.

eg unqualified references causing the wrong range to he searched
 
Upvote 0
Give something like this a try. Note: The ProgressBar portion of the code wasn't updated.

Code:
    ' Declare macro wide variables
    Dim currentRow As Integer, sheetIndex As Integer
    Dim rowCount As Long, lastRow As Long
    Dim pctDone As Single
    Dim Filename As String, currentCell As String
    
    Dim curCell As Range, curRange As Range, tarRange As Range
    Dim wsErrors As Worksheet, wsLog As Worksheet

' ============================== Compare errors to baseline errors ================================================
    
    Set wsErrors = ActiveWorkbook.Sheets(2)
    Set wsLog = ActiveWorkbook.Sheets(1)
    
    ' Update progress bar
'    ProgressBar.LabelCaption = "Comparing errors to baseline..."
'    ProgressBar.FrameRibbon.Caption = "0%"
'    ProgressBar.LabelRibbon.Width = 0
    
    ' Get a count of rows from the old errors sheet for looping
    With wsErrors
        Set curRange = .Range("AT1", .Range("AT" & Rows.Count).End(xlUp))
        rowCount = curRange.Rows.Count
        Set tarCell = .Range("AT1")
    End With
    
    ' Target range to search for and delete matches
    Set tarRange = wsLog.Range("AT1:AT" & wsLog.Cells.Find("*", , , , xlByRows, xlPrevious).Row)
    ' Write concatenation formula into sheet1 after import
    tarRange.FormulaR1C1 = "=CONCATENATE(RC1,RC2,RC39)"     ' write formula
    tarRange.Value = tarRange.Value                         ' replace formulas with values
 
    ' Find each match from Sheet2 and delete from Sheet1
    For Each curCell In curRange
 
        ' Calculate the percent done and update and ribbon
'        pctDone = sheetIndex / Sheets.Count
'        With ProgressBar
'            .FrameRibbon.Caption = Format(pctDone, "0%")
'            .LabelRibbon.Width = pctDone * .FrameRibbon.Width
'        End With
 
        ' Search sheet1 for every occurrence of currentCell
        Set tarCell = tarRange.Find(What:=curCell, _
                                    LookIn:=xlValues, _
                                    LookAt:=xlWhole, _
                                    SearchOrder:=xlByRows, _
                                    SearchDirection:=xlNext, _
                                    MatchCase:=False)

        ' Loop until every copy of the row is found and tagged for deletion
        Do While Not tarCell Is Nothing
            tarCell.Value = "X"
            Set tarCell = tarRange.FindNext(tarCell)
        Loop
        
    Next curCell
    
    ' Delete all tagged rows
    ' Uses Autofilter to display only Xed rows
    tarRange.AutoFilter Field:=1, Criteria1:="X"
    tarRange.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    If tarRange(1).Value = "X" Then tarRange(1).EntireRow.Delete
    wsLog.AutoFilterMode = False
 
    ' Hide the old errors sheet '(No need to unhide the sheet in the 1st place)
    'wsErrors.Visible = False             ' Hide from users
 
    ' Delete the concatenation column from sheet 1
    wsLog.Columns("AT").ClearContents             ' Delete the work column
    wsLog.Activate
    wsLog.Range("A1").Select
    'Application.Wait (Now + TimeValue("0:00:01")) ' Show completion

End Sub
 
Upvote 0
Norie:

The place where it is failing is that curCell never gets anything from the find. If you can point out some of the problems you see, I am willing to learn.


AlphaFrog:

With the exception of changing the prefix on the variables to match the rest, I knitted your code unchanged into my script and am still returning nothing from the find. I may have overlooked something as I typed it in by hand so that I could think through what I was typing. Do you see the problem?

Code:
    ' ============================== Compare errors to baseline errors ================================================
    ' Assign variables to worksheets
    Set currentErrors = ActiveWorkbook.Sheets(2)
    Set targetLog = ActiveWorkbook.Sheets(1)
 
    ' Reset progress bar
    ProgressBar.LabelCaption = "Comparing errors to baseline..."
    ProgressBar.FrameRibbon.Caption = "0%"
    ProgressBar.LabelRibbon.Width = 0
    DoEvents
 
    ' Get a count of rows from the old errors sheet for looping
    With currentErrors
        Set curRange = .Range("AT1", .Range("AT" & Rows.Count).End(xlUp))
        rowCount = curRange.Rows.Count
        Set tarCell = .Range("AT1")
    End With
 
    ' Target range to search for and delete matches
    Set tarRange = targetLog.Range("AT1:AT" & targetLog.Cells.Find("*", , , , xlByRows, xlPrevious).Row)
 
    ' Write concatenation formula into sheet1 after import
    tarRange.FormulaR1C1 = "CONCATENATE(RC1,RC2,RC39)"     ' Write formula
    tarRange.Value = tarRange.Value                        ' Replace formulas with values
 
 
    ' Find each match from Sheet2 and delete from Sheet1
    For Each curCell In curRange
 
        ' Calculate the percent done and update and ribbon
        pctDone = currentRow / rowCount
        currentRow = currentRow + 1
        With ProgressBar
            .FrameRibbon.Caption = Format(pctDone, "0%")
            .LabelRibbon.Width = pctDone * .FrameRibbon.Width
        End With
 
        ' Display progressbar updates
        DoEvents
 
        ' Search sheet1 for every occurrence of the row
        Set tarCell = tarRange.Find(What:=curCell, _
                                    LookIn:=xlValues, _
                                    LookAt:=xlWhole, _
                                    SearchOrder:=xlByRows, _
                                    SearchDirection:=xlNext, _
                                    MatchCase:=False)
 
        ' Loop until every copy of the row is found and tagged for deletion
        Do While Not tarCell Is Nothing
            tarCell.Value = "X"
            Set tarCell = tarRange.FindNext(tarCell)
        Loop
 
    Next curCell
 
    ' Delete all tagged rows
    ' Uses AutoFilter to display only Xed rows
    tarRange.AutoFilter Field:=1, Criteria1:="X"
    tarRange.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    If tarRange(1).Value = "X" Then tarRange(1).EntireRow.Delete
    targetLog.AutoFilterMode = False
 
    ' Hide the old errors sheet
    ActiveWorkbook.Sheets(2).Activate             ' Hide from users
    ActiveWindow.SelectedSheets.Visible = False
 
    ' Delete the concatenation column from sheet 1
    targetLog.Columns("AT").ClearContents
    targetLog.Activate
    targetLog.Range("A1").Select
    Application.Wait (Now + TimeValue("0:00:01")) ' Show completion

Since the activates are gone, I doubt that they are the problem, but I would be happy for any explanation of what is going on. I do not just want this to run, but to learn from experts so that I can do better in the future.
 
Last edited:
Upvote 0
Just to better explain the problem, I am enclosing links to images:

http://screencast.com/t/uLJ9OXzVW
http://screencast.com/t/DfdUSyIr

uLJ9OXzVW


DfdUSyIr
 
Upvote 0
Your original code had multiple problems so I thought it would be best to more or less rewrite it. Here are a few issues I noticed in the original code.

This was suppose to delete the entire row of the matched cell from column AT...
Code:
tarCell.Offset(1, 0).EntireRow.Delete
It deletes the row below the matched cell because of the offset. Is that what you wanted? It didn't make sense to me to delete the row below. Also, if you were to delete tarCell, that makes tarCell equal to Nothing because you deleted it. You couldn't then do a .FindNext(tarCell) because tarCell is nothing. That's why in the new code I just tagged each matched row in column AT with an X and then later filtered and deleted all the X'ed rows.

This was suppose to loop and delete all the subsequent matches in column AT.
Code:
                ' Loop until every copy of the row is deleted
                Do
                    Set tarCell = .FindNext(tarCell)
                Loop While Not tarCell Is Nothing And tarCell.Address <> firstAddress
It loops but wouldn't do anything to the other matches found. The only code within the loop is to FindNext. But it doesn't do anything to the foundnext results.



The new code I provided did function with the test data I made up. I tried my best to use your original code as a template. Below are some things you should test or check in the new code and report back.
  • If you have any error handling code (like On Error Resume Next ) prior to this new code , that error handling code should be disabled to help diagnose any potential problems.
  • You mentioned previously that "I can eyeball a watch". Can you see if tarCell finds a match? Do you know how to step through the code or put a Breakpoint in the code? If yes, that could greatly help in diagnosing it.
    Debugging Excel VBA Code

...I would be happy for any explanation of what is going on. I do not just want this to run, but to learn from experts so that I can do better in the future.

The code is commented and it attempts to replicate what your original code did except more efficiently. I don't know how to better explain it. If you have a specific question on a bit of code, I'd be happy to expand on that.
 
Upvote 0
AlphaFrog:

Thanks for the covering of the problems with the original code. The ForNext portion was just unfinished because I was unable to get the For part to work. The offset was from another row deletion thread in the forum, and I did not do it correctly.

I added a reply with screenshots of debugging showing a valid value in curCell when Find is called, and nothing being returned in tarCell. Since the other object involved is the range, I stepped through and saw that the Find in the command to set the range returned a valid range of 29707 rows.

I didn't mind you rewriting it and learned a lot from your code. I am using SnagIt to publish screenshots of the debugging session and am open to anything else to try. Here is the tarRange expanded a bit:

http://screencast.com/t/vUModqxfai
 
Upvote 0
You are missing an equal sign in the CONCATENATE formula.

Code:
tarRange.FormulaR1C1 = "[COLOR="Red"]=[/COLOR]CONCATENATE(RC1,RC2,RC39)"     ' Write formula
 
Upvote 0
That was it! Much thanks for the fix and the training. I am posting 'finished' code for anyone in the future looking for the same solution:

Code:
    ' ============================== Compare errors to baseline errors ================================================
    ' Assign variables to worksheets
    Set staticErrors = ActiveWorkbook.Sheets(2)
    Set importLog = ActiveWorkbook.Sheets(1)
 
    ' Reset progress bar
    ProgressBar.LabelCaption = "Comparing errors to baseline..."
    ProgressBar.FrameRibbon.Caption = "0%"
    ProgressBar.LabelRibbon.Width = 0
    DoEvents
 
    ' Get a count of rows from the sheet of old errors for looping
    With staticErrors
        Set curRange = .Range("AT1", .Range("AT" & Rows.Count).End(xlUp))
        rowCount = curRange.Rows.Count
        lastRow = Cells.SpecialCells(xlCellTypeLastCell).Row      ' Last row test
    End With
 
    ' Target range to search for and delete matches
    Set tarRange = importLog.Range("AT1:AT" & importLog.Cells.Find("*", , , , xlByRows, xlPrevious).Row)
 
    ' Write concatenation formula into sheet1 after import
    tarRange.FormulaR1C1 = "=CONCATENATE(RC1,RC2,RC39)"     ' Write formula
    tarRange.Value = tarRange.Value                        ' Replace formulas with values
 
    ' Find each match from Sheet2 and delete from Sheet1
    For Each curCell In curRange
 
        ' Calculate the percent done and update progressbar
        pctDone = currentRow / rowCount
        currentRow = currentRow + 1
        With ProgressBar
            .FrameRibbon.Caption = Format(pctDone, "0%")
            .LabelRibbon.Width = pctDone * .FrameRibbon.Width
        End With
 
        ' Display progressbar updates
        DoEvents
 
        ' Search sheet1 for every occurrence of the row
        Set tarCell = tarRange.Find(What:=curCell, _
                                    LookIn:=xlValues, _
                                    LookAt:=xlWhole, _
                                    SearchOrder:=xlByRows, _
                                    SearchDirection:=xlNext, _
                                    MatchCase:=False)
 
        ' Loop until every copy of the row is found and tagged for deletion
        Do While Not tarCell Is Nothing
            tarCell.Value = "X"
            Set tarCell = tarRange.FindNext(tarCell)
        Loop
 
    Next curCell
 
    ' Delete all tagged rows
    ' Uses AutoFilter to display only Xed rows
    tarRange.AutoFilter Field:=1, Criteria1:="X"
    tarRange.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    If tarRange(1).Value = "X" Then tarRange(1).EntireRow.Delete
    importLog.AutoFilterMode = False
 
    ' Hide the old errors sheet
    ActiveWorkbook.Sheets(2).Activate             ' Hide from users
    ActiveWindow.SelectedSheets.Visible = False
 
    ' Delete the concatenation column from sheet 1
    importLog.Columns("AT").ClearContents
    importLog.Activate
    importLog.Range("A1").Select
    Application.Wait (Now + TimeValue("0:00:01")) ' Show Progressbar completion

Elegant solution, AlphaFrog!
 
Upvote 0

Forum statistics

Threads
1,224,587
Messages
6,179,741
Members
452,940
Latest member
rootytrip

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top