I’m updating a macro that’s used in lots of spreadsheets, and it’s rather slow. While looking to speed it up, I noticed that at one point it goes through this loop:
For each wsLoop in ThisWorkbook.Worksheets wsLoop.Activate With ActiveSheet.Status_Text If bStatus = True Then .ForeColor = &HC000& .Caption = "ONLINE" Else .ForeColor = &HFF& .Caption = "OFFLINE" End If End With Next wsLoop
Where wsLoop is a worksheet, bStatus is a boolean and Status_Text is the name of an ActiveX label form control on each worksheet.
I know using .Activate is bad practice and can slow things down, so I dropped the
wsLoop.Activate and changed the next line to
With wsLoop.Status_Text, but now I get a “Method or data member not found” error message.
What’s the proper way to do this?
Interesting question which seems to touch on some poorly-documented features of Excel VBA. It seems that maybe the expression
ActiveSheet.Status_Text is operating as the name of the control, with the dot acting as a namespace qualifier, but that in
wsLoop.Status_Text VBA is interpreting the dot as the method/property access operator and is correctly giving the error message that no such method or property exists. To reproduce the problem, I created a label named
Status_Text on each sheet and then ran
Sub test1() Dim ws As Worksheet For Each ws In Worksheets Debug.Print ws.Status_Text.Caption 'fails Next ws End Sub
It crashes with the error that you show. One workaround (although just why it works is mysterious) is to change the loop index from being a
Worksheet to a
Sub test2() Dim ws As Variant For Each ws In Worksheets Debug.Print ws.Status_Text.Caption 'succeeds Next ws End Sub
The odd thing about this last example is if you add the line
Debug.Print TypeName(ws) in the for-each loop it prints
ws.Status_Text works if
ws is a variant which holds a worksheet but not if
ws is actually a worksheet. The mystery is in some sense deepened but in another sense lessened when you step through this sub in the debugger, looking at the locals window. The type of
ws in the loop is described as
Variant/Object/Sheet1 (in the first pass through the loop). The specific sheet seems to be part of the current subtype of the variable.
Another workaround is to use a
For-Next loop rather than a
Sub test3() Dim i As Long For i = 1 To Worksheets.Count Debug.Print Worksheets(i).Status_Text.Caption 'succeeds Next i End Sub
You could use either of these approaches to get a reference to the label without having to activate the sheet.