web-dev-qa-db-fra.com

Excel VBA: sur l'instruction d'erreur Goto ne fonctionnant pas à l'intérieur de la boucle For

J'essaie de parcourir un tableau dans Excel. Les trois premières colonnes de ce tableau ont des en-têtes de texte, les autres ont des dates comme en-têtes. Je veux affecter ces dates, séquentiellement, à une variable de type Date, puis effectuer certaines opérations en fonction de la date

Pour ce faire, j'utilise une boucle foreach sur myTable.ListColumns. Comme les trois premières colonnes n'ont pas d'en-tête de date, j'ai essayé de configurer la boucle afin que, en cas d'erreur d'attribution de la chaîne d'en-tête à la variable de type date, la boucle passe directement à la colonne suivante

Cela semble fonctionner pour la première colonne. Toutefois, lorsque l'en-tête de la deuxième colonne est "affecté" à la variable de type date, la macro rencontre une erreur même si elle se trouve dans un bloc de traitement des erreurs.

Dim myCol As ListColumn
For Each myCol In myTable.ListColumns
    On Error GoTo NextCol

    Dim myDate As Date
    myDate = CDate(myCol.Name)

    On Error GoTo 0

    'MORE CODE HERE

NextCol:
    On Error GoTo 0
Next myCol

Pour réitérer, l'erreur est renvoyée au deuxième tour de la boucle, à la déclaration

myDate = CDate(myCol.Name)

Quelqu'un peut-il expliquer pourquoi l'instruction On Error cesse de fonctionner?

14
Swiftslide

Avec le code indiqué, vous êtes toujours considéré comme étant au sein de la routine de traitement des erreurs lorsque vous supprimez l'instruction next

Cela signifie que les gestionnaires d'erreurs ultérieurs ne sont pas autorisés jusqu'à ce que vous repreniez celui en cours.

Une meilleure architecture serait:

    Dim myCol As ListColumn
    For Each myCol In myTable.ListColumns
        On Error GoTo ErrCol
        Dim myDate As Date
        myDate = CDate(myCol.Name)
        On Error GoTo 0
        ' MORE CODE HERE '
NextCol:
    Next myCol
    Exit Sub ' or something '

ErrCol:
    Resume NextCol

Cela délimite clairement la gestion des erreurs du code normal et garantit que le gestionnaire d'erreurs en cours d'exécution est terminé avant que vous essayiez de configurer un autre gestionnaire.

Ce site a une bonne description du problème:


Error Handling Blocks And On Error Goto

Un bloc de traitement des erreurs, également appelé gestionnaire d'erreurs, est une section de code vers laquelle l'exécution est transférée via une instruction On Error Goto <label>:. Ce code doit être conçu pour résoudre le problème et reprendre l’exécution dans le bloc de code principal ou pour mettre fin à l’exécution de la procédure. Vous ne pouvez pas utiliser l'instruction On Error Goto <label>: simplement sauter des lignes. Par exemple, le code suivant ne fonctionnera pas correctement:

    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo Err2:
    Debug.Print 1 / 0
    ' more code
Err2:

Lorsque la première erreur est générée, l'exécution est transférée à la ligne suivant le code Err1:. Le gestionnaire d'erreurs est toujours actif lorsque la deuxième erreur se produit et, par conséquent, la deuxième erreur n'est pas interceptée par l'instruction On Error.

33
paxdiablo

Vous devez ajouter resume de certaines sortes dans votre code de gestion des erreurs pour indiquer que la gestion des erreurs est terminée. Sinon, le premier gestionnaire d'erreurs est toujours actif et vous n'êtes jamais "résolu".

Voir http://www.cpearson.com/Excel/errorhandling.htm (plus précisément dans la rubrique "Traitement des erreurs et suppression d'erreur" et dans la section suivante).

8
enderland

Suivi de la réponse acceptée par paxdiablo. Ceci est possible, en autorisant deux pièges d'erreur dans le même sous, l'un après l'autre:

Public Sub test()
    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo -1     ' clears the active error handler
    On Error GoTo Err2:  ' .. so we can set up another
    Debug.Print 1 / 0
    ' more code
Err2:
    MsgBox "Got here safely"
End Sub

Utiliser On Error GoTo -1 annule le gestionnaire d'erreurs actif et en permet la création d'un autre (et err.clear ne le fait pas!). Que ce soit une bonne idée ou non, reste un exercice pour le lecteur, mais ça marche!

4
AjV Jsy

Effacer tous les paramètres de propriété de l'objet Err ne signifie pas réinitialiser le gestionnaire d'erreurs. 

Essaye ça:

Sub TestErr()
Dim i As Integer
Dim x As Double
    On Error GoTo NextLoop
    For i = 1 To 2
10:     x = i / 0
NextLoop:
        If Err <> 0 Then
            Err.Clear
            Debug.Print "Cleared i=" & i
        End If
    Next
End Sub

Vous remarquerez que, tout comme l'OP, l'erreur sera corrigée correctement lorsque i =1 mais échouera à la ligne 10 lorsque i = 2, même si nous avons utilisé Err.Clear 

0
Profex