A family of Microsoft spreadsheet software with tools for analyzing, charting, and communicating data.
Thanks for the reply & interesting code. Your explanation doesn't help me understand why the function has worked flawlessly for 15 years (including use on fitlered ranges), but gives erratic results now.
The reason might be that the last row/column was always filled and visible...
MS has not changed anything in this behavior, you're lucky that the issue did not occurred (or no one has noticed).
I guess you want to have all visible cells of the used range, the code below might be helpful.
BTW, if you want to get the filtered data only, access the AutoFilter.Range object in that sheet.
Andreas.
Option Explicit
Sub Test()
Debug.Print RangeVisible(RangeUsedRange(Cells)).Address
Debug.Print RangeSurround(IntersectA( _
SpecialCells(Cells, xlCellTypeVisible), _
UnionA(SpecialCells(Cells, xlCellTypeConstants), _
SpecialCells(Cells, xlCellTypeFormulas)))).Address
End Sub
Function SpecialCells(ByVal R As Range, ByVal Typ As XlCellType, _
Optional ByVal Value As XlSpecialCellsValue = &H17) As Range
'Avoid the SpecialCells-BUG to return all cells from the current region
On Error Resume Next
Select Case Typ
Case xlCellTypeConstants, xlCellTypeFormulas
Set SpecialCells = Intersect(R, R.SpecialCells(Typ, Value))
Case Else
Set SpecialCells = Intersect(R, R.SpecialCells(Typ))
End Select
End Function
Function IntersectA(ParamArray Args()) As Range
'Same as Intersect, but skips ranges which are Nothing
Dim i As Integer
For i = LBound(Args) To UBound(Args)
If IntersectA Is Nothing Then
Set IntersectA = Args(i)
ElseIf Not Args(i) Is Nothing Then
Set IntersectA = Intersect(IntersectA, Args(i))
End If
Next
End Function
Function UnionA(ParamArray Args()) As Range
'Same as Union, but skips ranges which are Nothing
Dim i As Integer
For i = LBound(Args) To UBound(Args)
If UnionA Is Nothing Then
Set UnionA = Args(i)
ElseIf Not Args(i) Is Nothing Then
Set UnionA = Union(UnionA, Args(i))
End If
Next
End Function
Function RangeVisible(ByVal R As Range) As Range
'Returns the used range of R
Dim C As Range
On Error Resume Next
Set R = Intersect(R, R.SpecialCells(xlCellTypeVisible))
On Error GoTo 0
If R Is Nothing Then
If C Is Nothing Then Exit Function
Set R = C
ElseIf Not C Is Nothing Then
Set R = Union(R, C)
End If
Set RangeVisible = RangeSurround(R)
End Function
Function RangeUsedRange(ByVal R As Range) As Range
'Returns the surrounding used range of R
Dim C As Range
On Error Resume Next
Set C = Intersect(R, R.SpecialCells(xlCellTypeFormulas))
Set R = Intersect(R, R.SpecialCells(xlCellTypeConstants))
On Error GoTo 0
If R Is Nothing Then
If C Is Nothing Then Exit Function
Set R = C
ElseIf Not C Is Nothing Then
Set R = Union(R, C)
End If
Set RangeUsedRange = RangeSurround(R)
End Function
Function RangeTopLeft(ByVal R As Range) As Range
'Returns the intersecting top leftmost cell of all areas in R
Dim Area As Range
Dim FirstRow As Long, FirstCol As Long, i As Long
If R Is Nothing Then Exit Function
FirstRow = R.Row + R.Rows.Count
FirstCol = R.Column + R.Columns.Count
For Each Area In R.Areas
i = Area.Row
If i < FirstRow Then FirstRow = i
i = Area.Column
If i < FirstCol Then FirstCol = i
Next
Set RangeTopLeft = R.Parent.Cells(FirstRow, FirstCol)
End Function
Function RangeBottomRight(ByVal R As Range) As Range
'Returns the intersecting bottom rightmost cell of all areas in R
Dim Area As Range
Dim LastRow As Long, LastCol As Long, i As Long
If R Is Nothing Then Exit Function
For Each Area In R.Areas
i = Area.Row + Area.Rows.Count - 1
If i > LastRow Then LastRow = i
i = Area.Column + Area.Columns.Count - 1
If i > LastCol Then LastCol = i
Next
Set RangeBottomRight = R.Parent.Cells(LastRow, LastCol)
End Function
Function RangeSurround(ByVal R As Range) As Range
'Returns the surrounding range of R
Dim Area As Range
Dim FirstRow As Long, FirstCol As Long, i As Long
Dim LastRow As Long, LastCol As Long
If R Is Nothing Then Exit Function
FirstRow = R.Row
FirstCol = R.Column
For Each Area In R.Areas
i = Area.Row
If i < FirstRow Then FirstRow = i
i = Area.Column
If i < FirstCol Then FirstCol = i
i = Area.Row + Area.Rows.Count - 1
If i > LastRow Then LastRow = i
i = Area.Column + Area.Columns.Count - 1
If i > LastCol Then LastCol = i
Next
With R.Parent
Set RangeSurround = .Range(.Cells(FirstRow, FirstCol), .Cells(LastRow, LastCol))
End With
End Function