I. Ce dont il s'agit▲
Imaginez un formulaire pour comptabiliser les opérations bancaires d'une association caritative.
Un formulaire père avec quatre fils qui détaillent les différents mouvements enregistrés à l'extrait de la banque. (Exemple repris de Tutoriel pour gérer une association avec Access)
Dans une première approche, ceci :
Dans la section pied de chacun des sous-formulaires, deux infos (en gris foncé) :
- le nombre de postes détaillés ;
- le total de ces postes.
Le pied s'affiche au bas de l'espace que nous avons réservé au conteneur du sous-formulaire :
Et ce, quel que soit le nombre de lignes que comporte le détail.
Ce que nous souhaitons, c'est que le pied soit collé juste en dessous de la dernière ligne de détail, comme ceci :
Bref, ce que nous voulons, c'est que la hauteur de l'espace réservé aux conteneurs des sous-formulaires s'adapte automatiquement pour que la section Pied apparaisse juste en dessous du dernier détail (ou de l'espace réservé à l'encodage du suivant).
Et si le nombre de lignes de détail s'avère trop grand pour les afficher toutes, nous ajouterons une barre de défilement verticale au sous-formulaire concerné.
II. Préparons le terrain▲
II-A. Convention de nommage▲
II-B. Des repères pour indiquer la hauteur maximum des sous-formulaires▲
III. Une sous-routine pour adapter la hauteur du conteneur de sous-formulaire▲
III-A. Le code▲
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.
47.
48.
49.
50.
51.
52.
53.
54.
Option Compare Database
Option Explicit
Public Sub AmenagerTailleSF(LeForm As Access.Form, LeSF As Access.SubForm)
Dim EspaceNecessaire As Long, EspaceLibre As Long, iAffichables As Integer
On Error GoTo GestionErreurs
With LeSF
'Calculer l'espace nécessaire pour afficher tous les enregistrements
.Form.RecordsetClone.MoveLast 'pour pouvoir ensuite compter le nbre d'enregistrements
EspaceNecessaire = .Form.Section(acHeader).Height _
+ .Form.Section(acFooter).Height _
+ .Form.Section(acDetail).Height _
* (.Form.RecordsetClone.RecordCount - .Form.AllowAdditions) 'Ceci revient à ajouter 1 si ajout autorisé
'Calculer l'espace disponible et le nbre d'enregistrements affichables
EspaceLibre = LeForm("Bas" & LeSF.Name).Top - .Top
iAffichables = Int(((EspaceLibre - .Form.Section(acHeader).Height - .Form.Section(acFooter).Height) / _
.Form.Section(acDetail).Height))
'Limitation au maximum possible
If EspaceNecessaire > EspaceLibre Then 'trop pour tout afficher
.Height = EspaceLibre
.Form.InsideHeight = EspaceLibre
.Form.ScrollBars = 2 'pour afficher une barre de défilement verticale
'Afficher les derniers enregistrements de la liste
.SetFocus
DoCmd.GoToRecord , , acNewRec 'afficher l'emplacement de l'ajout si permis, sinon erreur 2105 et instruction suivante
DoCmd.GoToRecord , , acLast
DoCmd.GoToRecord , , acPrevious, iAffichables - 1 + .Form.AllowAdditions
'se positionner sur le dernier
DoCmd.GoToRecord , , acLast
Else
.Height = EspaceNecessaire
.Form.InsideHeight = EspaceNecessaire
.Form.ScrollBars = 0 ' pas de barre de défilement verticale
'Afficher tous les enregistrements et se positionner sur le dernier
.SetFocus
DoCmd.GoToRecord , , acFirst
DoCmd.GoToRecord , , acLast
End If
End With
GestionErreurs:
Select Case Err.Number
Case 0 'Pas d'erreur
Exit Sub
Case 3021 'Pas d'enregistrement dans le sous-formulaire
Resume Next
Case 2105 'Pas d'ajout permis dans le sous-formulaire
Resume Next
Case Else
MsgBox "Erreur dans AmenagerTailleSF : " & vbLf & "N° erreur : " & Err.Number & " " & Err.Description, vbCritical
End Select
End Sub
III-B. Explication du code▲
4 : la procédure demande deux paramètres : l'objet formulaire qui appelle et l'objet conteneur du sous-formulaire qui doit être redimensionné.
7 : les instructions With et End With (ligne 42) permettent d'abréger l'écriture. Entre ces deux instructions au lieu d'écrire par exemple
« LeSf.Form.Section(acHeader).Height »
on pourra abréger et n'écrire que « .Form.Section(acHeader).Height ».
9-14 : on calcule la hauteur qui serait nécessaire pour afficher tous les enregistrements.
On additionne la hauteur de la section « En-tête », la hauteur de la section « Pied » et autant de fois la hauteur de la section « Détail » qu'il y a d'enregistrements à afficher.
On ajoute encore à cela une fois la hauteur de la section « Détail » pour l'espace (éventuel) d'un ajout d'un nouvel enregistrement.
N.B. Si les ajouts sont autorisés la propriété .Form.AllowAdditions vaut -1, sinon 0.
17 : par différence entre la propriété « Haut » du trait repère et celle du sous-formulaire, on détermine l'espace maximum que peut occuper le sous-formulaire déployé.
18 - 19 : le nombre d'enregistrements qui pourront s'afficher ensemble égale la partie entière Ent() du quotient de la hauteur disponible divisée par la hauteur d'une section détail.
21 - 41 : de deux choses l'une :
- EspaceNecessaire > EspaceLibre => il n'y a pas assez de place pour tout afficher :
23 : on attribue au sous-formulaire la hauteur maximum disponible,
24 : on ajuste la fenêtre,
25 : on ajoute une barre de défilement verticale,
27 - 32 : on fait voyager le sélecteur pour afficher toutes les dernières lignes. Y compris la ligne vierge pour l'ajout éventuel. Une erreur 2105 sera levée si la propriété « Ajout autorisé » est à Non. Cette erreur éventuelle est trappée et on continue ;
- on a assez de place pour tout montrer :
34 : on attribue au sous-formulaire la hauteur nécessaire,
35 : on ajuste la fenêtre,
36 : sans barre de défilement,
38 - 40 : on met le focus sur le dernier enregistrement.
IV. Quand et comment déclencher cette sous-routine▲
IV-A. À chaque lecture d'un enregistrement du formulaire principal▲
Nous aurons donc, dans l'événement « Sur activation » :
Option Compare Database
Option Explicit
Private Sub Form_Current()
'Moduler la taille des sous-formulaires
Call AmenagerTailleSF(Me, Me.CTNRsfDons)
Call AmenagerTailleSF(Me, Me.CTNRsfAutresRecettes)
Call AmenagerTailleSF(Me, Me.CTNRsfFrais)
Call AmenagerTailleSF(Me, Me.CTNRsfActionsHum)
End SubIV-B. À chaque ajout ou suppression d'enregistrement dans le sous-formulaire▲
Donc lors des événements « Après insertion » et « Après suppression » :
2.
3.
4.
5.
6.
7.
8.
9.
10.
Option Compare Database
Option Explicit
Private Sub Form_AfterDelConfirm(Status As Integer)
Call AmenagerTailleSF(Me.Parent, Me.Parent.ActiveControl): Me.Requery
End Sub
Private Sub Form_AfterInsert()
Call AmenagerTailleSF(Me.Parent, Me.Parent.ActiveControl): Me.Requery
End Sub
On peut écrire plusieurs instructions sur une même ligne de code, en les séparant par un deux-points. (Par exemple, lignes 5 et 9.)
V. Téléchargement▲
L'exemple en version Access2000 peut être téléchargé ici.
VI. Remerciements▲
Merci à Pierre Fauconnier pour ses remarques techniques au sujet de la syntaxe des gestions d'erreurs (utilisation de Case 0 pour éviter des Exit Sub dans le corps de la procédure).
Merci à Arkham46 pour l'amélioration du code : passer les objets en paramètres, plutôt que leur nom. En l'occurrence écrirePublic Sub AmenagerTailleSF(LeForm As Access.Form, LeSF As Access.SubForm)
plutôt quePublic Sub AmenagerTailleSF(LeNomDuForm as String, LeNomDuSubForm As String).
Merci à f-leb pour la correction orthographique.











