Formulaires gigognes

Un moyen pour présenter les détails d'une structure avec Access

Ce tutoriel propose un moyen de présenter le détail d'une arborescence.

En quelque sorte, des formulaires qui s'emboitent l'un dans l'autre : chacun affichant les éléments qui dépendent de l'enregistrement actif dans le formulaire à sa gauche.

Une technique qui permet de contourner la limite qui veut qu'un formulaire « père » ne peut avoir de « fils » que s'il est affiché en « mode simple » (un enregistrement à la fois).

L'occasion d'exploiter cette contribution d'Arkham46 qui permet d'ouvrir un formulaire à un endroit déterminé par la position d'un contrôle dans un autre formulaire.

Nous proposerons aussi une routine qui ajuste la taille d'un formulaire en « Mode continu » au nombre de ses enregistrements.

Si vous souhaitez réagir à cet article, une discussion est ouverte dans le forum :Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. « Des formulaires gigognes » : de quoi s'agit-il ?

Imaginez une structure (hexagonale ?) dans laquelle il y aurait des régions, des départements et des communes :

Image non disponible
Image non disponible

L'idée est de présenter cette structure avec des formulaires qui s'ouvrent en cascade et s'emboitent l'un dans l'autre… comme des tables gigognes :

Image non disponible

Ce que nous appelons « formulaire mère gigogne », c'est un formulaire affiché en mode continu dans lequel chaque enregistrement activé provoque l'ouverture instantanée à sa droite d'un autre formulaire juste à la hauteur de l'enregistrement actif.

À l'ouverture :

Image non disponible

et si on navigue dans l'un des formulaires, ceux à sa droite s'adaptent instantanément :

Image non disponible

II. Le nœud de la solution : la routine PositionForm()

Cette routine est proposée à cette adresse par Arkham46.

Même si vous ne comprenez pas à quoi servent toutes les API auxquelles il fait appel dans son code, faites confiance : ça marche au poil !

