VBA: Qu'arrive-t-il aux objets Range si l'utilisateur supprime des cellules?

supposons que j'ai un module dans avec une variable r de type Range . Supposons qu'à un moment donné, j'y stocke un objet Range (par exemple la cellule active). Maintenant, ma question: Qu'advient-il de la valeur de r si l'utilisateur supprime la cellule (la cellule, non seulement sa valeur)?

j'ai essayé de comprendre cela dans VBA, mais sans succès. Le résultat est étrange. r n'est pas Nothing , la valeur de r est de type Range , mais si j'essaie de regarder ses propriétés dans la fenêtre du débogueur, chaque valeur de la propriété est signalé comme "objet requis".

Comment puis-je, programmatiquement, déterminer si la variable r est dans cet état ou non?

puis-je le faire sans générer d'erreur et l'attraper?

28
demandé sur brettdj 2012-08-26 07:00:56

4 réponses

bonne question! Je n'ai jamais pensé à cela avant, mais cette fonction va, je pense, identifier une gamme qui a été initialisé - n'est pas Rien - mais est maintenant dans l'état "Objet requis" parce que ses cellules ont été supprimées:

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

vous pouvez tester est comme ceci:

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
21
répondu Doug Glancy 2012-08-26 05:15:32

je crois que lorsque vous utilisez le mot-clé Set dans VBA, il crée un pointeur en arrière-plan à L'objet de portée de la feuille de travail que vous avez spécifié (chaque cellule étant un objet dans la collection de cellules de la feuille de travail pour une portée donnée). Lorsque la plage est supprimée alors que vous la référencez encore en mémoire, la mémoire de l'objet que la variable Range pointait a été désallocée.

cependant, votre variable de gamme plus-probablement encore contient le pointeur vers L'objet Range récemment supprimé, c'est pourquoi il n'est pas rien, mais ce qu'il pointe vers n'existe plus, ce qui cause des problèmes quand vous essayez d'utiliser la variable à nouveau.

Regardez ce code pour voir ce que je veux dire:

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

consultez cet article pour plus d'informations sur ObjPtr(): http://support.microsoft.com/kb/199824

donc tant que vous avez une adresse valide à un objet, malheureusement, l'objet n'existe plus depuis qu'il a été supprimé. Et il semble que "Is Nothing" vérifie juste une adresse dans le pointeur (ce que je pense que VBA croit que la variable est "Set").

quant à la façon de contourner ce problème, malheureusement je ne vois pas de moyen propre de faire à l'instant (si quelqu'un trouve un moyen élégant pour gérer cela, s'il vous plaît poster!). Vous pouvez utiliser sur la reprise D'erreur comme suit:

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
6
répondu Joseph Serido 2016-10-29 13:43:40

Comment puis-je, programmatiquement, déterminer si la variable r est dans cette l'état ou pas?

puis-je le faire sans générer d'erreur et l'attraper?

Pas de.

à ma connaissance, vous ne pouvez pas tester cette condition de manière fiable: pas sans soulever et attraper une erreur.

votre question a été remarqué et discuté ailleurs : deux des grands noms dans Excel/VBA blogging (Dick Kusleika et Rob Bovey) ont regardé dans elle, et vous pouvez trouver quelque chose d'informatif là-bas. Mais la réponse est non.

en somme, une bonne question avec une réponse plutôt inquiétante.

4
répondu Nigel Heffernan 2016-10-27 15:24:44

pour tester si un objet range est invalide, j'utilise cette fonction:

Public Function InvalidRangeReference(r As Range) As Boolean    
    On Error Resume Next
    If r.Count = 0 Then
        InvalidRangeReference = Err
    End If    
End Function
1
répondu Excel Hero 2014-04-24 02:25:03