VBA:如果用户删除单元格,Range对象会发生什么?

时间:2012-08-26 03:00:56

标签: excel vba excel-vba

假设我在中有一些模块,其中某些变量r的类型为Range。假设在某些时候,我在那里存储一个Range对象(例如活动单元格)。现在我的问题是:如果用户删除了单元格(单元格,而不仅仅是其值),r的值会发生什么变化?

我试图在VBA中解决这个问题,但没有成功。结果很奇怪。 r不是Nothingr的值报告为Range类型,但如果我尝试在调试器窗口中查看其属性,则每个属性的值报告为“需要对象”。

如何以编程方式确定变量r是否处于此状态?

我可以在不产生错误并抓住错误的情况下执行此操作吗?

4 个答案:

答案 0 :(得分:21)

好问题!我以前从未考虑过这个问题,但我认为,这个函数会识别一个被初始化的范围 - 不是什么 - 但现在处于“对象必需”状态,因为它的单元格被删除了:

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

你可以测试是这样的:

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

答案 1 :(得分:6)

我相信当你在VBA中使用Set关键字时,它会在你指定的工作表中的工作表的Range对象的背景中创建一个指针(每个单元格是给定范围的工作表单元格集合中的一个对象) )。当您仍在内存中引用范围时删除范围时,已取消分配Range变量指向的对象的内存。

但是,你的Range变量最可能仍然包含指向最近删除的Range对象的指针,这就是为什么它不是什么,但它指向的任何东西都不再存在,这会在你尝试使用时导致问题变量再次。

查看此代码以了解我的意思:

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

有关ObjPtr()的更多信息,请查看此文章: http://support.microsoft.com/kb/199824

因此,虽然您有一个对象的有效地址,但遗憾的是该对象已不再存在,因为它已被删除。看来“Is Nothing”只是检查指针中的地址(我认为VBA认为该变量是“Set”)。

至于如何解决这个问题,遗憾的是我现在还没有看到一种干净的方式(如果有人找到一种优雅的方式来处理它,请发布它!)。您可以像这样使用On Error Resume Next:

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

答案 2 :(得分:4)

  

我如何以编程方式确定变量r是否在此中   国家与否?

     

我可以在不产生错误并抓住错误的情况下执行此操作吗?

没有

据我所知,你无法可靠地测试这种情况:不是没有提出并发现错误。

你的问题是noticed and discussed elsewhere:Excel / VBA博客中的两位大人物(Dick Kusleika和Rob Bovey)已经调查过了,你可能会在那里找到一些信息。但答案是否定的。

总而言之,一个很好的问题,相当令人担忧的答案。

答案 3 :(得分:1)

要测试范围对象当前是否无效,我使用此函数:

Public Function InvalidRangeReference(r As Range) As Boolean    
    On Error Resume Next
    If r.Count = 0 Then
        InvalidRangeReference = Err
    End If    
End Function