Il suffit de copier le code proposé dans un module (dans notre base exemple, c'est le module mArkham46).

Image non disponible

Et pour l'utiliser, deux lignes de code :

 
Sélectionnez
DoCmd.OpenForm "FormulaireAPositionner", , , , , acHidden
PositionForm Forms("FormulaireAPositionner"), Me.UneZoneDeTexte

Deux précautions :

  • le formulaire à ouvrir doit être en fenêtre indépendante :
Image non disponible
  • en cas d'appels successifs, refermez d'abord le formulaire précédemment ouvert avant de l'ouvrir une nouvelle fois.

III. Les particularités des formulaires

Image non disponible

Image non disponible L'en-tête s'adapte pour afficher le texte de l'enregistrement actif dans le formulaire mère gigogne.

Image non disponible L'enregistrement actif s'affiche dans une couleur distincte.

Image non disponible Le pied du formulaire s'affiche au raz du dernier enregistrement.

Image non disponible La hauteur du formulaire s'adapte au nombre d'enregistrements à afficher.

Image non disponible La source contient toute la table des départements, nous monterons plus loin comment passer le filtre qui limitera la liste aux départements de cette région.

Image non disponible Fenêtre indépendante, routine PositionForm() oblige !

Image non disponible Pas de possibilité de fermer ni déplacer : c'est le 1er formulaire de la cascade qui commande l'ouverture , la fermeture et la position de l'ensemble.

Image non disponible

Image non disponible Une étiquette, à l'origine vierge, que nous complèterons à la volée dans l'événement ouverture du formulaire.

Image non disponible Une zone de texte visible, mais non perceptible par l'utilisateur (hauteur = 0 !). Elle sera aménagée à chaque lecture d'enregistrement, pour déclencher la mise en forme conditionnelle (changement de couleur pour mettre l'enregistrement actif en évidence).
Accessoirement, ce contrôle qui est le seul avec « Arrêt sur tabulation » servira de piège à focus : on évite ainsi que le curseur se positionne sur un autre contrôle et en change l'aspect.

IV. Le code associé à fRegions (premier formulaire de la cascade)

IV-A. À l'ouverture

 
Sélectionnez
Private Sub Form_Open(Cancel As Integer)
  DoCmd.MoveSize 500, 500
  'Ajuster la hauteur
  Call AmenagerTailleFormulaire(5000)
End Sub

La méthode MoveSize de l'objet DoCmd permet de positionner un formulaire, ici nous l'ouvrons à 500 twips (à la grosse louche : 1 cm) plus à droite et plus bas que le coin supérieur gauche de la fenêtre Access. Soit à un endroit qui nous laissera de l'espace pour déployer la cascade.

Nous appelons ensuite la routine AmenagerTailleFormulaire() pour limiter sa hauteur à un maximum de 5000 twips (cette routine est décrite plus bas dans ce tutoriel).

IV-B. À la fermeture

 
Sélectionnez
Private Sub Form_Close()
    'Refermer tous les autres formulaires de la cascade
    If CurrentProject.AllForms("fDepartements").IsLoaded Then DoCmd.Close acForm, "fDepartements"
    If CurrentProject.AllForms("fCommunes").IsLoaded Then DoCmd.Close acForm, "fCommunes"
    If CurrentProject.AllForms("fDetails").IsLoaded Then DoCmd.Close acForm, "fDetails"
End Sub

Nous refermons aussi tous les formulaires de la cascade.

IV-C. À chaque lecture d'un enregistrement

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Private Sub Form_Current()
  'Pour mettre la ligne active en surbrillance
  Me.txtActif = Me.txttRegionsPK
  'Ouvrir fDepartements (suivant de la cascade)
     'd'abord le refermer s'il a déjà été ouvert
  If CurrentProject.AllForms("fDepartements").IsLoaded Then DoCmd.Close acForm, "fDepartements"
  DoCmd.OpenForm "fDepartements", , , "tRegionsFK =" & Me.txttRegionsPK, , acHidden
  PositionForm Forms("fDepartements"), Me.txtActif
  'Ajuster toutes les mères gigognes à sa droite
  Call Forms("fDepartements").Form_Current
  Call Forms("fCommunes").Form_Current
End Sub

Ligne 3 : on copie la valeur de la clé dans txtActif. Comme la clé est unique, l'enregistrement en cours est donc le seul pour lequel on a l'égalité entre txttRegionsPK et txtActif (dans tous les autres, txtActif a la valeur Null). Cette astuce permet d'exploiter la mise en forme conditionnelle pour allumer les contrôles d'une couleur particulière seulement sur la ligne active :

Image non disponible

Lignes 7 et 8 : on provoque l'ouverture du formulaire suivant de la cascade.

Remarque

Image non disponible

Lignes 10 et 11 : pour positionner correctement les formulaires qui s'ouvriront à la droite de celui-ci.

Faites l'expérience de supprimer ces instructions (en les mettant en commentaires),

Image non disponible

vous obtiendrez ceci :

Image non disponible

On peut faire appel à une routine d'un autre formulaire pour autant que celle-ci soit déclarée « Public ».

V. Le code associé aux formulaires suivants de la cascade

V-A. À l'ouverture

 
Sélectionnez
Private Sub Form_Open(Cancel As Integer)
  'Compléter le sous-titre
  Me.EtiSousTitre.Caption = "de la région " & Forms!fRegions!txtRegion
  'Ajuster la hauteur
  Call AmenagerTailleFormulaire(5000)
End Sub

On complète l'étiquette sous-titre en copiant le texte affiché dans l'enregistrement actif du formulaire situé à sa gauche.

V-B. À chaque lecture d'un enregistrement

 
Sélectionnez
Public Sub Form_Current()
  'Pour mettre la ligne active en surbrillance
  Me.txtActif = Me.txttDepartementsPK
  'Ouvrir fCommunes (suivant de la cascade)
    'Vérifier qu'il y a au moins une commune
  If DCount("tDepartementsFK", "tCommunes", "tDepartementsFK=""" & Me.txttDepartementsPK & """") = 0 Then Exit Sub
    'Ouvrir
       'D'abord le fermer s'il est ouvert
  If CurrentProject.AllForms("fCommunes").IsLoaded Then DoCmd.Close acForm, "fCommunes"
  DoCmd.OpenForm "fCommunes", , , "tDepartementsFK =""" & Me.txttDepartementsPK & """", , acHidden
  PositionForm Forms("fCommunes"), Me.txtActif
  'Ajuster toutes les mères gigognes à sa droite
  Call Forms("fCommunes").Form_Current
End Sub

Comme annoncé plus haut, cette Sub est déclarée « Public ».

C'est la seule différence (mutatis mutandis) par rapport au premier formulaire de la cascade.

VI. Adapter la hauteur d'un formulaire continu au nombre de ses enregistrements

 
Sélectionnez
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.
39.
40.
41.
42.
43.
44.
45.
46.
Public Sub AmenagerTailleFormulaire(HauteurMax As Long)
  Dim EspaceNecessaire As Long
  Dim i As Integer
  Dim lngHauteurAjustee As Long
  On Error GoTo GestionErreurs
  With CodeContextObject
     'Vérifier qu'il s'agit d'un formulaire qui affiche plusieurs enregistrements à la fois
     If .DefaultView = 0 Then
       MsgBox "Ce formulaire affiche un seul enregistrement à la fois, la routine ne s'applique pas"
       Exit Sub
     End If
     'Calculer l'espace nécessaire pour afficher tous les enregistrements
     .RecordsetClone.MoveLast 'pour pouvoir ensuite compter le nbre d'enregistrements
     EspaceNecessaire = .Section(acHeader).Height _
                  + .Section(acFooter).Height _
                  + .Section(acDetail).Height _
                       * (.RecordsetClone.RecordCount - .AllowAdditions) 'Ceci revient à ajouter 1 si ajout autorisé
     'Limitation au maximum possible
     If EspaceNecessaire > HauteurMax Then  'trop pour tout afficher
         .ScrollBars = 2 'pour afficher une barre de défilement verticale
         'Ajuster la hauteur (pour éviter que le dernier enregistrement ne soit amputé)
         Do Until lngHauteurAjustee > HauteurMax
           lngHauteurAjustee = .Section(acHeader).Height _
                  + .Section(acFooter).Height _
                  + .Section(acDetail).Height _
                       * (i - .AllowAdditions)
           i = i + 1
         Loop
         .InsideHeight = .Section(acHeader).Height _
                  + .Section(acFooter).Height _
                  + .Section(acDetail).Height _
                       * (i - 1 - .AllowAdditions)
       Else
        .ScrollBars = 0  ' pas de barre de défilement verticale
        .InsideHeight = EspaceNecessaire
     End If
  End With
GestionErreurs:
  Select Case Err.Number
      Case 0        'Pas d'erreur
      Case 3021 'Pas d'enregistrement
        DoCmd.MoveSize 0, 0, 0, 0  'ce qui a pour conséquence de cacher le formulaire
      Case Else
        MsgBox "Erreur dans AmenagerTailleFormulaire : " & vbLf & " erreur : " & Err.Number & " " & Err.Description, vbCritical
  End Select
End Sub

Commentaires du code

: la propriété CodeContextObject permet de déterminer l'objet pour lequel du code Visual Basic est en cours d'exécution.

Quand la routine AmenagerTailleFormulaire () s'exécute, CodeContextObject représente l'objet (ici le formulaire) qui a déclenché l'exécution. Il hérite alors de toutes les propriétés de ce dernier.

Concrètement, si à son ouverture, le formulaire fRegions appelle AmenagerTailleFormulaire(), nous aurons accès à toutes les propriétés du formulaire fRegions. Par exemple : 

CodeContextObject.DefaultView donnera la valeur du mode d'affichage (0 pour Mode simple, 1 pour mode continu…) ;

CodeContextObject.Section(acHeader).Height donnera la hauteur (en twips) de l'en-tête ; 

CodeContextObject.RecordsetClone.RecordCount donnera le nombre d'enregistrements…

Remarquez l'instruction ligne 6 vb With => ligne 37 End With.

L'instruction With permet d'appliquer une série d'instructions à l'objet indiqué (ici le formulaire), sans devoir le qualifier à chaque fois. Cela permet d'alléger l'écriture du code : on pourra écrire .DefaultView au lieu de CodeContextObject.DefaultView.

8 - 10 : si le formulaire est affiché en « Mode simple » (un enregistrement à la fois), l'appel à cette routine n'a pas de sens : on sort.

13 - 17 : l'espace nécessaire pour tout afficher, c'est la somme des hauteurs de l'en-tête, du pied et autant de fois la hauteur d'une section détail qu'il y a d'enregistrements, plus éventuellement la dernière section détail réservée à l'encodage d'un ajout (la propriété « Ajout autorisé » a alors la valeur True, c'est-à-dire -1, sinon elle vaut False, donc 0).

N.B. Si le formulaire appelant est vide (zéro enregistrement) l'instruction 13 va provoquer une erreur 3021 qui sera traitée aux instructions 42 - 43 (on rend le formulaire imperceptible : il est visible, mais toutes ses dimensions sont à 0).

19 - 36 : de deux choses l'une :

  • l'espace nécessaire est plus grand que l'espace maximum demandé (19 - 32) ;
  • on a assez de place pour tout montrer (34 - 35).

19 - 32 : on installe une barre de défilement verticale et ensuite, on fait en sorte que seules des sections « Détail » entières soient affichées. On veut par exemple éviter ceci :

Image non disponible

On ajoute autant de sections Détail pour dépasser la limite et on en retranche une pour obtenir ceci :

Image non disponible

VII. Téléchargement

La base exemple au format Access2000 se trouve ici.

VIII. Remerciements

Reconnaissance à Thierry GASPERMENT (Arkham46) pour ses nombreuses contributions.

Merci à Malick Seck (milkoseck) et Winjerome pour la relecture.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2016 Claude Leloup. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.