Search code examples
excelvbaerror-handlingruntime-error

Error handling in a loop using Resume Next


as a newcomer to VBA any help would be appreciated. The basic point of my program is to loop through columns of the spreadsheet and count the number of non-blank cells in each column, within a specified range. Here is an example of what my spreadsheet looks like.

1 2 3
1 thing
2 thing
3 thing

When all the cells in the column are blank, VBA throws out a 1004 error, no cells found. What I want to do is say, if a 1004 error occurs, set the count of the non-blank cells (nonBlank = 0) equal to zero, and if no error occurs, count normally. In something like Python, I'd use try/except. Here is my attempt.

For i = 1 To 3
    
    On Error Resume Next
    Set selec_cells = Sheet1.Range(Sheet1.Cells(FirstRow, i), Sheet1.Cells(LastRow, i)).SpecialCells(xlCellTypeVisible).Cells.SpecialCells(xlCellTypeConstants)
    
    If Err.Number <> 1004 Then
        nonBlank = 0
    Else
        nonBlank = selec_cells.Count
    End If
    On Error GoTo -1

 Next i

My issue is, when I run this code, it spits out 0 every time, even though column 2 should return 3. Thank you!

Edit: selec_cells is what throws out the error.


Solution

  • Error Handling

    • There is no On Error Goto -1 in VBA, it's a VB thing (those are links to different pages). A tip would be if you google VBA stuff, just put VBA in front of what you're looking for.

    • When using On Error Resume Next (defer error trapping), you should 'apply' it on a line or two maximally and 'close' with On Error Goto 0 (disable error trapping) or with another error handler.

    • Your usage of On Error Resume Next is unacceptable because in this particular case we can test the range: 1. defer error handling, 2. try to set the range, 3. disable error handling. If there was an error the range will not be set hence If Not rg Is Nothing Then which could be translated to something like 'If rg Is Something Then' (double negation) or If a reference to a range has been created Then.

    • The second solution illustrates a case where the main error handler is handling all errors except the SpecialCells error which has its own error handler. Resume Next means continue with the line after the line where the error occurred. Note the Exit Sub line and note Resume ProcExit where the code is redirected to a label.

    • The following illustrates two ways how you could handle this. At this stage, I would suggest you use the first one and remember to use the 'closing' On Error Goto 0 whenever you use On Error Resume Next (a line or two).

    The Code

    Option Explicit
    
    Sub testOnErrorResumeNext()
        
        Const FirstRow As Long = 2
        Const LastRow As Long = 11
        
        Dim rg As Range ' ... additionally means 'Set rg = Nothing'.
        Dim nonBlank As Long ' ... additionally means 'nonBlank = 0'.
        Dim j As Long
        
        For j = 1 To 3 ' Since it's a column counter, 'j' or 'c' seems preferred.
            
            ' Since you're in a loop, you need the following line.
            Set rg = Nothing
            On Error Resume Next
            Set rg = Sheet1.Range(Sheet1.Cells(FirstRow, j), _
                Sheet1.Cells(LastRow, j)).SpecialCells(xlCellTypeVisible) _
                .Cells.SpecialCells(xlCellTypeConstants) 
            On Error GoTo 0
            
            If Not rg Is Nothing Then
                nonBlank = rg.Cells.Count
            Else
                ' Since you're in a loop, you need the following line.
                nonBlank = 0
            End If
        
            Debug.Print nonBlank
    
        Next j
    
    End Sub
    
    Sub testOnError()
        
        On Error GoTo clearError
        
        Const FirstRow As Long = 2
        Const LastRow As Long = 11
        
        Dim rg As Range ' ... additionally means 'Set rg = Nothing'.
        Dim nonBlank As Long ' ... additionally means 'nonBlank = 0'.
        Dim j As Long
        
        For j = 1 To 3 ' Since it's a column counter, 'j' or 'c' seems preferred.
            
            ' Since you're in a loop, you need the following line.
            Set rg = Nothing
            On Error GoTo SpecialCellsHandler
            Set rg = Sheet1.Range(Sheet1.Cells(FirstRow, j), _
                Sheet1.Cells(LastRow, j)).SpecialCells(xlCellTypeVisible) _
                .Cells.SpecialCells(xlCellTypeConstants) 
            On Error GoTo clearError
            
            If Not rg Is Nothing Then
                nonBlank = rg.Cells.Count
            End If
              
            Debug.Print nonBlank
    
        Next j
        
    ProcExit:
        Exit Sub ' Note this.
    
    SpecialCellsHandler:
        ' Since you're in a loop, you need the following line.
        nonBlank = 0
        Resume Next
    
    clearError:
        MsgBox "Run-time error '" & Err.Number & "': " & Err.Description
        Resume ProcExit
    
    End Sub