"Object Required" when setting Active.Sheet to Range - vba

I have tried about every solution that I could find.
What I am trying to do is run a Function for selected range (The ActiveSheet)
I can't even get to the looping part because it errors on line 5 (arc = ActiveSheet.Row.Count). The error it throws is "Object Required". I have tried several different solutions found online with no luck. I am a complete noob at excel vba (my background is vb.net and c#). I would greatly appreciate a nudge in the right direction on what going wrong. Thanks in advance :)
Sub TestV2()
Dim rng As Range
Dim selectedRange As Range
Dim arc As Range
Set arc = ActiveSheet.Rows.Count
Set selectedRange = ActiveSheet.Rows.Count
For Each rng In selectedRange.Cells
If Application.CalculationState = xlDone Then
FireValidate
End If
Next rng
End
End Sub

You're getting this error because you declared arc as Range but you are trying to assign a Long number to it.

The Set keyword is required in VBA, to assign object references.
Set arc = ActiveSheet.Rows.Count
Set selectedRange = ActiveSheet.Rows.Count
Both arc and selectedRange are declared As Range, which is an object type - so the Set keyword is correct.
The problem is with the expressions on the right-hand side of the assignment operator: ActiveSheet.Rows.Count evaluates to a Long integer, which is not an object type. ActiveSheet.Rows.Count gets you the number of rows on the ActiveSheet, ...which should be the same number regardless of what specific sheet is currently active (all sheets have the same number of rows).
Hence, object required: you can't legally assign a Range object reference to a Long integer value; you need the right-hand side expression to evaluate to an object reference.
Tim Williams' answer shows how you can correctly assign the selectedRange to the Application.Selection, assuming what's currently selected is a Range object (a type mismatch error will occur if that's not the case).
What I am trying to do is run a Function for selected range (The ActiveSheet)
ActiveSheet doesn't return the selected range - it gives you the sheet that's currently active.
I am a complete noob at excel vba (my background is vb.net and c#)
You can reference the Excel object model from VB.NET or C# as well, and automate Excel through Visual Studio Tools for Office (VSTO) if you're more comfortable with these more powerful .net languages - but the object model will behave identically.

If you just want the current selection then:
Set selectedRange = Selection

You could try to modify your code as follows:
Sub TestV2()
Dim rng As Range
For Each rng In Selection
If Application.CalculationState = xlDone Then
FireValidate
End If
Next rng
End Sub
Hopefully it helps you.

There are three errors in your code:
.1. The key error. Use ActiveSheet.Rows.Count directly may encounter "Object Required" exception, instead, you can use the following worked code:
Dim ws As Worksheet
Set ws = ActiveSheet
'MsgBox ws.Rows.Count
Set arc = ws.Rows.Count
As hod said(this is not the key issue, but need to fix),
You're getting this error because you declared arc as Range but you are trying to assign a Long number to it.
As William have pointed, you can use the Set selectedRange = Selection directly if you want to operate the selected range.
Sub TestV2()
Dim rng As Range
Dim selectedRange As Range
Set selectedRange = Selection
For Each rng In selectedRange.Cells
If Application.CalculationState = xlDone Then
'FireValidate
'MsgBox "OK"
End If
Next rng
End Sub
And I think most time we just need the UsedRange.Rows but not the Rows all.
ActiveSheet.UsedRange.Rows.Count for the current sheet.
Worksheets("Sheet name").UsedRange.Rows.Count for a specific sheet.

Related

Am I using the Columns() property improperly, and if so, is there a good workaround?

I'm currently in the process of solving a
type mismatch error
in a macro I'm writing, and I've written a short subroutine to drill down on the specific issue. This subroutine should loop through all of Column A, entering the numbers 1-10 in rows 1-10.
Sub looptest()
Dim rRange As Range
Dim rCell As Range
Dim i As Integer
Set rRange = ThisWorkbook.Worksheets(1).Columns(1)
i = 0
For Each rCell In rRange
If i < 10 Then
i = i + 1
rCell.Value2 = i
End If
Next rCell
End Sub
Instead this fills every cell in Column A with 1. Stepping through it in debug mode shows that instead of referencing a single cell, rCell references the entire column.
I have found that if I replace
Set rRange = ThisWorkbook.Worksheets(1).Columns(1)
with
Set rRange = ThisWorkbook.Worksheets(1).Range("A1:A100")
the macro works as intended, however I'd prefer to be able to use Columns() or something similar in my production code.
Am I using the Columns() property improperly, and if so, is there a good workaround?
Begin with these changes:
Set rRange = ThisWorkbook.Worksheets(1).Columns(1).Cells
Dim i As Long
Using the .Cells lets us loop over the cells in a column rather than columns in a worksheet.

Why does ActiveSheet.FilterMode returns False when sheet has filter?

I'm using the following code in an attempt to detect a filter applied to a column in a table and then clear the filter:
If ActiveSheet.FilterMode Then ActiveSheet.ShowAllData
According to Microsoft documentation:
This property is true if the worksheet contains a filtered list in which there are hidden rows.
This doesn't seem to be the case since ActiveSheet.Filtermode only returns True if a cell inside the table where the filter is applied is selected.
First question: Is the documentation wrong? Documentation
Second question: Is my only option to select a cell inside the table to get the expression to return True?
PS I am using Excel 2010
Edit: Answer to Question 2, Non-select based methods to clear filters...
If ActiveSheet.ListObjects(1).Autofilter.FilterMode Then ActiveSheet.ListObjects(1).Autofilter.Showalldata
I can replicate both your issues on Excel 2013: both the buggy False on FilterMode and the error on ShowAllData.
In response to whether the documentation is wrong, I would say that it is missing a qualification to say that the ActiveCell should be in the ListObjects DataBodyRange. Perhaps the documentation is correct but that this is a bug that has not been addressed. Maybe you can update your question with a link to the documentation?
Re your second question - I agree that using this workaround is the most obvious solution. It seems a bit unpleasant to use Select but sometimes I guess this cannot be avoided.
This is how I did it using the Intersect function to check it the ActiveCell is currently in the area of the DataBodyRange of the ListObject:
Option Explicit
Sub Test()
Dim rng As Range
Dim ws As Worksheet
Dim lst As ListObject
'get ActiveCell reference
Set rng = ActiveCell
'get reference to Worksheet based on ActiveCell
Set ws = rng.Parent
'is there a Listobject on the ActiveCells sheet?
If ws.ListObjects.Count > 0 Then
Set lst = ws.ListObjects(1)
Else
Debug.Print "No table found"
Exit Sub
End If
'is cell is in the DataBodyRange of ListObject?
If Intersect(rng, lst.DataBodyRange) Is Nothing Then
'set the ActiveCell to be in the DataBodyRange
lst.DataBodyRange.Cells(1, 1).Select
End If
'now you can safely call ShowAllData
If ws.FilterMode = True Then
ws.ShowAllData
End If
End Sub
Edit
Further to #orson's comment:
What happens if you skip the If Intersect(rng, lst.DataBodyRange) Is Nothing Then and use If lst.AutoFilter.FilterMode Then lst.AutoFilter.ShowAllData End If ?
So, you can check the FilterMode of the ListObject itself and then as long as you have a reference to the ListObject you can use his code:
If lst.AutoFilter.FilterMode Then
lst.AutoFilter.ShowAllData
End If
An easier alternative can be to just AutoFit all rows:
Rows.AutoFit
The issue with that is that it will un-hide and auto fit all rows on the active sheet.
Update from http://www.contextures.com/excelautofilterlist.html
Dim list As ListObject
For Each list ActiveSheet.ListObjects
If list.AutoFilter.FilterMode Then
list.AutoFilter.ShowAllData
End If
Next

Trying to loops through multiple cells in VBA

I've searched online and found a few solutions, but none of them make sense to me. I'm wondering why this specifically doesn't work:
Dim rng As Range: Set rng = Range("A5:A10")
For Each cell In rng
Dim contents As String: contents = ThisWorkbook.Sheets("ROI's").Range("cell").Value
MsgBox (contents)
Next cell
(BTW this is within a larger macro which works)
It keep saying that the error is on the third line
In addition to Scott Craners answer, take the parenthesis away from around contents in MsgBox (contents), you are not placing it into a variable so it should not be enclosed.
Sub try2()
Dim rng As Range
Dim cell As Range
Dim contents As String
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = Range("A1:A10")
For Each cell In rng
contents = ws.Range(cell.Address(0, 0)).Value
MsgBox (contents)
Next cell
End Sub
I've been practicing wtih various problems concerning VBA...the above is just a snippet synthesizing what all the fine people above me have said about making this work. My 2 cents, brackets or not around the contents variable, the result is the same.

Run-time error 1004 while setting ranges

I'm trying to make an array of ranges, but I'm getting "application-defined or object-defined error". The error is appearing on the line with Set Rng. The format should be fine, even if the line is somewhat long. I've specified the sheet I'm trying to get the ranges from, and the sub is currently in Module 1. It could just be a typo error somewhere, but after having re-checked the line six times I'd be disappointed if that was it.
Sub TableRange(ByVal Target As Range)
Dim Rng As Range
Dim Area As Range
Set Rng = Worksheets("Tables").Range("A3:D23,A28:C39,A44:E61,A66:C102,A107:E121,A126:C135,A140:C149,A153:C162,A167:C192,A197:F215,A220:C269,A274:D282,A287:D295,A300:D304")
Set Rng = Union(Rng, Worksheets("Tables").Range("A309:C358,A363:C389,A394:C412,A417:C437,A442:C462,A467:D475,A480:D487,A492:C531,A536:D544,A549:D557,A562:C574,A579:D598,A603:D622"))
For Each Area In Rng.Areas
If Not Intersect(Target, Worksheets("Tables").Range(Area)) Is Nothing Then
'do stuff
End If
Next Area
End Sub
If there is anything else I should mention or that I can do to improve my question, let me know and I'll edit my post accordingly.
Update: Range array has been fixed, thanks to #user3964075, but now I seem to be stuck with the same error on If Not Intersect - Is Nothing Then
The code is fine, but string constant exceeds maximum length (255 chars) allowed for Range property. You can easily fix it with:
Set Rng = Worksheets("Tables").Range("A3:D23,A28:C39,A44:E61,A66:C102,A107:E121,A126:C135,A140:C149,A153:C162,A167:C192,A197:F215,A220:C269,A274:D282,A287:D295,A300:D304")
Set Rng = Union(Rng, Worksheets("Tables").Range("A309:C358,A363:C389,A394:C412,A417:C437,A442:C462,A467:D475,A480:D487,A492:C531,A536:D544,A549:D557,A562:C574,A579:D598,A603:D622"))
Maybe consider using Named Range instead of this long list.
EDIT: To fix the second problem, change it to:
If Not Intersect(Target, Area) Is Nothing Then
'do stuff
End If
You are not dealing with the Range.Areas property properly. Try a loop through the index.
dim a as long
For a =1 to Rng.Areas.count
If Not Intersect(Target, Rng.Areas(a)) Is Nothing Then
'do stuff
End If
Next a
I copied the Set Rng Line and had the same error.
When I removed one range, i.e. A28:C39 it works. It does not matter which Range will be removed.
Maybe there is a maximum of Ranges?
Try:
Set Rng = Worksheets("Tabelle1").Range("A3:D23,A44:E61,A66:C102,A107:E121,A126:C135,A140:C149,A153:C162,A167:C192,A197:F215,A220:C269,A274:D282,A287:D295,A300:D304,A309:C358,A363:C389,A394:C412,A417:C437,A442:C462,A467:D475,A480:D487,A492:C531,A536:D544,A549:D557,A562:C574,A579:D598,A603:D622")

VBA vlookup reference in different sheet

In Excel 2007, I am looping through the values of column 4 in Sheet 2. Still in Sheet 2, I want to output the result of my vlookup formula into column 5. The vlookup formula needs to refer to Sheet 1 where the reference columns are. In order to do so I have the following formula
Range("E2") = Application.WorksheetFunction.VLookup(Range("D2"), _
Worksheets("Sheet1").Range("A1:C65536"), 1, False)
Problem, it returns error code 1004. I read that it was because I needed to Select Sheet 1 before running the formulas such as:
ThisWorkbook.Worksheets("Sheet1").Select
But then the searched value Range ("D2") doesn't belong to Sheet 1 and it still return code 1004 after having brought Sheet 1 into view.
What is the correct way to refer to a different sheet in this case?
try this:
Dim ws as Worksheet
Set ws = Thisworkbook.Sheets("Sheet2")
With ws
.Range("E2").Formula = "=VLOOKUP(D2,Sheet1!$A:$C,1,0)"
End With
End Sub
This just the simplified version of what you want.
No need to use Application if you will just output the answer in the Range("E2").
If you want to stick with your logic, declare the variables.
See below for example.
Sub Test()
Dim rng As Range
Dim ws1, ws2 As Worksheet
Dim MyStringVar1 As String
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set ws2 = ThisWorkbook.Sheets("Sheet2")
Set rng = ws2.Range("D2")
With ws2
On Error Resume Next 'add this because if value is not found, vlookup fails, you get 1004
MyStringVar1 = Application.WorksheetFunction.VLookup(rng, ws1.Range("A1:C65536").Value, 1, False)
On Error GoTo 0
If MyStringVar1 = "" Then MsgBox "Item not found" Else MsgBox MyStringVar1
End With
End Sub
Hope this get's you started.
The answer your question: the correct way to refer to a different sheet is by appropriately qualifying each Range you use.
Please read this explanation and its conclusion, which I guess will give essential information.
The error you are getting is likely due to the sought-for value Sheet2!D2 not being found in the searched range Sheet1!A1:A65536. This may stem from two cases:
The value is actually not present (pointed out by chris nielsen).
You are searching the wrong Range. If the ActiveSheet is Sheet1, then using Range("D2") without qualifying it will be searching for Sheet1!D2, and it will throw the same error even if the sought-for value is present in the correct Range.
Code accounting for this (and items below) follows:
Sub srch()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim srchres As Variant
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")
On Error Resume Next
srchres = Application.WorksheetFunction.VLookup(ws2.Range("D2"), ws1.Range("A1:C65536"), 1, False)
On Error GoTo 0
If (IsEmpty(srchres)) Then
ws2.Range("E2").Formula = CVErr(xlErrNA) ' Use whatever you want
Else
ws2.Range("E2").Value = srchres
End If
End Sub
I will point out a few additional notable points:
Catching the error as done by chris nielsen is a good practice, probably mandatory if using Application.WorksheetFunction.VLookup (although it will not suitably handle case 2 above).
This catching is actually performed by the function VLOOKUP as entered in a cell (and, if the sought-for value is not found, the result of the error is presented as #N/A in the result). That is why the first soluton by L42 does not need any extra error handling (it is taken care by =VLOOKUP...).
Using =VLOOKUP... is fundamentally different from Application.WorksheetFunction.VLookup: the first leaves a formula, whose result may change if the cells referenced change; the second writes a fixed value.
Both solutions by L42 qualify Ranges suitably.
You are searching the first column of the range, and returning the value in that same column. Other functions are available for that (although yours works fine).
Your code work fine, provided the value in Sheet2!D2 exists in Sheet1!A:A. If it does not then error 1004 is raised.
To handle this case, try
Sub Demo()
Dim MyStringVar1 As Variant
On Error Resume Next
MyStringVar1 = Application.WorksheetFunction.VLookup(Range("D2"), _
Worksheets("Sheet1").Range("A:C"), 1, False)
On Error GoTo 0
If IsEmpty(MyStringVar1) Then
MsgBox "Value not found!"
End If
Range("E2") = MyStringVar1
End Sub
It's been many functions, macros and objects since I posted this question. The way I handled it, which is mentioned in one of the answers here, is by creating a string function that handles the errors that get generate by the vlookup function, and returns either nothing or the vlookup result if any.
Function fsVlookup(ByVal pSearch As Range, ByVal pMatrix As Range, ByVal pMatColNum As Integer) As String
Dim s As String
On Error Resume Next
s = Application.WorksheetFunction.VLookup(pSearch, pMatrix, pMatColNum, False)
If IsError(s) Then
fsVlookup = ""
Else
fsVlookup = s
End If
End Function
One could argue about the position of the error handling or by shortening this code, but it works in all cases for me, and as they say, "if it ain't broke, don't try and fix it".