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 :
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 :
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 :
et si on navigue dans l'un des formulaires, ceux à sa droite s'adaptent instantanément :
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).
Et pour l'utiliser, deux lignes de code :
DoCmd.OpenForm
"FormulaireAPositionner"
, , , , , acHidden
PositionForm Forms
(
"FormulaireAPositionner"
), Me.UneZoneDeTexte
Deux précautions :
- le formulaire à ouvrir doit être en fenêtre indépendante :
- 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▲
L'en-tête s'adapte pour afficher le texte de l'enregistrement actif dans le formulaire mère gigogne.
L'enregistrement actif s'affiche dans une couleur distincte.
Le pied du formulaire s'affiche au raz du dernier enregistrement.
La hauteur du formulaire s'adapte au nombre d'enregistrements à afficher.
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.
Fenêtre indépendante, routine PositionForm
(
) oblige !
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.
Une étiquette, à l'origine vierge, que nous complèterons à la volée dans l'événement ouverture du formulaire.
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 ▲
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▲
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▲
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 :
Lignes 7 et 8 : on provoque l'ouverture du formulaire suivant de la cascade.
Remarque
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),
vous obtiendrez ceci :
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▲
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▲
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▲
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
&
"N° erreur : "
&
Err
.Number
&
" "
&
Err
.Description
, vbCritical
End
Select
End
Sub
Commentaires du code
6 : 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 :
On ajoute autant de sections Détail pour dépasser la limite et on en retranche une pour obtenir ceci :
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.