30

タイプが変数のにモジュールがあるとします。ある時点で、そこにRangeオブジェクト(アクティブセルなど)を格納するとします。さて、私の質問:ユーザーがセル(セルの値だけでなくセル)を削除すると、その値はどうなりますか?rRanger

私はこれをVBAで理解しようとしましたが、成功しませんでした。結果は奇妙です。rではないNothing場合、の値はrタイプRangeであると報告されますが、デバッガウィンドウでそのプロパティを確認しようとすると、各プロパティの値は「必要なオブジェクト」として報告されます。

rプログラムで、変数がこの状態にあるかどうかをどのように判断できますか?

エラーを生成してキャッチせずにこれを行うことはできますか?

4

4 に答える 4

22

いい質問です!私はこれまでこれについて考えたことはありませんでしたが、この関数は、初期化された範囲を識別すると思います-Nothingではありませんが、セルが削除されたため、現在「オブジェクトが必要」状態になっています:

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
于 2012-08-26T04:24:39.497 に答える
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/199 ​​824

したがって、オブジェクトへの有効なアドレスを持っていても、残念ながらオブジェクトは削除されているため、もう存在しません。そして、「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
于 2012-08-26T04:17:41.297 に答える
4

変数 r がこの状態にあるかどうかをプログラムで判断するにはどうすればよいですか?

エラーを生成してキャッチせずにこれを行うことはできますか?

いいえ。

私の知る限りでは、この状態を確実にテストすることはできません。

あなたの質問は他の場所で注目され、議論されています: Excel/VBA ブログの 2 人の有名人 (Dick Kusleika と Rob Bovey) が調査しており、有益な情報が見つかるかもしれません。しかし、答えはNo.

全体として、かなり心配な答えを持つ良い質問です。

于 2012-08-31T12:53:25.023 に答える
2

範囲オブジェクトが現在無効かどうかをテストするには、次の関数を使用します。

Public Function InvalidRangeReference(r As Range) As Boolean    
    On Error Resume Next
    If r.Count = 0 Then
        InvalidRangeReference = Err
    End If    
End Function
于 2014-04-24T02:25:03.337 に答える