简体   繁体   中英

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.

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

My preference is, wherever possible, to encapsulate the line of code that may cause an error in its own function. The function returns true or false to indicate whether or not there is an error and an out parameter is used to return the value that you want.

This keeps the error testing confined within a very short well defined function.


Sub ttest()

    Dim mySheet As Excel.Worksheet
    Set mySheet = ThisWorkbook.Sheet1
    
    Dim myIndex As Long
    Dim myNonBlank as long
    For myIndex = 1 To 3
    
        If AllCellsAreBlank(mySheet.Range(ThisWorkbook.Sheet1.Cells(myFirstRow, myIndex), mySheet.Cells(myLastRow, myIndex)), myIndex, mySelectCells) Then
        
            myNonBlank = 0
            
        Else
        
            myNonBlank = mySelectCells.Count
            
        End If
        
    Next
    
End Sub



Public Function AllCellsAreBlank(ByRef ipRange As Excel.Range, ByVal ipIndex As Long, ByRef opSelectCells As Range) As Boolean

    On Error Resume Next
    set opSelectCells = ipRange.SpecialCells(xlCellTypeVisible).Cells.SpecialCells(xlCellTypeConstants)
    AllCellsAreBlank = Err.Number <> 0
    On Error GoTo 0
    
End Function

For reference the prefixes I use are

  • ip: for an input only parameter
  • iop: for an input parameters that will be changed by the method
  • op: for a parameter only used to return a value
  • my: any variable declared within a Method.

I's also suggest you acquire the habit of meaningful descriptive names, myRow, myCol are much more meaningful than i,j, and of ensuring you use fully qualified references rather than the implicit use of the activesheet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM