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

Sondages et Débats Discussion :

[Cours pt-04]les bases du débogage


Sujet :

Sondages et Débats

  1. #1
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut [Cours pt-04]les bases du débogage
    >>>> Merci de noter toutes remarques concernant ce cours dans le sujet parallèle : [Cours papyturbo]Commentaires, remarques et suggestions
    -------------------------------------------------------------------------
    Ce cours est la suite
    - du [Cours pt-01][Débutants]Analyse structure base de données simple et
    - du [Cours pt-02][Débutants]Requête avec plusieurs sommes
    - et représente une "pause" dans le déroulement du [Cours pt-03]turbo-formulaire (les bases), pause destinée à défricher les bases du débogage avant de retourner finir notre formulaire.
    Il commence donc par une réponse aux questions posées par Serge57, dans la réponse #10 du cours précédent (le 03),
    et nous travaillons à partir du dernier .mdb :
    SuiviAffaire 2006-08-17.zip (89,0 ko) -------------------------------------------------------------------------

    Zzzzzzap!, zoooing ! tiou tiou tiou tiou, sortez vos lasers quantiques et vos tromblons zappeurs, enfilez le costard de Blade Runner, on part à la chasse aux bugs , en espérant que ce ne soient pas eux qui nous flinguent les premiers.

    D'abord, se référer au débat [Conseils] Comment retrouver un problème , qui traite de ce sujet assez à fond. Il contient tous les principaux aspects du débogage et mérite d'être relu par tous.
    Ici, nous détaillerons surtout les étapes de base pour débutants.

    ----------------
    Je reprends le bug déjà signalé et apparemment corrigé dans la réponse #9.

    La 1ère étape consiste à identifier le bug. Si un message d'erreur s'affiche, facile. Là, ce n'était le cas qu'à condition de faire des tests. En l'occurence, réduire le formulaire à sa taille la plus petite, à partir du coin inférieur droit (mais également : le passer en plein écran, puis en réduction, etc.)

    La 2ème étape, c'est le travail du beta testeur qui doit décrire aux développeurs "Comment reproduire le bug". En tant que développeurs, on doit au moins savoir faire cela, et ça a consisté en (dans la réponse #9 du cours 03) :
    Je n'ai peut être pas été assez clair, donc, pour reproduire le bug, avec ta dernière version du .mdb :
    1- démarrer l'application 'Affaires'
    2- agrandir Access en plein écran,
    3- réduire le formulaire Affaires, pour pouvoir le redimensionner à la souris,
    4- saisir le bord inférieur, et remonter jusqu'à ce que la section détail, qui contient le sous-formulaire ssfAffaires, disparaisse.
    Dès qu'il disparaît complètement, on a une erreur 2100 'Contrôle ou sous-formulaire trop grand.'


    La 3ème étape consiste à comprendre ce qu'il se passe et, lors de l'affichage du message, j'ai une boîte de dialogue avec le message et 2 boutons actifs : Fin (on arrête tout, sans commentaire) ou Débogage (clic)
    Le bouton Débogage m'amène sur une ligne de code jaune, la ligne qui provoque l'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                Me.Section(acDetail).Height = NewHeight
    Là, je regarde les 2 valeurs qui pourraient être concernées.
    Pour ça, les techniques de base sont :
    - laisser la souris au dessus du nom d'une variable, comme 'NewHeight' : sa valeur s'affiche dans une bulle.

    Ça ne marche pas toujours pour une expression plus complexe, comme 'Me.Section(acDetail).Height (si la souris est au dessus de 'acDetail', la bulle affiche 'acDetail = 0', ce qui ne nous intéresse pas). Donc :
    - sélectionner l'expression et appuyer sur Maj+F9 : la valeur s'affiche dans une boîte de dialogue.

    Troisième méthode :
    - ouvrir la fenêtre de débogage avec Ctrl+G, et, dans la fenêtre d'exécution qui s'ouvre sous le code, taper un '?' suivi d'un espace et de la valeur, le nom de la variable ou l'expression à évaluer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ? Me.Section(acDetail).Height
     105
    Maintenant, je sais que
    - ma section détail, avant le Form_resize, mesurait 105 twips en hauteur,
    - la variable NewHeight est négative (-5).
    D'où vient cette NewHeight négative ?
    Elle est calculée au dessus, en gros :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    NewHeight = Me.InsideHeight - Me.Section(acHeader).Height
    On peut ignorer la section acFooter, dont la hauteur est 0.
    Ce qui veut juste dire que je suis remonté tellement vite que InsideHeight (la fenêtre) est plus petit que la section acHeader (l'en-tête du formulaire).
    4ème étape : trouver la solution.
    Il paraît ici évident qu'on ne peut pas demander à Access de dessiner une section Détails dont la hauteur serait négative !
    D'où, solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            If NewHeight > 0 Then
                Me.Section(acDetail).Height = NewHeight
                .Height = NewHeight - (.Top * 2)
            End If
    On ne va ajuster la hauteur de la section détails que si elle est positive.

    5ème étape : documenter le probème.
    Et ça devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            'Pour empêcher l'erreur de dimensionnement du formulaire (erreur 2100)
            If NewHeight > 0 Then
                Me.Section(acDetail).Height = NewHeight
                .Height = NewHeight - (.Top * 2)
            End If
    Étape qu'on oublie trop souvent, indispensable pour permettre de se relire quelques mois plus tard.
    Trop de commentaires tueraient les commentaires ?
    Peut être, mais il en faut beaucoup pour que ce soit trop et au minimum, il faut signaler toute correction de bug ou de message d'erreur, comme ici.
    ---------------------
    Voilà, en 5 étapes, comment le premier message d'erreur a été "corrigé".

    Et tu me signales qu'il est encore là ?
    Citation Envoyé par Serge57
    En reproduisant la manip sur la base corrigée , l’erreur 2100 existe toujours ???.
    Mais c'est pas croyable, ça.

    Donc, même méthode -> reste plus qu'à trouver la solution appropriée ?

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Mais c'est pas croyable, ça.

    Donc, même méthode -> reste plus qu'à trouver la solution appropriée ?
    Et voici le nouveau code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            If NewHeight > (.Top * 2) Then
            'If NewHeight > 0 Then
                Me.Section(acDetail).Height = NewHeight
                'ssfAffaires.Top = 0 : juste au cas où ou mettrait une bordure autour du sous-form, ou...
                .Height = NewHeight - (.Top * 2)
            End If
    On m’a soufflé le code (merci pour le souffleur, il se reconnaîtra, je ne balance pas ). En suivant ta méthode, je pense que j'y serai arrivé tout seul.

    La 1ère étape consiste à identifier le bug. Si un message d'erreur s'affiche, facile. Là, ce n'était le cas qu'à condition de faire des tests. En l'occurence, réduire le formulaire à sa taille la plus petite, à partir du coin inférieur droit (mais également : le passer en plein écran, puis en réduction, etc.)
    Et oui, voilà l’expérience (ou le retour d’expérience) qui parle. Ce que je veux dire : Au début je n’avais même pas détecté le bug (l'erreur 2100), pas assez d ‘essai … Du coup, j’ai fait tout plein essais sur le formulaire et, je n’ai plus vu apparaître d’erreur. C’est BIEN ??

  3. #3
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    Citation Envoyé par Serge57
    Du coup, j’ai fait tout plein essais sur le formulaire et, je n’ai plus vu apparaître d’erreur. C'est bien ?
    Que demande le peuple ?
    C'est top cool, et c'est ce qu'il faut maintenant, à chaque routine, quelle qu'elle soit.
    Stop : pas vrai. Pas top cool. Et l'étape 5 ?
    In-dis-pen-sa-ble : noter un commentaire aussi concis que possible, mais clair !

    Puisque tu commences à être rôdé, continuons avec un bug un poil plus difficile.
    Dans la réponse #8 du cours pt03, tu as écrit :
    Citation Envoyé par Serge57
    J’ai remarqué que si access à plus de 2 de 2 lignes de menu, une barre d’ascenseur vertical se crée dans le conteneur.
    Il semble bien que tu aies détecté quelque chose (1ère étape), mais...
    - il faut peut être compléter cette première étape, en identifiant clairement le problème ("qu'est-ce qu'il fait ?" et "qu'est-ce qu'il devrait faire" ? ou bien "qu'est-ce qu'il fait qui ne va pas ?"
    - étape 2 : comment reproduire le bug ?
    et puis : 3, 4 et 5, bien sûr, mais il risque d'y avoir des pièges.
    Comme quoi, si quelque chose semble bizarre, faut fouiner ou, au minimum, le noter pour plus tard, mais jamais laisser passer, sinon, ça ne peut qu'empirer après...

    Coups de pouce (je conseille à chacun, dont Serge, de ne pas trop se faire aider, ça pert tout son fun) :
    1- pour arrêter le code qui pose problème, pouvoir inspecter les valeurs des variables et autres paramètres, et détecter la ou les instructions qui font que ça déc..., il va falloir, soit
    - appuyer sur F9 (ou menu Débogage > Basculer le point d'arrêt, dans l'IDE (espace de travail en VBA : I pour quèque chose genre "Interactive" ? + "Development Environment")
    - écrire un Stop dans le code, éventuellement suivi de ":", si tu le mets devant une instruction existante.
    Chacun son usage :
    Le F9 (point d'arrêt) est temporaire.
    Le Stop peut être enregistré avec le code (jusqu'à ce que le bug soit résolu, par exemple).

    2- s'il se passe des choses bizarres, ça vaudra le coup d'appuyer sur Ctrl+L (ou menu Affichage > Pile des appels). On en reparlera, mais j'attends tes questions / observations...

    Bien entendu, les points d'arrêt et la pile des appels sont documentés dans l'aide d'access.

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Il Il semble bien que tu aies détecté quelque chose (1ère étape), mais...
    - il faut peut être compléter cette première étape, en identifiant clairement le problème ("qu'est-ce qu'il fait ?" et "qu'est-ce qu'il devrait faire" ? ou bien "qu'est-ce qu'il fait qui ne va pas ?"
    Ok , j’ai joint un fichier .doc ou j’ai insérer deux images pour montrer le bug.


    1ère étape - Identification du bug -– un ascenseur apparaît verticalement quand je rajoute une ligne de menu access supplémentaire.


    2éme étape reproduction du bug – dans application « SuiviAffaire » ouvrir le formulaire 10-100 Affaires, si dans la barre de menu il y a plus de deux lignes « de boites outils » un ascenseur vertical apparaît.


    3éme étape comprendre ce qui se passe – Il n’y a pas de message d’erreur. Je suppose qu’il y a un petit hic sur la valeur de la variable « InsideHeight » retournée par access. J’ai remarqué qu’a chaque affichage d'un nouveau menu, la variable prend une autre valeur. Mais je n’ai pas trouvé de relation cohérante pour faire un "IF" ….
    Suis-je sur la bonne piste ?

    -------
    Fichiers attachés : reponse-4.doc (158,0 ko)
    -------

  5. #5
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    Bon pour l'identification du bug, et on peut le reproduire sans problème (étape 2). Sauf que j'aurais précisé : il faut que le formulaire Affaires soit en 'plein écran' pour que l'ascenseur apparaisse à droite (ça tombe bien, il se met en plein écran au démarrage ).

    Par contre, attention : la phrase
    Citation Envoyé par Serge57
    1ère étape - Identification du bug -– un ascenseur apparaît verticalement quand je rajoute une ligne de menu access supplémentaire.
    est plus précise que la suivante
    Citation Envoyé par Serge57
    2éme étape reproduction du bug – dans application « SuiviAffaire » ouvrir le formulaire 10-100 Affaires, si dans la barre de menu il y a plus de deux lignes « de boites outils » un ascenseur vertical apparaît.
    En faisant le test que tu prescris, je constate que :
    - quel que soit le nombre de barres d'outils,
    - si j'en supprime une (menu Affichage > Barres d'outils, ou clic droit dans l'espace des barres d'outils) : aucun problème, pas d'ascenseur,
    - si j'en ajoute une : apparition de l'ascenseur, ce qui permet, en le faisant glisser vers le bas, de voir une bande orange en dessous du sous-formulaire ssfAffaires. De plus, à l'oeil nu, cette bande semble avoir à peu près la hauteur d'une barre d'outils.
    Citation Envoyé par Serge57
    3éme étape comprendre ce qui se passe – Il n’y a pas de message d’erreur.
    Et voilà le hic ! Ce bug fait partie des pires qui soient . Donc, ça vaut le coup d'y passer un moment, en détail.
    Donc tu as dû
    - ouvrir le code (Alt+F11) de l'évènement Form_Resize()
    - cliquer sur la 1ère ligne (ou autre ?) et appuyer sur F9 pour insérer un 'point d'arrêt'
    ou bien
    - taper l'instruction Stop
    - revenir vers le formulaire,
    - faire le test (afficher une nouvelle barre d'outils),
    - chercher la valeur de InsideHeight et autres variables, lorsque l'exécution du code s'arrête sur le point d'arrêt ou sur le Stop.
    Citation Envoyé par Serge57
    Je suppose qu’il y a un petit hic sur la valeur de la variable « InsideHeight » retournée par access. J’ai remarqué qu’a chaque affichage d'un nouveau menu, la variable prend une autre valeur. Mais je n’ai pas trouvé de relation cohérante pour faire un "IF" ….
    A priori, je ne pense pas qu'il "y ait un hic" sur la propriété « InsideHeight » de notre formulaire.
    Je pense qu'elle change, en fonction de la taille allouée au formulaire.
    Le bon sens nous dit :
    - la fenêtre d'Access contient tout : barre de titre + menu (1 bande) + toutes les barres d'outils (1 bande chacune) + le formulaire, qui occupe "le reste".
    - quand on ajoute une barre d'outils ou de menu, on réduit l'espace vertical alloué au formulaire -> à vérifier de test en test.

    Je comprends que tu aies du mal à suivre ce qu'il se passe.
    Suite des outils de débogage : -------------
    Une fois l'exécution du code arrêtée par un point d'arrêt ou une instruction Stop, on peut :
    - (rappel) inspecter chaque valeur avec la souris, ou avec Shift+F9,
    - appuyer sur F8 pour exécuter chaque instruction en pas à pas.
    Normalement !
    Ce que je constate aussi :
    - si j'ai mis l'arrêt sur la 1ère ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Private Sub Form_Resize()
    Dim NewHeight As Long
    Dim NewWidth As Long
     
        Stop: With ssfAffaires
            '1- redimensionnement VERTICAL .....................................
            'Me.InsideHeight = somme de toutes les sections
            'footer est à 0.  Juste mentionnée à titre de précaution (si on met quelque chose dedans + tard)
            NewHeight = Me.InsideHeight - Me.Section(acHeader).Height - Me.Section(acFooter).Height
    et que j'appuies sur F8, l'instruction suivante (en jaune) passe sur 'NewHeight = Me.InsideHeight - Me.Section...'
    Ce qui est bien.
    Mais, si j'appuie encore sur F8 pour exécuter cette instruction, la ligne jaune (prochaine à exécuter) remonte en arrière !!!
    L'exécution repasse sur la 1ère ligne !
    Non, il n'y a pas vraiment de bug dans Access. Le problème ici, c'est que, à chaque fois qu'on exécute cette 2ème ligne de code, Access considère qu'on a changé la taille du formulaire et relance l'exécution de l'évènement Form_Resize.
    Ce qu'on peut constater en appuyant sur Ctrl+L : affichage de la pile des appels.

    Ce qu'on voit c'est que, à chaque fois qu'on exécute une ligne de code, la 'Fenêtre de débogage' relance l'exécution de l'évènement !
    Résultat : les évènement Form_Resize sont parmi les pires à déboguer , et on ne pourra pas utiliser F8 (faire du pas à pas) dans un évènement Form_Resize().

    On va devoir utiliser un autre outil : Debug.Print
    L'instruction Debug.Print (sur une ligne de code, il suffit de taper 'Debug.?') va afficher ce qu'on veut, dans la fenêtre d'exécution.
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Private Sub Form_Resize()
    Dim NewHeight As Long
    Dim NewWidth As Long
     
        With ssfAffaires
    Debug.? "InsideHeight" Me.InsideHeight
    va afficher la valeur de 'InsideHeight' à chaque exécution, sans qu'on ait besoin d'arrêter le code pour autant.
    Comme l'instruction est tout en haut de la subroutine, elle affiche la valeur avant d'exécuter notre code. Mais on pourrait aussi en mettre d'autres après, plus bas, pour avoir les résultats.
    Si je rééxécute le test (ajout / suppression d'une barre d'outils), je vois des valeurs défiler dans la fenêtre d'exécution, comme, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    InsideHeight= 6660 
    InsideHeight= 6270 
    InsideHeight= 6660
    On est donc toujours dans l'étape 3, mais on va pouvoir
    - sans mettre aucun Stop ni point d'arrêt,
    - savoir la hauteur de chaque objet (NewHeight + Section(acDetail) + ssfAffaires),
    - aussi bien avant d'exécuter le code de l'évènement Form_Resize qu'après,
    - à chaque opération (agandissement, réduction...).

    Est-ce que, avec ces outils, le problème commence à être plus précis ? ou bien tu nages encore plus ????

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Est-ce que, avec ces outils, le problème commence à être plus précis ? ou bien tu nages encore plus ????
    Beaucoup plus pratique que les « MsgBox ‘variable’ » que j’utilisais.

    Résultat obtenu des variables.
    1er lancement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    InsideHeight 13185 
    acHeader  2040 
    acFooter 0 
    NewHeight  11145 
    Height  11031
    Aprés insertion d’une bande de menu supplémentaire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    InsideHeight 12795 
    acHeader  2040 
    acFooter 0 
    NewHeight  10755 
    Height  10641
    Constat : Réduction de 390 twips de la fenêtre contenant le sous formulaire (InsideHeight) 13185-12795, et réduction de la hauteur du sous formulaire (height) 11031-10641.
    Donc la fenêtre contenant le sous formulaire « ssfAffaires » se corrige.

    Il reste le formulaire contenant, le formulaire « Affaires ».
    Il faudrait réajuster la hauteur du formulaire ?
    Je penche pour la variable windowheight. Suis je sur le bon chemin ?

  7. #7
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    On approche, on approche, mais c'est encore froid.
    J'aurais mis un peu plus d'indications, dans ces debug.print, concernant tout ce que nous essayons, avec plus ou moins de succès, de modifier.
    Les sections Header et Footer ne bougeront jamais, tes tests le confirment.
    Mais la section Détail, par contre, devrait être toujours égale à NewHeight, non ? Et le sous-formulaire aussi, à (2*.Top) près.
    Et, comme déjà indiqué, je ferais ces tests 2 fois à chaque resize :
    - avant nos opérations (au début de la routine), pour vérifier si on a la même valeur qu'au passage précédent,
    - après nos opérations, (juste avant le Exit) pour vérifier si les transformations sont bonnes ?
    Avec un mot ("avant" ou "après") dans chaque Debug.Print, pour qu'on sache.

    Petite astuce qui peut être utile pour mettre des commentaires dans la fenêtre d'exécution(par exemple noter, pour nous, si tu as ajouté ou si tu as masqué une barre d'outil, avant chaque série de mesure) :
    - si tu essayes d'aller à la ligne avec Enter, message d'erreur : Access essaye de compiler et exécuter la ligne.
    - tu peux aller à la ligne avec Ctrl+Enter sans afficher ce message d'erreur.

    Autre (voir la syntaxe de Debug.Print dans l'aide - F1) :
    - tu peux mettre autant de noms et de valeurs que tu veux sur la même ligne, en les séparant par des ";"
    - une ligne de commande Debug.Print qui se termine par un ";" ne va pas à la ligne. Donc, la prochaine commande continuera sur la même ligne.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    J'aurais mis un peu plus d'indications, dans ces debug.print, concernant tout ce que nous essayons, avec plus ou moins de succès, de modifier.
    Voici le nouveau code .

    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
     
    Private Sub Form_Resize()
    Dim NewHeight As Long
    Dim NewWidth As Long
     
        With ssfAffaires
            '1- redimensionnement VERTICAL .....................................
            'Me.InsideHeight = somme de toutes les sections
            'footer est à 0.  Juste mentionnée à titre de précaution (si on met quelque chose dedans + tard)
            NewHeight = Me.InsideHeight - Me.Section(acHeader).Height - Me.Section(acFooter).Height
            Debug.Print "—Avant le IF --";
            Debug.Print "InsideHeight="; Me.InsideHeight; " - "; "NewHeight="; NewHeight; " - "; "Height="; .Height; " - "; "acDetail="; Me.Section(acDetail).Height
            If NewHeight > 0 Then
                Debug.Print "Rentre dans le IF"
                Me.Section(acDetail).Height = NewHeight
                'ssfAffaires.Top = 0 : juste au cas où ou mettrait une bordure autour du sous-form, ou...
                .Height = NewHeight - (.Top * 2)
            End If
                '2- redimensionnement HORIZONTAL ...................................
                'NewWidth = Me.InsideWidth
                '.Width = NewWidth - (.Left * 2)
            'astuce, pour réduire la largeur du formulaire à
            '   la largeur du contrôle le plus à droite :
            Me.Width = 0
            Debug.Print "—Aprés le IF --";
            Debug.Print "InsideHeight="; Me.InsideHeight; " - "; "NewHeight="; NewHeight; " - "; "Height="; .Height; " - "; "acDetail="; Me.Section(acDetail).Height
        End With
        Debug.Print " --------------------------------"
    End Sub
    - Lors du premier lancement le résultat dans la fenêtre exécution est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     --------------------------------
    -- Avant le IF --InsideHeight= 13185  - NewHeight= 11145  - Height= 10641  - acDetail= 10755 
    Rentre dans le IF
    -- Aprés le IF --InsideHeight= 13185  - NewHeight= 11145  - Height= 11031  - acDetail= 11145 
     --------------------------------
    Je constate que la section Détail (acdétail) est bien égale à la variable NewHeight et que la hauteur du sous formulaire (height) aussi à (2*Top) près. Donc BON.

    Insertion d’une nouvelle barre de menu, résultat dans la fenêtre exécution est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     --------------------------------
    -- Avant le IF --InsideHeight= 12795  - NewHeight= 10755  - Height= 11031  - acDetail= 11145 
    Rentre dans le IF
    -- Aprés le IF --InsideHeight= 12795  - NewHeight= 10755  - Height= 10641  - acDetail= 11088 
     --------------------------------
    Le constat n’est plus le même. La section Détail n’a rein à voir avec la variable NewHeight par la la Hauteur du formulaire (Height) elle oui à (2*Top) prés.

    Après plusieurs essais et lecture des variables,
    - dés que la hauteur du sous formulaire est modifiée, Access recalcule la hauteur du de la section détail.
    D’où le nouveau code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            If NewHeight > 0 Then
                Debug.Print "Rentre dans le IF"
                .Height = NewHeight - (.Top * 2)
                Me.Section(acDetail).Height = NewHeight
                'ssfAffaires.Top = 0 : juste au cas où ou mettrait une bordure autour du sous-form, ou...
            End If
    la différence : D’abord j’impose la hauteur du sous formulaire, puis celle de la section détail du formulaire.

    Revenons à nos étapes.

    1 - Identification du bug réponse # 4
    2 - reproduction du bug réponse #4 corrigé par Papy Turbo dans réponse #5
    3 - Comprendre ce qui se passe Si l'on modifie la hauteur d'un sous formulaire (ou sous état), Access recalcul la hauteur de la section ou se trouve "ce sous formulaire."
    4 - Trouver la solution Une fois la hauteur du sous formulaire imposer, il faut impose la hauteur de la section contenant le sous formulaire. (Tout en restant logique avec la variable "InsideHeight"
    5 - documenter le problème
    d'où le nouveau code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            If NewHeight > 0 Then
                ' Toujours imposer la hauteur du Sous Formulaire avant la redéfinition de la section le contenant.
                .Height = NewHeight - (.Top * 2) ' hauteur du sous formulaire
                Me.Section(acDetail).Height = NewHeight 'hauteur de la section le contenant
                'ssfAffaires.Top = 0 : juste au cas où ou mettrait une bordure autour du sous-form, ou...
            End If

    On approche, on approche, mais c'est encore froid.
    c'est chaud ??

  9. #9
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut

    Ben voilà.
    Dans ce sens là, ça marche.

    Comme je suis vicieux et à l'intention de tous ceux qui meurent d'envie de se plonger dans le monde fascinant du Form_Resize(), je vais juste montrer ce que j'ai fait (c'est quasi identique à ce que tu as fait, juste une ligne de plus) , et les conclusions.
    L'ancien code, au complet, avec les Debug.Print :
    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
    35
    36
    37
    38
    Private Sub Form_Resize()
    Dim NewHeight                           As Long
    Dim NewWidth                            As Long
     
        With ssfAffaires
            '1- redimensionnement VERTICAL .....................................
            'Me.InsideHeight = somme de toutes les sections
            'footer est à 0.  Juste mentionnée à titre de précaution
            '   (si on met quelque chose dedans + tard)
            NewHeight = Me.InsideHeight - Me.Section(acHeader).Height - _
                        Me.Section(acFooter).Height
            If NewHeight > (.Top * 2) Then
    Debug.Print "1 | InsideHeight="; Me.InsideHeight; "| NewHeight="; NewHeight; _
                "| Section(acDetail)="; Section(acDetail).Height; _
                "| hauteur ssf avec bordure="; .Height + (.Top * 2); _
                "| ssfAffaires"; .Height; "| (.Top * 2)="; (.Top * 2)
                Me.Section(acDetail).Height = NewHeight
    Debug.Print "2 | InsideHeight="; Me.InsideHeight; "| NewHeight="; NewHeight; _
                "| Section(acDetail)="; Section(acDetail).Height; _
                "| hauteur ssf avec bordure="; .Height + (.Top * 2); _
                "| ssfAffaires"; .Height; "| (.Top * 2)="; (.Top * 2)
                .Height = NewHeight - (.Top * 2)
    Debug.Print "3 | InsideHeight="; Me.InsideHeight; "| NewHeight="; NewHeight; _
                "| Section(acDetail)="; Section(acDetail).Height; _
                "| hauteur ssf avec bordure="; .Height + (.Top * 2); _
                "| ssfAffaires"; .Height; "| (.Top * 2)="; (.Top * 2)
    Debug.Print "----------------------------------"
            End If
            '2- redimensionnement HORIZONTAL ...................................
            NewWidth = Me.InsideWidth
            .Width = NewWidth - (.Left * 2)
            ''End If
            'astuce, pour réduire la largeur du formulaire à
            '   la largeur du contrôle le plus à droite :
            Me.Width = 0
        End With
     
    End Sub
    Note : j'utilise l'autre outil de base, indispensable sous Access pour y voir clair : SmartIndenter de Stephen Bullen (OA Ltd), disponible gratuitement depuis la page Outils
    Il a la particularité se mettre (en option seulement, mais ça me plaît) tous les Debug.? dans la marge, à gauche, et plein d'autres options...
    Et le résultat, copié de la fenêtre d'exécution ou j'ai rajouté le type d'action (ajout ou suppression barre d'outils) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Suppression d'une barre d'outils (formulaire s'aggrandit)
    1 | InsideHeight= 9705 | NewHeight= 7665 | Section(acDetail)= 7275 | hauteur ssf avec bordure= 7275 | ssfAffaires 7161 | (.Top * 2)= 114 
    2 | InsideHeight= 9705 | NewHeight= 7665 | Section(acDetail)= 7665 | hauteur ssf avec bordure= 7275 | ssfAffaires 7161 | (.Top * 2)= 114 
    3 | InsideHeight= 9705 | NewHeight= 7665 | Section(acDetail)= 7665 | hauteur ssf avec bordure= 7665 | ssfAffaires 7551 | (.Top * 2)= 114 
    ----------------------------------
    Ajout d'une barre d'outils (formulaire est réduit)
    1 | InsideHeight= 9315 | NewHeight= 7275 | Section(acDetail)= 7665 | hauteur ssf avec bordure= 7665 | ssfAffaires 7551 | (.Top * 2)= 114 
    2 | InsideHeight= 9315 | NewHeight= 7275 | Section(acDetail)= 7608 | hauteur ssf avec bordure= 7665 | ssfAffaires 7551 | (.Top * 2)= 114 
    3 | InsideHeight= 9315 | NewHeight= 7275 | Section(acDetail)= 7608 | hauteur ssf avec bordure= 7275 | ssfAffaires 7161 | (.Top * 2)= 114 
    ---------------------------------- apparition de l'ascenseur (acDetail trop petite)
    ? 114/2
     57 
    ? 7551 + 57
     7608
    Comme tu le constates, je me suis demandé pourquoi, en réduction, la section détail ne faisait que 7608 twips, et pas 7275 "comme tout le monde" ?
    Lorsqu'on essaye de réduire la section acDetail,
    - elle contient un sous formulaire qui mesure encore 7551 twips (il n'a pas encore été réduit),
    - le ssf démarre à 57 twips (=.Top) du haut de la section.
    Access essaie en fait de le réduire, mais (bon sens ?), il ne peut pas le réduire plus que ce qu'il contient !!!

    Dans l'autre sens, en inversant les 2 lignes comme toi, on constate des choses intéressantes :
    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
            If NewHeight > (.Top * 2) Then
    Debug.Print "1 | InsideHeight="; Me.InsideHeight; "| NewHeight="; NewHeight; _
                "| Section(acDetail)="; Section(acDetail).Height; _
                "| hauteur ssf avec bordure="; .Height + (.Top * 2); _
                "| ssfAffaires"; .Height; "| (.Top * 2)="; (.Top * 2)
                'Toujours imposer la hauteur du Sous Formulaire (contenu)
                '            AVANT la redéfinition de la section le contenant.
                .Height = NewHeight - (.Top * 2)
    Debug.Print "2 | InsideHeight="; Me.InsideHeight; "| NewHeight="; NewHeight; _
                "| Section(acDetail)="; Section(acDetail).Height; _
                "| hauteur ssf avec bordure="; .Height + (.Top * 2); _
                "| ssfAffaires"; .Height; "| (.Top * 2)="; (.Top * 2)
                Me.Section(acDetail).Height = NewHeight
    Debug.Print "3 | InsideHeight="; Me.InsideHeight; "| NewHeight="; NewHeight; _
                "| Section(acDetail)="; Section(acDetail).Height; _
                "| hauteur ssf avec bordure="; .Height + (.Top * 2); _
                "| ssfAffaires"; .Height; "| (.Top * 2)="; (.Top * 2)
    Debug.Print "----------------------------------"
            End If
    Résultat :
    Note : ne pas oublier la gomme, sur la barre d'outils de mzTools, pour nettoyer la fenêtre d'exécution
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Ajout d'une barre d'outils
    1 | InsideHeight= 9315 | NewHeight= 7275 | Section(acDetail)= 7608 | hauteur ssf avec bordure= 7665 | ssfAffaires 7551 | (.Top * 2)= 114 
    2 | InsideHeight= 9315 | NewHeight= 7275 | Section(acDetail)= 7608 | hauteur ssf avec bordure= 7275 | ssfAffaires 7161 | (.Top * 2)= 114 
    3 | InsideHeight= 9315 | NewHeight= 7275 | Section(acDetail)= 7275 | hauteur ssf avec bordure= 7275 | ssfAffaires 7161 | (.Top * 2)= 114 
    ----------------------------------
    Suppression barre
    1 | InsideHeight= 9705 | NewHeight= 7665 | Section(acDetail)= 7275 | hauteur ssf avec bordure= 7275 | ssfAffaires 7161 | (.Top * 2)= 114 
    2 | InsideHeight= 9705 | NewHeight= 7665 | Section(acDetail)= 7608 | hauteur ssf avec bordure= 7665 | ssfAffaires 7551 | (.Top * 2)= 114 
    3 | InsideHeight= 9705 | NewHeight= 7665 | Section(acDetail)= 7665 | hauteur ssf avec bordure= 7665 | ssfAffaires 7551 | (.Top * 2)= 114 
    ----------------------------------
    Cette fois-ci (je suis d'accord, faut être grave pour pinailler comme ça), c'est quand on supprime une barre qu'on constate un hic.
    Sur la ligne 2,
    - On n'a pas encore touché à la section acDetail,
    - on a agrandi le ssf de 7161 à 7551,
    - la section détail a été agrandie (par access) de 7275 à 7608 (soit toujours de quoi contenir le ssf et son .Top, 7608 = 7551 + 57)
    En conclusion,
    - quand on agrandit un contrôle à l'intérieur d'une section, Access agrandit la section pour contenir le tout,
    - quand on essaye de réduire la section, il limite la réduction à la taille des contrôles contenus.


    Maintenant, faut pas rêver en pensant que c'est fini !
    C'est bien fini dans notre cas, mais, si j'ai insisté pour bien comprendre le mécanisme, c'est qu'un jour ou l'autre, tu vas tomber sur d'autres conteneurs de contrôles, qui ne se comporteront peut être pas comme la section acDetail !!!
    Et là, suffira de faire les mêmes tests, comprendre, solution, commentaire.

    Bon, ben on retourne à notre formulaire, dans le cours #03, nouvelle réponse #12.

  10. #10
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut Bug dans CheckTablesConnection()
    Reprenons à partir de l'application 'mise à jour de données', jointe à ta réponse #22 du cours 05.

    Le 1er problème vient du fait qu'on a une monstruosité dans le code de gestion d'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Catch:
    Debug.Print Err, Err.Description
        If Debugging Then
            Resume
        End If
    Déjà, est-ce que tu vois bien ce qui cloche ? Qu'est-ce qu'il va se passer si jamais Debugging est vrai ? Tu peux faire le test
    Ensuite, oublions comment cette énormité est arrivée là, un copier/glisser quelconque ? et reprenons la notion de base avec une La Palissade : les seules erreurs à trouver sont les erreurs non prévues.
    La bonne routine de gestion d'erreurs non prévues, dans notre cas, redevient donc :
    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
    Finally:
        Set db = Nothing
        Exit Sub    '=================================
    Catch:
        Debug.Print Err, Err.Description
        Select Case MsgBox(Err.Description, vbAbortRetryIgnore + vbCritical, Title)
        Case vbAbort
            Resume Finally
        Case vbRetry
            If Debugging Then Stop
            Resume
        Case vbIgnore
            Resume Next
        End Select
    End Sub
    - J'inclus le Finally: dedans, parce qu'il est utile à de très nombreuses routines, comme on l'a déjà vu. Ici, pour fermer l'objet db proprement. Mais, tant qu'à faire, il manque aussi 'td' et 'ConnectTest'...
    Je répète lourdement le but : on ne peut pas quitter cette routine sans passer par le Finally:, même (et surtout) s'il y a une erreur non prévue.
    - le Debug.? sera utile pour nous, pour retrouver le n° et description d'erreur pendant et surtout après le débogage, quand on en sera à la gestion d'erreur connue (identifiée, déboguée, à traiter).

    - les 3 choix sont utiles pour un utilisateur en face d'une erreur non prévue. Il peut :
    1- parfois, corriger l'erreur : il faut introduire une disquette ou clé USB, ou se reconnecter au réseau... Ensuite, il clique sur Réessayer et ça devrait marcher.
    2- sinon, il clique sur Ignorer. Ça peut surprendre, mais dans bon nombre de cas, ça marche quand même.
    3- si la 1ère erreur en déclenche d'autres, comme une 'variable objet non définie'..., il clique sur Annuler. Puis il recommence le tout.

    - Enfin, le Stop va nous permettre, si Debugging est vrai (à faire dans appInit() et dans la fenêtre d'exécution : ThisApp.debugging = True) de cliquer sur Réessayer > l'exécution s'arrête au Stop > on reprend avec F8 qui va faire un Resume > on continue en pas à pas, toujours avec F8...
    À partir de là, faut se creuser le ciboulot pour bien comprendre
    - comment marche ce code ?
    - qu'est-ce qui cloche ?
    Déjà, tu as vu qu'il faut être très rigoureux avec tes tests et les méthodes de débogage d'une routine écrite par toi.
    Mais c'est beaucoup plus drôle de déboguer quelque chose qui a été écrit par quelqu'un d'autre
    Et si j'en juge par la constante mauvaise humeur des développeurs qui reprennent un code "bidouillé par je ne sais quel tocard-nulard", ça arrive tout le temps.
    Donc, c'est ton tour de me déboguer, pendant que je vais boire l'apéro.

    Je ne m'attends pas à ce que tu cherches des jours et des jours, pour apporter la solution toute crue. N'hésite pas à expliquer ce que tu as fait, les difficultés, ce que tu ne comprends pas... On va chercher ensemble (après l'apéro).

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Je ne m'attends pas à ce que tu cherches des jours et des jours, pour apporter la solution toute crue. N'hésite pas à expliquer ce que tu as fait, les difficultés, ce que tu ne comprends pas... On va chercher ensemble (après l'apéro).
    Donc j’explique MA démarche.
    La ‘reconnections’ des tables utilisent les variables « OldBase » et « NewBase »
    Dans la ‘sub Reconnect’ la variable « OldPathName » me semble bien formaté (chemin + nom) alors que la variable « NewPathName » il manque le nom du fichier. Bonne approche ???

    On va chercher ensemble (après l'apéro).
    l’apéro est fini (4 jours d’apéro c’est pas mal !!!). Mille escuses pour les retards, mais beaucoup de charge et voyage ….

  12. #12
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    Bonne approche ?
    - Tu n'es peut être pas loin, mais je ne sais pas si tu as la bonne méthode.
    En tout cas, tu n'es pas sûr de toi, donc il manque quelque chose.
    Sur la méthode :
    - tu examines ta routine, si les variables font bien leur boulot...
    Tu risques d'y passer des heures et des jours, à revérifier chaque variable, chaque algorythme, chaque calcul...

    Pour l'instant, ce que je cherche en premier, c'est : "quelle est la ligne qui provoque une erreur # ???, message "le nom de fichier est incorrect".
    Le n° d'erreur est généralement important. C'est par là qu'on l'identifie et qu'on va la traiter, si besoin.

    Donc,
    - si tu as bien suivi les corrections indiquées plus haut,
    tu dois pouvoir
    - relancer le programme,
    - obtenir l'erreur,
    - noter son n° et son message (merci, Debug.?)
    - t'arrêter sur la ligne : - Resume te ramène effectivement sur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Reconnect OldBase, NewBase
    À partir de là, faut trouver la ligne "qui plante", seul moyen d'être sûr que le problème est bien là.

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Donc,
    - si tu as bien suivi les corrections indiquées plus haut,
    tu dois pouvoir
    - relancer le programme,
    - obtenir l'erreur,
    - noter son n° et son message (merci, Debug.?)
    - t'arrêter sur la ligne :
    Numéro de l’erreur est 3055 ‘ Nom de Fichier incorrect’

    La ligne qui pose problème se trouve dans la ‘Sub Reconnect ….’
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    If InStr(.Connect, OldPathName) > 0 Then
       .Connect = JET_PREFIX & NewPathName
       .RefreshLink
    End If
    La variable 'NewParhName' a bien le nouveau répertoire mais pas le nom du fichier .

    Donc pour corriger: ancien code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Reconnect OldBase, NewBase
    Nouveau code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Reconnect OldBase, NewBase & FileName
    Des tests …. Et ça marche !!!!

  14. #14
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    Ben, bravo !
    Tu as
    - trouvé la ligne qui plante,
    - du coup, tu es sûr du problème à résoudre,
    et tu as la solution sans trop de difficulté.

    Mais, ce qui m'intéresse, plus encore que la solution, c'est la méthode.
    Autrement dit, comment tu as fait pour t'arrêter sur la ligne qui plante, bien qu'elle soit dans une routine qui n'a aucun contrôle d'erreur (pas de On Error Goto ...), laquelle est appelée par une routine qui en a... ?

    On est là pour connaître à fond tous les outils de débogage.
    Autrement dit, savoir où se trouvent les interrupteurs qui permettent d'allumer et de ne pas rater une marche quand on descend à la cave fouiller dans le charbon..., si tu vois ce que je veux dire.

    Donc, n'hésite pas à raconter les marches ratées, les outils, les options, les paramètres que tu as changés pour y arriver.

  15. #15
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Mais, ce qui m'intéresse, plus encore que la solution, c'est la méthode
    Pour trouver le numéro et le type d’erreur:

    1- dans l’éditeur VBA, menu ‘Options’ - ‘Général’ – ‘Récupération de erreurs’ – coché la case ‘Arrêt sur toutes les erreurs’
    2- Relancer l’application.
    3- Retourne l’erreur 3044 (chemin non valide pour le fichier) sur la ligne ‘Set ConnectTest = db.OpenRecordset(td.Name)’
    4- Remettre dans l’éditeur VBA ‘Arrêt sur les erreures non gérées’
    5- Relancer l’application‘
    6- Dérouler la routine pas à pas « touche F8 », lors du choix du fichier et de l’essai de reconnections (Reconnect OldBase, NewBase), dans la variable ‘NewBase’, le chemin est bien formaté, mais il manque le nom du fichier.
    7- Conclusion ‘Reconnect OldBase, NewBase & Filename’


    Dure d’expliquer la démarche !!

  16. #16
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut [Travaux pratiques] et notions de base sur la gestion d'erreurs
    Citation Envoyé par Serge57
    Dure d’expliquer la démarche !!
    Je veux bien te croire
    Ta démarche est bonne, puisque tu as trouvé. Mais j'ai insisté parce que mon petit doigt me disait que tu avais eu du mal à trouver ça, et donc, que quelques concepts de base n'étaient pas encore tout à fait clairs.
    Voici ma démarche, quasi identique, pour trouver la ligne qui donne l'erreur :
    1- déjà exposé en détail, arrêt, dans notre code de gestion d'erreur, sur le Stop,
    2- F8 sur le Resume, ce qui me ramène sur la ligne Reconnect OldBase, NewBase
    3- toujours F8 pour entrer dans la Sub Reconnect(...)
    4- Pause : dès que je constate que cette Sub n'a aucun contrôle d'erreur (pas de 'On Error Goto ...'), c'est que j'ouvre le menu Outils > Options > Général pour choisir Arrêt sur toutes les erreurs,
    5- puis, pour gagner du temps, F5 (exécution complète)
    6- l'exécution s'arrête sur .RefreshLink, avec le message d'erreur 'Nom de fichier incorrect' > clic sur débogage.
    À partir de là, le problème est quasiment résolu : je suis sur l'erreur proprement dite, RefreshLink plante, donc le nouveau chemin + nom de fichier ne doit pas être correct...

    Maintenant, tâchons de clarifier tout cela :
    - quand utilise t'on Arrêt sur erreurs non gérées ou bien Arrêt sur toutes les erreurs ?
    - À quoi peut bien servir l'option Arrêt dans le module de classe ?

    Il y a quelques notions de base que les 2 exercices ci-dessous, et les centaines de variations que je te conseille de pousser plus loin (ajouter plusieurs routines qui s'appellent l'une l'autre, sur plus de niveaux ; mettre du contrôle d'erreur à des niveaux variables ; etc.) doivent rendre absolument évidentes pour tout développeur :
    L'ensemble de notre code se divise en 2 catégories : erreurs gérées ou erreurs non gérées.
    Le code avec erreurs gérées
    - commence avec un 'On Error Goto ...' ou bien 'On Error Resume Next'
    - se termine avec un 'On Error Goto 0', ou bien avec la fin de la routine (End/Exit Sub/Function...)
    - inclut tout le code contenu dans les subroutines appelées, à condition qu'il n'y ait pas d'autre gestion d'erreur dans la routine appelée. Sinon, c'est cette gestion d'erreur locale qui prend le pas, jusqu'à ce qu'on remonte à l'appelant ou qu'on rencotre un 'On Error Goto 0'.

    Tant qu'aucune erreur n'est gérée, c'est facile pour nous : l'exécution s'arrête en affichant la boîte avec les options 'fin / débogage', ce qui nous permet de corriger (ou gérer) l'erreur.
    Si une erreur se produit
    - dans un bloc avec gestion d'erreur : l'exécution continue là où nous l'avons spécifié avec le On Error...,
    - dans un bloc sans gestion d'erreur,
    --- soit la routine où se produit l'erreur est appelée depuis une autre -> VBA va 'remonter' jusqu'à la gestion d'erreur spécifiée dans l'appelant.
    --- soit la routine n'est appelée par aucune autre : l'exécution s'arrête en affichant la boîte avec les options 'fin / débogage'.
    --- soit il n'y a aucune gestion d'erreur à aucun niveau : l'exécution s'arrête également, au niveau d'appel le plus bas, sur la ligne qui a provoqué l'erreur, en affichant la boîte avec les options 'fin / débogage'.


    Exercices : lancer chaque exercice en cliquant dans le code + F5.
    Routine simple, pas de contrôle d'erreur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     Public Sub TestLevel0()
        Debug.Print "Level 0 - Instruction 1"
        Error 16
        Debug.Print "Level 0 - Instruction 2"
    End Sub
    Tester avec les 3 options :
    Arrêt sur :
    - toutes les erreurs
    - dans module de classe
    - erreurs non gérées
    Ici, quelle que soit l'option, l'exécution s'arrête sur la ligne d'erreur et affiche la boîte avec les options 'fin / débogage'.

    Routine simple, avec contrôle d'erreur
    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
     Public Sub TestLevel0()
        On Error GoTo Catch
        Debug.Print "Level 0 - Instruction 1"
        Error 16
        Debug.Print "Level 0 - Instruction 2"
    Finally:
        Exit Sub    '======================
    Catch:
        Debug.Print Err; Err.Description
        Select Case MsgBox(Err.Number & " - " & Err.Description, vbAbortRetryIgnore, "Tests contrôle d'erreur")
        Case vbAbort
            Resume Finally
        Case vbRetry
            Resume
        Case Else   ' = vbIgnore
            Resume Next
        End Select
    End Function
    TEST. Arrêt sur :
    - toutes les erreurs : boîte de débogage (Fin/débogage), impossible de continuer avec F8
    - dans module de classe : pas d'arrêt, contrôle d'erreur actif -> notre MsgBox s'affiche
    - erreurs non gérées : idem module de classe.

    2 niveaux de routines, contrôle d'erreur au niveau appelant (niveau 0) :
    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
     Public Sub TestLevel0()
        On Error GoTo Catch
        Debug.Print "Level 0 - Instruction 1"
        Testlevel1
        Debug.Print "Level 0 - Instruction 2"
    Finally:
        Exit Sub    '======================
    Catch:
        Debug.Print Err; Err.Description
        Select Case MsgBox(Err.Number & " - " & Err.Description, vbAbortRetryIgnore, "Tests contrôle d'erreur")
        Case vbAbort
             Resume Finally
        Case vbRetry
             Resume
        Case Else   ' = vbIgnore
             Resume Next
        End Select
    End Function
    '---------------------------
    Sub Testlevel1()
        Debug.Print "Level 1 - Instruction 1"
        Error 16
        Debug.Print "Level 1 - Instruction 2"
    End Sub
    TEST. Arrêt sur :
    - toutes les erreurs : arrêt dans TestLevel1, sur l'erreur
    impossible d'aller + loin avec F8
    - dans module de classe : pas d'arrêt, contrôle d'erreur actif au niveau 0 -> notre MsgBox s'affiche
    L'instruction : Debug.Print "Level 1 - Instruction 2" ne sera jamais exécutée.
    - erreurs non gérées : idem module de classe.
    Refaire le même, sans aucune gestion d'erreur, seulement au niveau bas...

    Appel d'une méthode, dans un module de classe
    Toujours dans Module1, l'appelant devient :
    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
     Public Function TestLevel0()
    Dim Object1 As Classe1
     
        On Error GoTo Catch
        Debug.Print "Level 0 - Instruction 1"
        Set Object1 = New Classe1
        Object1.Method1
        Debug.Print "Level 0 - Instruction 2"
    Finally:
        Exit Function    '======================
    Catch:
        Debug.Print Err; Err.Description
        Select Case MsgBox(Err.Number & " - " & Err.Description, vbAbortRetryIgnore, "Tests contrôle d'erreur")
        Case vbAbort
             Resume Finally
        Case vbRetry
             Resume
        Case Else   ' = vbIgnore
             Resume Next
        End Select
    End Function
    Dans le module de classe Classe1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     Public Sub Method1()
        Debug.Print "Class module - Instruction 1"
        Error 16
        Debug.Print "Class module - Instruction 2"
    End Sub
    TEST. Arrêt sur :
    - toutes les erreurs :
    arrêt dans Method1, sur l'erreur
    impossible d'aller + loin avec F8
    - dans module de classe :
    idem toutes les erreurs : l'exécution s'arrête directement sur l'erreur.
    - erreurs non gérées :
    pas d'arrêt, contrôle d'erreur actif -> notre MsgBox s'affiche
    L'instruction : Debug.Print "Class module - Instruction 2" ne sera jamais exécutée.

    Quel est l'intérêt de cette distinction ? Pourquoi s'arrêter spécifiquement dans les modules de classe et non pas dans les modules standards ???
    Il m'a fallu quelques années pour y comprendre quelque chose.
    Pour cela, il faut penser à la réutilisation du code.
    Je vais simplifier bien sûr, en répondant à la question : Quand utilise t'on des modules de classe ? et en ne donnant que 2 réponses :
    1- pour créer des objets métier : ces objets peuvent être réutilisés dans plusieurs applications complémentaires les unes des autres.
    2- pour se constituer une bibliothèque (Library) de code réutilisable dans toutes (ou au moins dans plusieurs) de nos applications.
    Le 2ème cas est plus subtil, parce qu'il n'y aura pas QUE des modules de classe dans une librairie complète. Il y aura des modules de classe et des routines simples, dans des modules standards.

    Exemple :
    Nous avons déjà 2 applications en chantier : SuiviAffaires (l'application principale) + SuiviAffaire_MàJ (mise à jour de la BDD).
    Admettons que nous voulions réutiliser, dans SuiviAffaires, le mécanisme qui permet à SuiviAffaire_MàJ
    - de vérifier si les tables sont bien attachées
    et, en cas d'erreur,
    - d'ouvrir la boîte de dialogue pour que l'utilisateur puisse indiquer l'emplacement de la base,
    puis,
    - reconnecter automatiquement toutes nos tables.
    nous allons avoir besoin de :
    - 2 classes : clApplication + clLog
    - au moins notre module 'APIsWindows', qui contient OuvrirFichierSpécifique()...
    - peut être d'autres Subs et Fonctions utilisées 2 fois ?

    Plutôt que de copier ces modules d'une application à l'autre, je conseillerais fortement de:
    - créer une base de données indépendante, par exemple Librairie.mdb
    - d'y copier (ou importer) les modules concernés.
    Puis, dans chacune des 2 applications (et au delà, dans toutes tes futures applications),
    - ajouter une simple référence à Librairie.mdb (dans VBA, menu Outils > Références)

    À moyen et long terme, les avantages sont considérables : un seul code à corriger et/où compléter, réutilisable partout.
    + le fait que la librairie peut être compilée en une Librairie.mde, donc code sécurisé
    L'inconvénient par contre : il n'est pas très pratique de déboguer un code dans une librairie partagée, même si c'est possible (pas dans un .mde).
    Notre cas est typique : nous avons trouvé une erreur dans une méthode (CheckConnections) appartenant à un des objets qu'on souhaiterait réutiliser ailleurs.
    Il faut donc impérativement
    1- utiliser et déboguer complètement cette partie du code, tant qu'elle est incluse directement dans la 1ère application. C'est + facile, c'est ce que nous sommes en train de faire avec la classe clApplication, et c'est pour cette raison que nous avons du code de gestion d'erreur. Ça nous permet de nous arrêter et de corriger ou compléter cette méthode, ainsi que les routines comme Reconnect, qu'elle appelle.
    2- une fois qu'elle aura été correctement déboguée, nous allons la déplacer dans la librairie partagée, pour pouvoir la réutiliser.

    Et c'est là, ou peut être déjà depuis un bon 1/4 d'heure ? que tu vas me dire : quel rapport avec notre contrôle d'erreur et les options d'arrêt ???
    J'y arrive : tout cet exposé pour bien comprendre le principe suivant :
    Tout le code de notre application est contenu dans des routines qui s'appellent les unes les autres.
    Tout déclenchement de code part toujours
    - soit de la fonction de démarrage App_Init(),
    - soit d'un évènement de l'interface utilisateur : clic sur un bouton, lancement d'une commande dans un menu spécifique, saisie d'une valeur dans un contrôle...
    Les propriétés et les méthodes de nos objets (modules de classe), de même que tout ce que nous mettrons dans une librairie réutilisable, ne seront jamais appelés en direct, mais toujours à partir d'une des routines ci-dessus, déclenchée depuis l'interface.
    Par rapport aux tests ci dessus, elles ne seront jamais au niveau 0.

    Lorsque nous allons terminer notre application pour la distribuer à d'autres utilisateurs, nous allons
    1- mettre du code de contrôle d'erreur à toutes les routines au niveau de l'interface utilisateur (dans tous les évènement de tous les formulaires et/ou de tous les états et de leurs contrôles) + dans la fonction de démarrage App_Init().
    Grâce à ce contrôle d'erreur, nous sommes assurés que les utilisateurs de notre application :
    - ne verront jamais la boîte de dialogue avec options Débogage/Fin (ils ne sont pas censés rentrer dans le code pour déboguer)
    - que notre contrôle d'erreurs non prévues sera toujours actif, avec ses 3 options : Annuler/Réessayer/Ignorer
    - de +, si nous avons prévu d'enregistrer l'erreur dans un journal, toute erreur non prévue y sera bien enregistrée (ce qui nous sera beaucoup plus utile que les indications usuelles des utilisateurs qui ne retiennent jamais les messages d'erreur... )
    Même si l'erreur se produit dans une sub-sub-sub...routine, à n'importe quel niveau, elle sera contrôlée, affichée, enregistrée.

    2- à l'inverse, nous n'allons mettre aucun code de contrôle d'erreur dans notre librairie. Ou disons, le strict minimum.
    Et pareil dans nos objets métier.
    Ceci est volontaire.
    Lorsqu'on appelle une commande de VBA, par exemple FileCopy et qu'une erreur se produit ("File not found", par exemple), l'erreur n'est pas gérée à l'intérieur de la commande FileCopy. Elle nous est renvoyée au niveau de notre application, pour que nous puisssions la traiter sur place et afficher les messages clairs à notre utilisateur ("Impossible de trouver le fichier Clients", par exemple).
    Nous devons, après les avoir correctement déboguées, considérer nos routines, encapsulées dans notre librairie, comme un complément de VBA, une surcouche du langage.
    Nos commandes de librairie (par exemple ThisApp.CheckTablesConnection) doivent être utilisées comme si elles faisaient partie d'une version étendue d'Access ou de VBA. Nous n'avons fait qu'ajouter une méthode personalisée à l'objet Application d'Access.
    Elles ne devraient pas afficher un message à l'utilisateur : c'est le programmeur de chaque application qui va
    - capturer l'erreur au niveau de l'appel,
    - personaliser chaque message dans la langue de l'utilisateur, et en fonction du contexte de chaque application.
    Elles vont donc se contenter de renvoyer les erreurs au niveau appelant : à l'application qui utilise la librairie.

    Et voilà la seule explication que je puisse trouver pour justifier la présence de l'option "Arrêt dans les modules de classe" qui sont, par définition, réutilisables et ne gèrent normalement pas les erreurs non prévues.
    Bien entendu, il y a des exceptions
    Regardons en une, que nous utilisons déjà, la fonction CopyFile().
    Comme par hasard, l'original provient de ma librairie usuelle : je l'utilise partout, à la place de la commande VBA FileCopy()
    Lorsqu'elle aura été incluse dans une librairie, CopyFile() permettra, comme ici,
    - de contrôler que la source est bien différente de la destination. Note qu'elle n'affiche pas de message d'erreur : elle le renvoit avec un Err.Raise. Le programmeur de l'application principale pourra afficher ou non le message, ou gérer l'erreur dans son On Error Goto...
    - de gérer le fait que le fichier de destination peut déjà exister : faut-il le supprimer ou l'écraser, avec message ou sans rien dire...
    Là, je suppose que tu as remarqué un petit hic : la routine affiche éventuellement un message. Idéalement, il faudrait que le programmeur de chaque application puisse modifier ce message grâce à un des arguments d'appel de CopyFile().
    Si d'autres erreurs non prévues se produisent, elles déclencheront le contrôle d'erreur de l'application principale qui pourra les gérer comme s'il s'agissait d'une erreur dans une commande VBA.

    Voili voilou. Si ces notions sont parfaitement claires :
    - distinction entre code avec ou sans gestion d'erreur,
    - niveaux d'appels de code entre les diverses routines,
    - comment VBA 'remonte' en cas d'erreur 'en bas', jusqu'à ce qu'il trouve une gestion d'erreur,
    - faut-il gérer les erreurs non prévues et est-il préférable de ne pas gérer les erreurs non prévues ?
    tu es à 2 doigts de créer des applications solides, que tu pourras déboguer rapidement, au fur et à mesure que les tests (préliminaires, beta tests ou déploiement réel) révèlent des erreurs non prévues.

  17. #17
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Voili voilou. Si ces notions sont parfaitement claires : …. tu es à 2 doigts de créer des applications solides, que tu pourras déboguer rapidement, au fur et à mesure que les tests (préliminaires, beta tests ou déploiement réel) révèlent des erreurs non prévues.
    J’ai fait beaucoup d’essais, et je pense avoir compris le principe, mais pour le mettre en pratique on va voir !!

    Deux petites remarques (ou éclaircissement)
    Pas compris la différence entre un module de classe et un module ‘normal’ !!!

    Citation Envoyé par Papy Turbo
    - créer une base de données indépendante, par exemple Librairie.mdb
    Lors de la distribution de l’application, il faudra joindre la librairie ???

  18. #18
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    Citation Envoyé par Serge57
    Pas compris la différence entre un module de classe et un module ‘normal’ !!!
    Réponse tellement évidente (dès que tu auras utilisé quelques modules de classe), que ça va pas être facile
    Essayons un petit résumé :

    Module standard :
    - contient des variables Public ou Privées (avec Dim...)
    - contient des procédures Sub et Function, qui peuvent être Public, donc appelées depuis n'importe quel autre module, ou Private, donc utilisables seulement à partir d'une autre procédure du même module.

    Module de classe :
    (voir cours 05-Mise à jour BDD, les classes clApplication et clLog)
    - permet de créer un 'objet', doté de propriétés (=variables qui appartiennent à l'objet) et de méthodes (procédures qui appartiennent à l'objet).
    - les propriétés utilisent des Property Get et Property Let, (Voir Get/Let Name dans clLog) pour lire ou modifier la propriété.
    Raccourci : une variable publique dans le module de classe - voir Public Title as String, dans clApplication - n'a pas besoin des Property Letou Get.

    La valeur de la propriété est stockée dans une variable (mName ou Title, dans les exemples), à l'intérieur de l'objet.
    - les méthodes sont des Sub (qui ne renvoient rien) et des Function (qui peuvent renvoyer une valeur), comme dans un module standard.
    - les propriétés et les méthodes sont Public ou Private, comme dans un module standard.
    Note : Les librairies externes utilisent aussi des procédures Friend. Celles-ci sont 'publiques' dans toute la librairie elle-même, mais sont invisibles à l'application qui fait référence à cette librairie. On en reparlera peut être...

    L'utilisation d'un objet est différente de celle des variables et procédures standard :
    - tu dois d'abord créer une variable objet, du type de ta classe.
    1- Déclaration de la variable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Public ThisApp As clApplication
    suivi de 2- Création de l'objet, qui est une instance (=une copie en mémoire) de la classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Set ThisApp = New clApplication
    L'utilisation, la modification d'une propriété ou d'une méthode se fait toujours en passant par le nom de la variable objet, suivi d'un point et de la propriété ou de la méthode.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MsgBox ThisApp.Title
    ThisApp.Debugging = True
    Les utilisations multiples peuvent être imbriqués dans un With... End With
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    With ThisApp
        MsgBox .Title
        .Debugging = True
    End With
    - les classes ont en plus 2 "évènements" : Initialize et Terminate, qui permettent de donner des valeurs initiales aux propriétés (Voir clApplication > Class_Initialize qui crée le titre de l'application), ou de les fermer proprement lors de la destruction de l'objet.
    - Attention : un objet peut en cacher un autre, ce qui fait toute la puissance des objets. Voir notre clApplication qui contient un objet Log As clLog.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ThisApp.Log.Name = "SuiviAffaires_MiseAJourBDD"
    Voir surtout, dans l'aide d'Access > Microsoft DAO 3.60 > Références des objets DAO > Modèle d'objet DAO pour espace de travail Microsoft Jet. Tu y trouveras un exemple complexe qui contient des objets et collections très familiers : Databases > recordsets > fields...

    Enfin, les objets peuvent être contenus dans des collections (voir exemple DAO ci-dessus, ou collection Forms() qui contient des objets Form...).
    Si nous avions besoin de plusieurs journaux dans notre moteur de mise à jour, nous aurions pu doter notre classe clApplication d'une collection de journaux, utilisables comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ThisApp.Logs.Item(0).Name = "Journal d'erreurs - SuiviAffaires"
    ThisApp.Logs.Item(1).Name = "Journal de mise à jour de la base V1"
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ThisApp.Logs.Item("Journal d'erreurs - SuiviAffaires").Append Err.description
    À chaque fois que tu tapes un point dans le code (Docmd.Maximize), tu utilises une propriété ou une méthode d'un objet. La liste des propriétés et méthodes est affichée par la fonction intellisense de l'éditeur de code...

    Citation Envoyé par Serge57
    Lors de la distribution de l’application, il faudra joindre la librairie ???
    Oui, et ça ne pose aucun problème si les 2 "bases .mdb" (l'application qui utilise la librairie + la librairie elle-même) sont copiées dans un seul répertoire : dès le premier lancement de l'application, Access rétablit la liaison (référence) avec la librairie
    Lors de modifications ultérieures de ton application, tu n'as plus besoin de distribuer la librairie (sauf si elle a été modifée aussi, oeuf corse).

    Voilà, si tout ça est bien clair (et y a intérêt ), je te propose de terminer notre application de mise à jour des bases en
    1- supprimant d'abord tout code d'erreur, sauf code de traitement d'une erreur spécifique, bien sûr. Ceci afin de repartir sur une base simple et claire.
    2- d'extraire vers une librairie ce que nous pourrons réutiliser ailleurs. Par exemple, nos classes clApplication et clLog, pour que l'application principale soit elle aussi dotée d'un journal d'erreurs.
    3- de choisir où nous allons mettre du code de contrôle d'erreur, et utiliser le générateur de mzTools pour 'blinder' nos 2 applications contre toute erreur imprévue.

    Donc, sauf questions ici que nous continuerons en //, prochain exercice :
    - reprendre la suite du cours 05, en supprimant tout code d'erreur non indispensable.

  19. #19
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    79
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 79
    Par défaut
    Citation Envoyé par Papy Turbo
    Voilà, si tout ça est bien clair (et y a intérêt ), je te propose de terminer notre application de mise à jour des bases...
    Vache, vache…. Je pensais avoir tout compris mais je rame un peu …


    1- supprimant d'abord tout code d'erreur, sauf code de traitement d'une erreur spécifique, bien sûr. Ceci afin de repartir sur une base simple et claire.
    Dans toutes les subroutines et fonctions du modules ClApplication et SpecificTransferRoutines. (mais il faut les pièger dans les sub appelantes !! )


    2- d'extraire vers une librairie ce que nous pourrons réutiliser ailleurs. Par exemple, nos classes clApplication et clLog, pour que l'application principale soit elle aussi dotée d'un journal d'erreurs.
    J’ai essayé, Mais code erreur dans variable « Public ThisApp As clApplication » variable non référence !! Pas tout compris vu que la librairie est raccrochée à l’application.

    3- de choisir où nous allons mettre du code de contrôle d'erreur, et utiliser le générateur de mzTools pour 'blinder' nos 2 applications contre toute erreur imprévue.
    N’étant pas un VRAI développeur, je ne sais pas l’utiliser.

    Nota : beaucoup de retard dans mes réponses,parce que ça ce complique(je m’accroche), que je ne comprend pas tout du premier coups et que j’ai un métier qui me sature en ce moment. (semaine 23 et semaine 24 pas là, en déplacement)

  20. #20
    Membre Expert
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Par défaut
    Bonjour, Serge,
    je vois que l'enthousiasme et la bonne humeur sont toujours là .
    Ça fait bien plaisir.
    Et puis, tant qu'il fait beau, on a le moral au top, non ?
    Citation Envoyé par Serge57
    Vache, vache…. Je pensais avoir tout compris mais je rame un peu …
    Je ne te cache pas que les exercices que tu t'offres ici (et que j'encourage vivement tous les lecteurs à faire, sauf si leur but est simplement de connaître quelques termes techniques pour briller en comité de coordination ?!? Hint : pour ça, Wikipedia, ça va plus vite) sont nettement d'ordre didactique, sans grand intérêt pratique pour notre application, dans l'immédiat : tu vas enlever tout code de traitement des erreurs non prévues, en conservant juste le traitement des erreurs spécifiques.
    Plus tard, (étape 3.), nous remettrons notre traitement d'erreurs non prévues (là où il faut, et pas plus).

    Le but est de bien distinguer les deux : dans la pratique, beaucoup mélangent allègrement le traitement des erreurs non prévues et celui des erreurs spécifiques, ce qui amène à des capharnaüms pas faciles à démêler ensuite...

    Donc, étape 1 : juste produire une appli qui, en cas d'erreur non prévue, ouvre la boîte de dialogue d'Access : Erreur... choix -> Déboguer ? ou Fin ?
    Citation Envoyé par Serge57
    Dans toutes les subroutines et fonctions du modules ClApplication et SpecificTransferRoutines. (mais il faut les pièger dans les sub appelantes !! )
    Chaque chose en son temps : on fera ça à l'étape 3, sur une base "propre".
    Citation Envoyé par Serge57
    J’ai essayé, Mais code erreur dans variable « Public ThisApp As clApplication » variable non référence !! Pas tout compris vu que la librairie est raccrochée à l’application.
    Pige pas Tu as déjà démarré l'étape 2 et séparé la librairie du reste ?
    C'est un peu prématuré, et je comprends que tu satures.
    Encore une fois, Che va piano va sano, étape par étape.
    Citation Envoyé par Serge57
    N’étant pas un VRAI développeur, je ne sais pas l’utiliser.
    1- un Pro, par définition, c'est quelqu'un qui gagne principalement sa vie en développant. D'accord, ce n'est pas ton cas, comme tant d'autres sous Access. Mais un VRAI, c'est quoi ?
    2- avec les exercices que tu fais depuis quelques mois, j'ai le sentiment que tu vas, d'ici à l'année prochaine, nous pondre des applications qui seront beaucoup beaucoup plus "propres" (structure d'appels, contrôle d'erreur, commentaires...), mieux structurées (portée des variables, modules spécifiques/génériques, classes...), plus efficaces (optimisation, ergonomie, réutilisation de code...) que le plupart de celles, dites "professionnelles", sur lesquelles je tombe ici et là
    Citation Envoyé par Serge57
    Nota : beaucoup de retard dans mes réponses,parce que ça ce complique(je m’accroche), que je ne comprend pas tout du premier coups et que j’ai un métier qui me sature en ce moment. (semaine 23 et semaine 24 pas là, en déplacement)
    Ce sont les aléas de ces cours en ligne. J'en suis exactement au même point (je serai à Caen, la semaine 23 - mais rien à voir avec les 60 ans de D-Day), donc, tout va bien.

    Je préfère, au contraire, qu'on s'offre le luxe de prendre le temps (revoir la récré sur débogage et méthode de test, plus haut), pour bien éclaircir les quelques principes de base (y en a pas tellement).
    Et rien ne vaut la pratique : exercices, exercices, exercices...

    Donc, dès que tu as fait ton nettoyage (étape 1), avec quelques tests pour que ça compile et que ça marche quand même, tu le mets en pièce jointe et on revoit ça.

Discussions similaires

  1. [Lazarus] Cours complet sur les bases de la programmation, par Eric Thirion
    Par Alcatîz dans le forum Lazarus
    Réponses: 8
    Dernier message: 10/05/2014, 17h29
  2. Réponses: 0
    Dernier message: 05/01/2014, 13h59
  3. [Cours pt-03]turbo-formulaire (les bases)
    Par Papy Turbo dans le forum Sondages et Débats
    Réponses: 29
    Dernier message: 29/10/2007, 18h56
  4. Cherche bon cours sur les bases de données
    Par SOPSOU dans le forum Bases de données
    Réponses: 2
    Dernier message: 07/09/2007, 14h56

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