假设我在vba中有一些模块,其中某些变量r
的类型为Range
。假设在某些时候,我在那里存储一个Range对象(例如活动单元格)。现在我的问题是:如果用户删除了单元格(单元格,而不仅仅是其值),r
的值会发生什么变化?
我试图在VBA中解决这个问题,但没有成功。结果很奇怪。 r
不是Nothing
,r
的值报告为Range
类型,但如果我尝试在调试器窗口中查看其属性,则每个属性的值报告为“需要对象”。
如何以编程方式确定变量r
是否处于此状态?
我可以在不产生错误并抓住错误的情况下执行此操作吗?
答案 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