IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

Gestion d'une erreur de validation


Sujet :

Macros et VBA Excel

  1. #1
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut Gestion d'une erreur de validation
    Citation Envoyé par ChristianBosch Voir le message
    J'avais fais ça dans un userform avec un multipage ou j'avais près de 25 entrées et pour éviter a l’utilisateur de chercher ses erreurs de saisies je l'indiquais directement a la sorties de la textbox. Comme tous les champs étaient des nombres j'ai fais cette fonction sur mesures (oui je suis un flemmard mais, au fond, nous le sommes tous) pour me faciliter le codage.

    Par contre je ne connaissait pas le application.International(xlDecimalSeparator) intéressant afin d'éviter de remplacer !
    Mais malgré la valeur incorrecte le code appelant continue son exécution et j’imagine avec 25 entrés l'utilisateur doit être bombardé par les message box

    Simplement il faut ressaisir les entrées incorrectes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    Private Function GetDouble(box As MSForms.TextBox)
      On Error GoTo handler
      GetDouble = CDbl(box.Text)
      Exit Function
    handler:
      box.SelStart = 0
      box.SelLength = Len(box.Text)
      box.SetFocus
      MsgBox """" & box.Text & """ n'est pas une valeur numerique correcte", vbCritical
      Err.Raise vbObjectError + 100
    End Function
     
     
    Private Sub CommandButton1_Click()
    On Error GoTo handler
       Dim v1, v2, v3
       v1 = GetDouble(TextBox1)
       v2 = GetDouble(TextBox2)
       v2 = GetDouble(TextBox3)
     
    Exit Sub
    handler:
      If Err.Number <> vbObjectError + 100 Then: Err.Raise Err.Number
    End Sub

  2. #2
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    Perso, je ne suis pas fan du tout d'un on error goto lorsque l'on peut tester avec IsNumeric, et encore moins pour créer une nouvelle erreur après. Err.Raise ne devrait a priori pas exister en VBA. Ca n'a pas de sens de générer une erreur que l'on va devoir gérer par la suite... Je ne comprends pas bien pourquoi se compliquer autant la vie alors qu'un simple isnumeric encadrant éventuellement un replace est largement suffisant. Et je ne coderais jamais le setfocus dans une fonction qui vérifie qu'on a saisi un double. Il y a un gros défaut d'architecture, là. Au passage, Exit Function est pour moi une abomination.

    Je ne comprends pas ta fonction. Tu fais afficher un message d'erreur puis tu génères une erreur qui va planter le code...

    De plus, ça n'a pas plus de sens pour moi de mettre un msgbox à cet endroit-là. La fonction doit juste déterminer si on a saisi une valeur qui pourra être transformée en numérique. Si oui, elle pourra forcément être transformée en double...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Function IsNumericValue(Value As String) As Boolean
      IsNumericValue = IsNumeric(Replace(Replace(Replace(Value, " ", ""), ".", ","), ",", Application.International(xlDecimalSeparator)))
    End Function
    Si on veut transformer la valeur et tester si elle a pu être transformée, j'opérerais comme ceci en ne typant pas fonction et en testant un IsEmpty en cas de souci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Function StringToDouble(Value As String)
      Dim Temp
     
      Temp = Replace(Replace(Replace(Value, " ", ""), ".", ","), ",", Application.International(xlDecimalSeparator))
      If IsNumeric(Temp) Then StringToDouble = CDbl(Temp)
    End Function
     
    Sub Test()
      Dim Value As String
      Dim Result
     
      Value = "1 234,56"
      Result = StringToDouble(Value)
      If IsEmpty(Result) Then
        MsgBox "Raté"
      Else
        MsgBox Result
      End If
    End Sub

    Si on veut tendre vers du générique pour gérer les différents séparateurs en fonction des paramètres régionaux, c'est un peu plus compliqué. Normalement, on devrait considérer que les saisies sont conformes aux paramètres régionaux de l'utilisateur et ne traiter qu'à partir de cette hypothèse.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Mars 2021
    Messages
    334
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2021
    Messages : 334
    Points : 602
    Points
    602
    Par défaut
    Mais malgré la valeur incorrecte le code appelant continue son exécution et j’imagine avec 25 entrés l'utilisateur doit être bombardé par les message box
    Le code de L'USF s’arrête sur l'evenement appelant (ici en l’occurrence textbox_change), donc non ca ne bombarde pas l'utilisateur.

    L'utilisateur est bombardé dans le cas ou il rentre du texte a chaque fois... Si c'est le cas c'est qu'il est vraiment pas très futé (car en plus je fais la conversion point--->virgule sans message d'alerte)...

    Surtout que dans mon cas c'est un outil de production donc les personnes savent ce qu'elles doivent rentrer. Le but c'est plutôt d'éviter les erreur d'étourderie qui se retrouveraient dans mon tableau et provoqueraient des erreurs dans les calculs de KPI.

    Perso, pour signaler le problème dans un textbox, je bascule son fond en rouge pâle lors de la vérification de la saisie
    Et oui Pierre bonne remarque, c'est ce que je fais sur le bouton d'enregistrement quand un champs est vide et qu'il n'est pas censé l’être je mets les textbox en rouge ! Car je laisse la possibilité dans l'évenement change de laisser la textbox vide. J'ai décidé de combiner les deux méthodes pour faire gagner du temps a l'utilisateur lors de la saisie.

  4. #4
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut
    Perso, je ne suis pas fan du tout d'un on error goto lorsque l'on peut tester avec IsNumeric, et encore moins pour créer une nouvelle erreur après. Err.Raise ne devrait a priori pas exister en VBA. Ca n'a pas de sens de générer une erreur que l'on va devoir gérer par la suite... Je ne comprends pas bien pourquoi se compliquer autant la vie alors qu'un simple isnumeric encadrant éventuellement un replace est largement suffisant. Et je ne coderais jamais le setfocus dans une fonction qui vérifie qu'on a saisi un double. Il y a un gros défaut d'architecture, là. Au passage, Exit Function est pour moi une abomination.
    J'ai utilisé goto pour créer un bloque try/catch qui est une opération assez fréquente dans les langages évolués et facilite énormément la vie des développeurs .. c'est un code standard qu'on peut traduire en C#
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     double GetDouble(TextBox t)
    {
      try{
        return Convert.ToDouble(t.Text);
      }catch(Exception e)
      {
        t.SelectAll();
        t.Focus();
        throw e;
      }
    }

    Pour rappel la fonction et pour vérifier une série d'ENTREES de saisie et répondre a une situation assez fréquente mais elle peut contenir n’importe quelle autre restriction l’essentiel en cas de mauvaise saisie une erreur doit être déclencher.

    Je ne comprends pas ta fonction. Tu fais afficher un message d'erreur puis tu génères une erreur qui va planter le code...
    De plus, ça n'a pas plus de sens pour moi de mettre un msgbox à cet endroit-là. La fonction doit juste déterminer si on a saisi une valeur qui pourra être transformée en numérique. Si oui, elle pourra forcément être transformée en double...
    On peut dire que la section handler ne fait pas partie de la fonction son principale rôle est d'effectuer de petites opérations sur Textbox et a la sortie soit redéclencher l'erreur ou en créer une nouvelle pour empêcher le retour a l'appelant et d'aller directement au handler du bloque Goto englobant s'il y en pas le code plante ce qui ce qui est normal car il a déjà planté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
      Result = StringToDouble(Value)
      If IsEmpty(Result) Then
        MsgBox "Raté"
      Else
        MsgBox Result
      End If
    End Sub
    Je pense pas que tu as compris la pertinence du code que j'ai posté;tu te focalise uniquement sur la convertion vers le double mais tu peux me dire comment tu vas vérifier plusieurs entrées pour ne pas dire 25 entrées comme disait l'autre ,même avec une version améliorer la tache reste difficile.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Function GetDoubleFromBox(box As MSForms.TextBox, ByRef Value As Double) As Boolean
      Dim Temp
      Temp = Replace(Replace(Replace(box.Text, " ", ""), ".", ","), ",", Application.International(xlDecimalSeparator))
      GetDoubleFromBox = IsNumeric(Temp)
      If GetDoubleFromBox Then Value = CDbl(Temp)
    End Function
     
    Sub validAll()
    Dim V As Double
      If Not GetDoubleFromBox(TextBox1, v1) _
       Or Not GetDoubleFromBox(TextBox2, v2) _
       Or Not GetDoubleFromBox(TextBox3, v3) Then
         Exit Sub
     End If
      'reste du code 
    End Sub
    Si le fonction ValideAll est appeler dans une autre fonction on ne pourra pas savoir si cette opération s'est bien déroulé ou non

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     validAll 
     'ici on ne peut pas être sur la que la précédente opération a réussi ou pas
    Fichiers attachés Fichiers attachés

  5. #5
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut
    Le code de L'USF s’arrête sur l'evenement appelant (ici en l’occurrence textbox_change), donc non ca ne bombarde pas l'utilisateur.

    L'utilisateur est bombardé dans le cas ou il rentre du texte a chaque fois... Si c'est le cas c'est qu'il est vraiment pas très futé (car en plus je fais la conversion point--->virgule sans message d'alerte)...
    C'est votre choix et votre façon de coder que je respecte. on parle d'une façon générale pour moi la vérification au moment du saisie c'est un peu pour le style qui gonfle le code pour un petit gain la vérification finale doit être faite une seule fois au moment de la validation (via ok) et pour laisser aussi davantage de liberté de déplacement sur la fiche en fait dans certains cas si on entre dans une entrée on ne pourrait pas sortir sans fournir une valeur correcte en plus l'utilisateur peut annuler toute l’opération donc on devrait pas être très rigoureux afin que ces messages ne se transforment pas un harcèlement.

  6. #6
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    Salut Wheel,

    Citation Envoyé par wheel Voir le message
    J'ai utilisé goto pour créer un bloque try/catch qui est une opération assez fréquente dans les langages évolués et facilite énormément la vie des développeurs .. c'est un code standard qu'on peut traduire en C#
    Je connais bien le Try\Catch\Finally. J'ai assez souvent dit sur ce forum que le On Error était un Try\Catch\Finally à la sauce VBA . Mais je dis aussi qu'il faut l'utiliser à bon escient et qu'il n'a pas sa place lorsqu'une fonction native du langage permet de l'utiliser. Si IsNumeric ou IsDate existent, c'est justement pour éviter la gestion d'erreur des CDbl et CDate sur des valeurs non convertibles. Perso, remplacer IsNumeric par une gestion d'erreur, assortie en plus d'un Exit Function, ne fait pas partie de mes bonnes pratiques alors que, justement, le On Error Goto bien construit évite le Exit Function qui est pour moi un non-sens et une pratique à éradiquer.


    Citation Envoyé par wheel Voir le message
    l’essentiel en cas de mauvaise saisie une erreur doit être déclencher
    Ce n'est pas obligatoire qu'une erreur soit déclenchée en cas de mauvaise saisie. Ce qui est obligatoire, c'est qu'il y ait quelque chose qui avertisse l'utilisateur et qui bloque la validation. Un Err.Raise est UNE possibilité parmi d'autres d'arriver à cela. Mais le Err.Raise ne fait que déporter la gestion de l'erreur ailleurs, donc à l'intérieur d'un projet VBA, je ne vois pas l'intérêt du Err.Raise.



    Citation Envoyé par wheel Voir le message
    lJe pense pas que tu as compris la pertinence du code que j'ai posté
    Tracasse. Je suis capable de lire et comprendre un code informatique . Au passage, GetDoubleFromBox n'a pas grand-chose à voir avec GetDouble, mais c'est GetDouble que je critiquais, notamment pour le Exit Function et son message intempestif suivi d'une levée d'erreur. Je maintiens que ça n'a pas de sens et perso, cette architecture d'une fonction, non typée en plus, sensée renvoyer un double mais qui, en plus, vide le contrôle, donne le focus à un contrôle, ramène le point d'insertion au début de la zone de saisie, émet un message à l'intention de l'utilisateur et génère une erreur, ce n'est vraiment pas ma tasse de thé. Le Err.Raise vbObjectError + 100 va donner -2147221404 qui est vraiment un très beau numéro d'erreur, facile à donner au support De plus, il me semblerait utile, si vraiment on doit lever une erreur, de renseigner au moins une description: Err.Raise 1000,,"Valeurs non conformes à la saisie", par exemple. De plus, le Err.Raise impose qu'il y ait une gestion d'erreur quelque part dans la pile des appels. Si je pense que tout code évènementiel devrait être assorti d'une gestion d'erreur pour éviter d'entrer en débogage, je sais que c'est rarement le cas d'une part, et que d'autre part le VBE permet de s'arrêter sur l'erreur même avec une gestion d'erreurs. C'est une des raisons qui fait que je ne suis pas fan de la "programmation par l'erreur", en VBA du moins, mais dans les autres langages que je connais également.

    Citation Envoyé par wheel Voir le message
    Si le fonction ValideAll est appeler dans une autre fonction on ne pourra pas savoir si cette opération s'est bien déroulé ou non
    ValideAll n'est pas une fonction mais une procédure donc une fonction Void qui ne renvoie pas de valeur. Le principe d'une fonction de vérification est qu'elle renvoie une valeur qui reprend le résultat du test. Tu peux bien sûr utiliser une procédure qui génère une erreur, mais c'est un style de programmation qui n'est pas le mien, car je n'aime pas "programmer par l'erreur". Ca ne donne pas un déroulement fluide du code, ça n'en permet pas une lecture linéaire et ça rend complexe la gestion de situations qui au départ ne le sont pas. De plus, pour moi, la vérification de la saisie et la transformation des données sont deux choses différentes et ne se passent pas sur le même plan. Au clic sur le bouton de validation, on vérifie les données, puis on les transforme au besoin pour les traiter dans la suite du code (=> une autre procédure/fonction).


    Citation Envoyé par wheel Voir le message
    mais tu peux me dire comment tu vas vérifier plusieurs entrées
    Le nombre de contrôles à tester ne rend pas la tâche plus laborieuse. Tout dépend comment tu veux alerter l'utilisateur et comment tu veux lui permettre de gérer le problème de saisie. Si tu as 25 contrôles ou plus et que l'utilisateur est manche au point d'avoir saisi 20 contrôles en erreur, tu vas te taper 20 messages d'erreur au fur et à mesure de la vérification du formulaire et de la correction des erreurs. J'ai des doutes sur le plan ergonomique.

    Voilà une manière parmi d'autres de vérifier une saisie, sans Exit Function, sans On Error mal géré et sans Err.Raise. On peut utiliser les tags des contrôles pour déterminer ce qu'on attend. Ici, pour l'exemple, j'ai un tag composé de deux valeurs, le type de données attendu et le fait que la saisie soit obligatoire ou facultative (par exemple "String;Mandatory" ou "Numeric;Optional")... Je n'ai que trois contrôles, mais tu peux en avoir 200 si tu veux, c'est la même fonction qui sera utilisée. On pourrait même, si on voulait, récupérer un tableau ou une collection des contrôles en erreur en plus de la valeur de retour pour colorer, dans une autre procédure, les contrôles qui posent problème.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    Private Sub btnValidate_Click()
      Dim Result As Long
      Dim Message As String
     
      Result = DataAreOk()
      If Result = 0 Then
        Message = "Tout est ok"
      Else
        If (Result And 1) = 1 Then Message = "Toutes les données obligatoires n'ont pas été renseignées."
        If (Result And 2) = 2 Then Message = Message & IIf(Message <> "", vbLf, "") & "Certaines dates saisies ne sont pas valides"
        If (Result And 4) = 4 Then Message = Message & IIf(Message <> "", vbLf, "") & "Certaines valeurs numériques ne sont pas valides"
      End If
      If Message <> "" Then MsgBox Message, vbExclamation
    End Sub
     
    Function DataAreOk() As Long
      Dim MissingValues As Long
      Dim ErrorOnDates As Long
      Dim ErrorOnNumerics As Long
      Dim ctl As MSForms.Control
     
      For Each ctl In Me.Controls
        If ctl.Tag Like "*Mandatory*" Then
          If ctl.Value = "" Then MissingValues = 1
        End If
        If ctl.Tag Like "*Date*" Then
          If ctl.Value <> "" And Not IsDate(ctl.Value) Then ErrorOnDates = 2
        End If
        If ctl.Tag Like "*Numeric*" Then
          If ctl.Value <> "" And Not IsNumeric(ctl.Value) Then ErrorOnNumerics = 4
        End If
      Next
      DataAreOk = MissingValues + ErrorOnDates + ErrorOnNumerics
    End Function

    Pour moi, la gestion des erreurs ne devrait être utilisée que dans du code évènementiel ou lorsque l'erreur ne peut pas être gérée autrement:
    dans un code évènementiel car c'est forcément l'appel le plus bas dans la pile et donc ça évite d'entrer en débogage (sauf option spécifique du VBE);
    Lorsque l'on ne peut pas gérer le risque autrement. Si je veux ouvrir un fichier, je suis obligé d'utiliser un On Error car je ne sais pas tester que je vais pouvoir ouvrir le fichier avant de l'ouvrir. je suis donc obligé de tenter de l'ouvrir et de voir si cela génère une erreur. Et je persiste et signe: devoir gérer des erreurs prévisibles et contournables à coup de On Error et lever des erreurs à coup de Err.Raise résulte pour moi de défauts d'architecture en VBA.


    Cela dit, ce ne sont que mes bonnes pratiques. A chacun de trouver les siennes.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  7. #7
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut
    il me semblerait utile, si vraiment on doit lever une erreur, de renseigner au moins une description: Err.Raise 1000,,"Valeurs non conformes à la saisie", par exemple.
    C'est l'utilisation normale j'en ai même fait un code toutefois j'ai évité de mettre le code pour "Msgbox" a la sortie de l’événement appelant et pour éviter de le réécrire a chaque fois que je dois utiliser la fonction GetDouble donc il sera plus judicieux de placer message box dans a la sortie de GetDouble ...il faut se rappeler encore que l’utilisation cette fonction est dans la validation finale à un seul niveaux de l'évènement

    De plus, le Err.Raise impose qu'il y ait une gestion d'erreur quelque part dans la pile des appels.
    Oui c'est une gestion d'erreur structuré

    car je n'aime pas "programmer par l'erreur". Ca ne donne pas un déroulement fluide du code, ça n'en permet pas une lecture linéaire et ça rend complexe la gestion de situations qui au départ ne le sont pas.
    Malheureusement la gestion des erreurs en VBA n'est pas bien faite c'est une réalité a part une utilisation structuré comme dans les langages( le code reste linière et fluide) je ne suis pas non plus fan a son utilisation les exemples on les rencontre et ce n'est pas rare

  8. #8
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    Sans aucune ponctuation, c'est un peu pénible à lire et à essayer de comprendre...

    Citation Envoyé par wheel Voir le message
    [...]Malheureusement la gestion des erreurs en VBA n'est pas bien faite c'est une réalité[...]
    C'est TA réalité. Perso, je trouve qu'elle est aussi bien faite que le Try-Catch-Finally dans d'autres langages que je connais, surtout lorsqu'on l'utilise correctement dans un code bien structuré, et pas "à tout va" et dans n'importe quelle circonstance avec des Exit Function et des procédures/fonctions qui font 36 choses à la fois


    Citation Envoyé par wheel Voir le message
    [...]a part une utilisation structuré comme dans les langages( le code reste linière et fluide) je ne suis pas non plus fan a son utilisation les exemples on les rencontre et ce n'est pas rare
    Les Try-Catch-Finally ou On Error étant en fait des Goto conditionnels, je ne vois pas comment ils pourraient participer à un code fluide et surtout linéaire (à part le On Error Resume Next)...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  9. #9
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut
    C'est TA réalité. Perso, je trouve qu'elle est aussi bien faite que le Try-Catch-Finally dans d'autres langages que je connais, surtout lorsqu'on l'utilise correctement dans un code bien structuré
    En VBA les deux opérations Finally et Catch sont fusionner en une ce qui complique son utilisation un bloque catch ne doit pas être exécuter qu'en cas d'erreur on ne peut pas faire ca sans utiliser Exit Function ou Exit Sub correspond au code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Exit Function
    Catch:
      ....
    End Function

    Les Try-Catch-Finally ou On Error étant en fait des Goto conditionnels, je ne vois pas comment ils pourraient participer à un code fluide et surtout linéaire (à part le On Error Resume Next)...
    Il est claire et limpide comme les bloques If qui sont aussi conditionnels.. c'est le développeur qui doit être conscient de ce qu'il écrit dans sans code en plus il ne faut limiter l'inspection uniquement au corps de la fonction mais aussi au vecteur des exceptions.

  10. #10
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    Citation Envoyé par wheel Voir le message
    En VBA les deux opérations Finally et Catch sont fusionner en une ce qui complique son utilisation un bloque catch ne doit pas être exécuter qu'en cas d'erreur on ne peut pas faire ca sans utiliser Exit Function ou Exit Sub correspond au code suivant [...]
    Non, les blocs ne sont pas fusionnés et on peut gérer l'erreur sans besoin du Exit Function(*). Voici la modélisation d'un bloc Try/Catch/Finally sans Exit Function et sans fusion Catch/Finally. Avec 5/0, on voit bien que l'on passe sur le catch puis sur le Finally, alors qu'avec 5/1, on ne passera que sur le Finally. On a donc bien le fonctionnement du Try/Catch/Finally des autres langages.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     Sub Test()
      On Error GoTo Catch: ' Debut du bloc Try
      Debug.Print 5 / 0
      '...
      '...
      '...
      ' Fin du bloc Try
     
    Catch:
      If Err <> 0 Then ' Début du bloc Catch
        MsgBox "on est dans le catch pour gérer l'erreur " & Err.Number
        '...
        '...
        '...
      End If ' Fin du bloc Catch
     
      ' Début du bloc Finally
      MsgBox "On passe ici pour le Finally"
      '...
      '...
      '...
      ' Fin du bloc Finally
    End Sub
    La différence avec les autres langages, c'est que le bloc TRY/CATCH/[FINALLY] impose au moins le CATCH, alors que le ON ERROR permet de se passer de l'un ou l'autre des blocs CATCH FINALLY. Dans les faits, on ne se passera pas du test If Err <>0 then qui matérialise le CATCH en VBA.




    Citation Envoyé par wheel Voir le message
    Il est claire et limpide comme les bloques If qui sont aussi conditionnels.. c'est le développeur qui doit être conscient de ce qu'il écrit dans sans code en plus il ne faut limiter l'inspection uniquement au corps de la fonction mais aussi au vecteur des exceptions.
    Ce n'est pas la même chose. Le bloc If reste dans la linéarité et est facile à repérer si l'on indente le code. On lit les lignes de codes et on arrive à une condition qui fait que l'on rentre dans le bloc ou pas, mais c'est linéaire, et si la condition n'est pas remplie, on saute simplement le bloc. Lorsque l'on saute à l'étiquette après une erreur (sauf un On Error Resume Next), on ne sait pas forcément quelle ligne va nous faire passer au bloc de gestion de l'erreur, et on ne "voit" pas directement ce bloc. il y a bien une rupture de la linéarité du code.




    (*) Les EXIT ne devraient pas exister, que ce soit pour sortir d'une fonction, d'une procédure, d'une propriété, d'une boucle. C'est pour moi un non sens en programmation. Toute procédure/fonction ne peut avoir qu'une entrée et qu'une sortie. Ca permet de remettre tout à zéro, notamment en passant par le Finally avant de sortir (Suppression des tableaux, remise des options d'applications que l'on aurait modifiées, fermeture d'un fichier, ...)
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  11. #11
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut
    Non, les blocs ne sont pas fusionnés et on peut gérer l'erreur sans besoin du Exit Function(*). Voici la modélisation d'un bloc Try/Catch/Finally sans Exit Function et sans fusion Catch/Finally. Avec 5/0, on voit bien que l'on passe sur le catch puis sur le Finally, alors qu'avec 5/1, on ne passera que sur le Finally. On a donc bien le fonctionnement du Try/Catch/Finally des autres langages.
    Si..dans les autres langages et apres l'exécution du code dans le finally le contrôle ne sera jamais remis au code applant car finally n'empêche pas la propagation de l'erreur .. la pile des appels ne sera pas utilisé on passe directement au victeur des exceptions pour exécuter le prochain bloc installé donc en absence d'un autre gestionnaire d erreur englobant le code finira par planter .

  12. #12
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    On ne se comprend peut-être pas, mais honnêtement, l'absence de ponctuation et la syntaxe de tes messages n'aident pas à comprendre tes propos.

    Citation Envoyé par wheel Voir le message
    Si..dans les autres langages et apres l'exécution du code dans le finally le contrôle ne sera jamais remis au code applant car finally n'empêche pas la propagation de l'erreur
    Ben si, le code est aiguillé sur le code appelant. C'est le but même du Finally. L'erreur est capturée et traitée, puis on passe sur le finally et le code se rebranche après sur le code appelant. Sinon, ça n'a pas d'intérêt de gérer l'erreur. il n'y a donc pas de propagation de l'erreur. Cela étant dit, c'est vrai que ce n'est pas finally qui empêche la propagation, c'est le try/catch (puisque finally est optionnel).

    Si, dans le Catch, tu lèves une erreur avec throw, alors il faut considérer deux cas: soit il y a un gestionnaire d'erreur dans la pile, soit pas. S'il y en a un, le code ne plante pas , l'éventuel finally est exécuté puis le branchement est réalisé sur le premier gestionnaire d'erreur présent dans la pile. S'il n'y a pas de gestionnaire d'erreur dans la pile, le code plante sur la ligne du throw et le finally n'est pas exécuté. Forcément, dans ce cas-là, il n'y a pas de propagation. Mais dans une application, ce cas ne se présentera jamais. il serait idiot de lever une erreur avec un throw pour ne pas la gérer plus tard => Ca corrobore ce que je disais précédemment: Dans une appli, un throw (ou un Err.Raise en VBA) n'a pas de sens. le throw n'a de sens que dans une bibliothèque ou un contrôle personnalisé, mais est une ineptie dans le code d'une application s'il n'y a pas de gestion d'erreur en amont, c'est-à-dire dans la pile des appels, puisque l'on sait alors que le code peut planter.

    En ça, le fonctionnement n'est pas identique à celui du VBA puisque, en présence d'un Err.Raise, le code est de suite branché sur le premier gestionnaire d'erreur de la pile d'erreur ou plante en l'absence de gestionnaire d'erreur. Mais en VBA, dans la mesure où le périmètre d'exécution du code est le projet VBA, Err.Raise n'a aucune utilité et c'est une ineptie de le placer dans le code de gestion de l'erreur. Il avait une utilité en VB6 qui permettait de créer des dll, des classes ou des contrôles personnalisés qui seraient appelés par d'autres projets.



    Citation Envoyé par wheel Voir le message
    [...]donc en absence d'un autre gestionnaire d erreur englobant le code finira par planter .
    Tu énonces un truisme, là . il est évident qu'en l'absence d'un gestionnaire d'erreur dans la pile, le code plante sur une erreur. Donc, envoyer un Err.Raise dans un code VBA est inepte puisque soit il n'y a pas de gestionnaire d'erreur dans la pile et le code plante, soit il y a un gestionnaire d'erreur et donc, pourquoi générer une erreur sur une erreur plutôt que la traiter de suite. J'attends l'exemple qui me démontrera le contraire .

    Mais ce sont des digressions sur la gestion des erreurs en C# (ou d'autres langages). Je t'invite à lire les tutos liés à la gestion des erreurs sur les forums de ces langages si tu veux perfectionner ton approche et mieux comprendre le fonctionnement de la gestion d'erreurs avec les blocs try/catch/[finally].

    Pour ce qui est du vba, j'ai modélisé le code qui met le mieux possible en place la gestion d'une erreur "à la manière d'un try/catch/[finally]", en précisant que Err.Raise est inutile en VBA et que dans une appli bien construite, on place une gestion d'erreur sur tout code évènementiel pour ne pas planter et entrer en débogage, puisque toute procédure évènementielle est , par définition, la première de la pile, c'est-à-dire celle du bas de la pile. On est ainsi certain d'avoir toujours un gestionnaire d'erreur dans la pile, que l'on gère avec les blocs catch et [finally]. Ce code fonctionne sans Exit d'aucune sorte et est pour moi la seule bonne façon de gérer les erreurs en VBA.

    C'est vrai qu'en VBA, on pourrait utiliser une classe d'un autre project, mais c'est de toute façon en "PublicNotCreatable" et ça doit représenter 0.000000000000000000001% des projets VBA. On ne s'étendra donc pas là-dessus.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  13. #13
    Membre actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Points : 292
    Points
    292
    Par défaut
    Ben si, le code est aiguillé sur le code appelant. C'est le but même du Finally. L'erreur est capturée et traitée, Sinon, ça n'a pas d'intérêt de gérer l'erreur. il n'y a donc pas de propagation de l'erreur.
    On peut dire qu'il n'existe aucun finally en VBA c'est un simple catch pour capturer l'erreur on peut le modéliser comme ca en C# et la partie que tu appelles finally se situe en dehors de tout le bloc TRY
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    try{ 'On error 
     
    }catch(Exception e){} 'l’étiquette 
     'le code après étiquette 
     '.. 
     '..
    Si, dans le Catch, tu lèves une erreur avec throw, alors il faut considérer deux cas: soit il y a un gestionnaire d'erreur dans la pile, soit pas. S'il y en a un, le code ne plante pas , l'éventuel finally est exécuté puis le branchement est réalisé sur le premier gestionnaire d'erreur présent dans la pile.
    Non si une erreur se produite en CATCH et FINALLY est présent alors ce denier sera exécuté avant de déclencher l'erreur .. il y a toujours la garantie d’exécution pour le "finally" ... En VBA l’opération FINALLY est difficile à implémenter à 100% surtout qu'elle impose aussi le déclenchement du bloc si une instruction de saut EXIT SUB, EXIT FUNCTION, NEXT est utilisée dans le bloc protégé (TRY).. cette opération ne peut être envisager que nativement.

    il serait idiot de lever une erreur avec un throw pour ne pas la gérer plus tard
    Oui d’accord sur ce point dans les applications il existe un gestionnaire qui s'occupe de ces erreurs non gérés.

    Ca corrobore ce que je disais précédemment: Dans une appli, un throw (ou un Err.Raise en VBA) n'a pas de sens. le throw n'a de sens que dans une bibliothèque ou un contrôle personnalisé, mais est une ineptie dans le code ...
    Comme n'importe quelle autre approche dont l'efficacité dépend du programmeur. les débutants ne sont pas obligés d'adopter cette méthode. mais les autres qui ont déjà de l'expérience peuvent estimer et évaluer l'apport et le gain qu'elle peut apporter.(seule la pratique répondra)

    pourquoi générer une erreur sur une erreur plutôt que la traiter de suite. J'attends l'exemple qui me démontrera le contraire
    Je retourne à l'exemple précédent qui représente un cas typique de vérification de la saisie.(ajusté)
    Le code effectue trois opérations : la vérification de la valeur, la mise en surbrillance de l'entrée et permet de stopper le programme au cas de mauvaise saisie;

    La décompose de cette fonction produira une ribambelle de blocs de if et de test pour mener la même opération, le code reste réutilisable pour futur usage sans toucher a une ligne de code sauf pour modifier la condition de la validation qui varie selon le besoin.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    Private Function ReadDblFromTextBox(box As MSForms.TextBox)
    Dim S As String
      S = Replace(Replace(Replace(box.Text, " ", ""), ".", ","), ",", Application.International(xlDecimalSeparator))
      If IsNumeric(S) Then
         ReadDblFromTextBox = CDbl(S)
      Else
         box.SelStart = 0
         box.SelLength = Len(box.Text)
         box.SetFocus
         MsgBox """" & box.Text & """ n'est pas une valeur numerique correcte", vbCritical
         Err.Raise vbObjectError + 1000
      End If
    End Function
     
    Private Sub Valider_Click()
    Dim v
    On Error GoTo Finally
     v = ReadDblFromTextBox(TextBox1) + ReadDblFromTextBox(TextBox2) _
         + ReadDblFromTextBox(TextBox3)
     
     MsgBox v
     
    Finally:
    If Err <> 0 Then
        If Err.Number <> vbObjectError + 1000 Then Err.Raise Err.Number
    End If
    End Sub

    Mais ce sont des digressions sur la gestion des erreurs en C# (ou d'autres langages). Je t'invite à lire les tutos liés à la gestion des erreurs sur les forums de ces langages si tu veux perfectionner ton approche et mieux comprendre le fonctionnement de la gestion d'erreurs avec les blocs try/catch/[finally].
    Perso j'ai créé mon propre scripte qui prend en charge ces opérations le problème n'est pas la .. je me suis bien documenté !


  14. #14
    Responsable
    Office & Excel


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 122
    Points : 55 921
    Points
    55 921
    Billets dans le blog
    131
    Par défaut
    Citation Envoyé par wheel Voir le message
    On peut dire qu'il n'existe aucun finally en VBA[...]
    Non, ce n'est pas exact. Tu as dis toi-même que catch et finally étaient fusionnnés en VBA, ce qui est exact, dans les faits. S'i y a un gestionnaire d'erreur, l'erreur est "gérée" en ce qu'elle ne plante plus le code (C'est une partie du catch ET le code qui suit l'étiquette sera exécuté qu'il y ait ou non erreur (C'est le finally). Si l'on veut jouer sur les mots, je serais alors d'accord de dire qu'il y a toujours un finally et que celui-ci englobe éventuellement du code spécifique en cas d'erreur avec le code If Err <> 0 Then. On ne pourra donc jamais faire correspondre pile poil les mécanismes C# et VBA puisqu'en VBA, on est branché sur une étiquette qui fait "un peu de catch" (l'erreur ne plante pas) et un peu de finally (selon que l'on utilise un Exit Function ou pas).

    Je rappellerai que la discussion a commencé sur ton code qui m'a fait tiquer parce qu'il
    • utilisait un Exit Function avant l'étiquette, ce qui désactive le mécanisme du finally de C# (comme un bloc try/catch # sans finaly);
    • levait à nouveau l'erreur avec Err.Raise.



    Je rappellerai aussi que tu as affirmé qu'il n'était pas possible de gérer l'erreur sans Exit function alors que j'ai montré avec le code VBA donné précédemment que l'on peut modéliser catch/finally en utilisant un bloc If Err <> 0 Then pour "défusionner" catch et finally et modéliser try/catch/finally au plus près du mécanisme C#. Utiliser Exit Function comme tu l'as fait revient à se priver de la possibilité de finally, puisque pour avoir un finally avec un Exit Function, tu dois rebrancher une deuxième fois après le traitement de l'erreur par code sur une étiquette se trouvant AVANT Exit Function. Ca donnerait juste du code spaghetti. Sans Exit Function et avec un bloc If Err <>0 Then après l'étiquette, on est en VBA au plus près de ce qui se fait en C#.


    Après, que tu proposes de programmer à coup de On Error pour éviter les If en cascade et que je propose une autre approche, c'est une question de style. Perso, je n'aime pas "programmer par l'erreur" parce qu'à mon estime, ça ne rend pas le code fluide, ça oblige à trouver quelle erreur a été commise pour la gérer (on déporte alors la cascade des If ou des Select Case dans le bloc de gestion de l'erreur), et ça fait entrer en jeu des mécanismes "hors vba" (mise en attente du thread au niveau du processeur, branchement sur le processeur d'erreur, réactivation du thread si le processeur d'erreur a trouvé où le rebrancher, ...).
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

Discussions similaires

  1. Une erreur de validation
    Par PseT34 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 7
    Dernier message: 11/01/2008, 11h12
  2. Réponses: 15
    Dernier message: 13/10/2007, 11h39
  3. Gestion d'une erreur de cmde Windows
    Par kenny49 dans le forum Windows XP
    Réponses: 1
    Dernier message: 23/04/2007, 12h35
  4. [VBA-E] Gestion d'une erreur #N/A
    Par Mut dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 07/04/2006, 20h17
  5. gestion d'une erreur
    Par Jeannotc dans le forum Bases de données
    Réponses: 8
    Dernier message: 25/06/2004, 18h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo