3

I am new to VBA. I am currently trying to apply a loop on a user defined function. The defined function is as follows.

  Function CountColor(InRange As range, ColorIndex As Long, _
    Optional OfText As Boolean = False) As Long
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' CountColor
' This function counts the cells in InRange whose ColorIndex
' is equal to the ColorIndex parameter. The ColorIndex of the
' Font is tested if OfText is True, or the Interior property
' if OfText is omitted or False. If ColorIndex is not a valid
' ColorIndex (1 -> 56, xlColorIndexNone, xlColorIndexAutomatic)
' 0 is returned. If ColorIndex is 0, then xlColorIndexNone is
' used if OfText is Fasle or xlColorIndexAutomatic if OfText
' is True. This allows the caller to use a value of 0 to indicate
' no color for either the Interior or the Font.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim R As range
Dim N As Long
Dim CI As Long

If ColorIndex = 0 Then
    If OfText = False Then
        CI = xlColorIndexNone
    Else
        CI = xlColorIndexAutomatic
    End If
Else
    CI = ColorIndex
End If


Application.Volatile True
Select Case ColorIndex
    Case 0, xlColorIndexNone, xlColorIndexAutomatic
        ' OK
    Case Else
        If IsValidColorIndex(ColorIndex) = False Then
            CountColor = 0
            Exit Function
        End If
End Select

For Each R In InRange.Cells
    If OfText = True Then
        If R.Font.ColorIndex = CI Then
            N = N + 1
        End If
    Else
        If R.Interior.ColorIndex = CI Then
            N = N + 1
        End If
    End If
Next R

CountColor = N


End Function

I am trying to use this function CountColor in a Sub. But it throws a runtime 424 error.

Sub Summary()    
    LastColumn = Cells(1, Columns.Count).End(xlToLeft).Column
    LastRow = Cells(Rows.Count, 1).End(xlUp).Row

        For i = 2 To LastRow
        TOTALFAILS = CountColor((range(Cells(i, 4), Cells(i, LastColumn))), 38)
        Cells(i, LastColumn + 8) = TOTALFAILS

        Next i
End Sub

Could you please help me figure out what am doing wrong? Any help will be deeply appreciated. Thanks

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
Rohin Raj
  • 33
  • 2
  • In your loop, you are passing 2 range variables into your function. Your function requires a range, long, and an optional boolean. Are you trying to pass the value or the cell as the the ColorIndex? Or the color of the cell? – Dude_Scott Mar 07 '19 at 19:37
  • @Dude_Scott - actually `Range(Cells(i,4),Cells(i,LastColumn))` is 1 range parameter, not 2. – Vityata Mar 07 '19 at 19:45
  • 1
    You’re right. I misread. – Dude_Scott Mar 07 '19 at 19:46

2 Answers2

1

There is one "(" more than needed in the way the function is called, thus it does not get the correct parameters. Try this:

CountColor(Range(Cells(i, 4), Cells(i, LastColumn)), 38)

To make sure you are passing on the expected parameter, press Ctrl + I, while on the line. The VBEditor would help:

enter image description here

In general, whenever working with Range() and Cells() objects, make sure to refer their Worksheets and Workbooks, to avoid 1004 errors. In the case of the example it should be like this:

With ThisWorkbook.Worksheets(1)
    For i = 2 To LastRow
        TOTALFAILS = CountColor(.Range(.Cells(i, 4), .Cells(i, LastColumn)), 38)
        .Cells(i, LastColumn + 8) = TOTALFAILS
    Next i
End With
Vityata
  • 42,633
  • 8
  • 55
  • 100
  • Upvoted for correctness. @RohinRaj see my answer for *why* this answer is correct. – Mathieu Guindon Mar 07 '19 at 20:19
  • 1
    @RohinRaj you'll get a +2 reputation bonus if you mark an answer as "accepted", by clicking the hollow green checkmark just underneath the up/down voting buttons next to either answer. Note that this will also take your question out of the "unanswered" questions list. – Mathieu Guindon Mar 07 '19 at 20:27
1

Your CountColor function is expecting a Range object reference for the first parameter, but that's not what you're giving it:

TOTALFAILS = CountColor((range(Cells(i, 4), Cells(i, LastColumn))), 38)

The first argument is the result of this expression:

(range(Cells(i, 4), Cells(i, LastColumn)))

When you put an argument between parentheses, what you're passing is the evaluated result of the expression, passed ByVal (regardless of the function's signature specifying ByRef or not).

So why "object required" then? Doesn't the expression evaluate to a Range object?

The Range class has a hidden default member that you can reveal in the Object Browser (F2):

Members of 'Range'

Notice the hidden/shaded _Default member.

If you're familiar with the Collection class, you might be aware of its Item member being that class' default member:

Members of 'Collection'

The default member can be implicitly invoked. That's how you can do myCollection("someKey") to retrieve an item, and that's how it's completely equivalent to myCollection.Item("someKey").

The Range.[_Default] member is a bit different, in that its implementation will "redirect" to different members, depending on context: when invoked without parameters, it returns Range.Value - for a single-cell range, that's the cell's value. For a multiple-cell range, that's a 2D variant array containing all the values.

So when you pass (someRange) as an argument, what you're implicitly passing is (someRange.[_Default]), because the class has a default, parameterless member (well, the two parameters are optional, so a parameterless invocation is legit).

In other words you're passing a 2D variant array to CountColor - not a Range object reference.

And that's why VBA throws run-time error 424 "object required" - because the call requires an object, but no object was provided.

As Vityata already answered, removing the extraneous parentheses will fix this, because without the extraneous parentheses, you're no longer forcing ByVal evaluation of the Range object/expression.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • Note: the object browser doesn't show hidden members by default. You need to right-click somewhere and tick the "show hidden members" option to have them show up. – Mathieu Guindon Mar 07 '19 at 20:20