Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VBA: What happens to Range objects if user deletes cells?

Tags:

excel

vba

Suppose I have some module in vba with some variable r of type Range. Suppose that, at some point, I store a Range object there (e.g. the active cell). Now my question: What happens to the value of r if the user deletes the cell (the cell, not only its value)?

I tried to figure this out in VBA, but without success. The result is strange. r is not Nothing, the value of r is reported to be of type Range, but if I try to look at its properties in the debugger window, each property's value is reported as "object required".

How can I, programmatically, determine whether variable r is in this state or not?

Can I do this without generating an error and catching it?

like image 340
JohnB Avatar asked Aug 26 '12 03:08

JohnB


People also ask

How do ranges work in VBA?

Range is a property in VBA that helps specify a particular cell, a range of cells, a row, a column, or a three-dimensional range. In the context of the Excel worksheet, the VBA range object includes a single cell or multiple cells spread across various rows and columns.

What does ClearContents do in VBA?

Clear contents is a method in VBA which is used to delete or remove the values which are stored in the cells provided to it, this method makes the cell range empty and it is used with the range property to access the specified cell range, the example to use this method is as follows range(“A1:B2”).

How do you use scrolls in VBA?

The key to scrolling your windows with Excel VBA is to understand that each of the scroll properties fall under the ActiveWindow object. For example, to scroll your row with VBA, you would call the ActiveWindow. ScrollRow property.

How do you use ClearContents in VBA?

In VBA, there is a method called ClearContents that you can use to clear values and formulas from a cell, range of cells, and the entire worksheet. To use this method, first, you need to define the expression somewhere you want to clear the content, and then type “. ClearContents”.


3 Answers

Nice question! I've never thought about this before, but this function will, I think, identify a range that was initialzed - is not Nothing - but is now in the "Object Required" state because its cells were deleted:

Function RangeWasDeclaredAndEntirelyDeleted(r As Range) As Boolean
Dim TestAddress As String

If r Is Nothing Then
    Exit Function
End If
On Error Resume Next
TestAddress = r.Address
If Err.Number = 424 Then    'object required
    RangeWasDeclaredAndEntirelyDeleted = True
End If
End Function

You can test is like this:

Sub test()
Dim r As Range

Debug.Print RangeWasDeclaredAndEntirelyDeleted(r)
Set r = ActiveSheet.Range("A1")
Debug.Print RangeWasDeclaredAndEntirelyDeleted(r)
r.EntireRow.Delete
Debug.Print RangeWasDeclaredAndEntirelyDeleted(r)
End Sub
like image 126
Doug Glancy Avatar answered Oct 07 '22 09:10

Doug Glancy


I believe that when you use the Set keyword in VBA, it creates a pointer in the background to the worksheet's Range object in the worksheet you specified (each cell being an object in the collection of Cells of the Worksheet for a given Range). When the range is deleted while you are still referencing it in memory, the memory for the object that the Range variable was pointing to has been deallocated.

However, your Range variable most-likely still contains the pointer to the recently removed Range object, which is why it isn't nothing, but whatever it's pointing to doesn't exist anymore, which causes problems when you try to use the variable again.

Check out this code to see what I mean:

Public Sub test2()
    Dim r As Excel.Range
    Debug.Print ObjPtr(r)           ' 0

    Set r = ActiveSheet.Range("A1")
    Debug.Print ObjPtr(r)           ' some address

    r.Value = "Hello"

    r.Delete
    Debug.Print ObjPtr(r)           ' same address as before
End Sub

Check out this article for more info about ObjPtr(): http://support.microsoft.com/kb/199824

So while you have a valid address to an object, unfortunately the object doesn't exist anymore since it has been deleted. And it appears that "Is Nothing" just checks for an address in the pointer (which I think VBA believes that the variable is "Set").

As to how to get around this problem, unfortunately I don't see a clean way of doing it at the moment (if anyone does find an elegant way to handle this, please post it!). You can use On Error Resume Next like so:

Public Sub test3()
    Dim r As Excel.Range
    Debug.Print ObjPtr(r)           ' 0

    Set r = ActiveSheet.Range("A1")
    Debug.Print ObjPtr(r)           ' some address

    r.Value = "Hello"

    r.Delete
    Debug.Print ObjPtr(r)           ' same address as before

    On Error Resume Next
    Debug.Print r.Value
    If (Err.Number <> 0) Then
        Debug.Print "We have a problem here..."; Err.Number; Err.Description
    End If
    On Error GoTo 0
End Sub
like image 6
Joseph Avatar answered Oct 07 '22 10:10

Joseph


How can I, programmatically, determine whether variable r is in this state or not?

Can I do this without generating an error and catching it?

No.

To the best of my knowledge, you can't test for this condition reliably: not without raising and catching an error.

Your question has been noticed and discussed elsewhere: Two of the big names in Excel/VBA blogging (Dick Kusleika and Rob Bovey) have looked into it, and you may find something informative in there. But the answer's No.

All in all, a good question with rather worrying answer.

like image 4
Nigel Heffernan Avatar answered Oct 07 '22 08:10

Nigel Heffernan