I. Ce que l'on veut réaliser▲
Soit une table de mouvements comptables :
On voudrait un état dans lequel chacun des journaux (Achats, Caisse…) est paginé individuellement :
II. Si vous êtes pressé▲
… que vous n'aimez pas lire et que seul le résultat vous intéresse, voici comment y arriver :
- construisez votre état en vous inspirant de ce schéma :
- dans le module associé à l'état, vous collez aveuglément ce code :
Option
Compare Database
Option
Explicit
Dim
sCtlGroupe As
String
Dim
sValGroup As
String
Dim
sChampGroupe As
String
Dim
oColTable As
Collection
Public
Sub
MaJoColTable
(
Groupe As
String
, NumPage As
Integer
)
On
Error
GoTo
GestionErreurs
If
NumPage >
oColTable
(
Groupe) Then
oColTable.Remove
Groupe
oColTable.Add
NumPage, Groupe
End
If
GestionErreurs
:
Select
Case
Err
.Number
Case
0
'pas d'erreur
Case
5
'pas encore dans la collection
oColTable.Add
NumPage, Groupe
End
Select
End
Sub
Public
Function
GetPages
(
Groupe As
String
) As
Integer
GetPages =
oColTable
(
Groupe)
End
Function
Private
Sub
Report_Open
(
Cancel As
Integer
)
On
Error
GoTo
GestionErreurs
'Recherche du nom du contrôle qui contient le champ de groupage
sChampGroupe =
Me.Report.GroupLevel
(
0
).ControlSource
'<----- le niveau de regroupement le plus élevé
'Construire la propriété Contrôle source du champ txtNumerotation
Me.txtNumerotation.ControlSource
=
"="" Page "" & [Page] & "" sur "" & getpages(["
&
sChampGroupe &
"])"
'Initialiser la collection
Set
oColTable =
New
Collection
GestionErreurs
:
Select
Case
Err
.Number
Case
0
'pas d'erreur
Case
Else
MsgBox
"Erreur dans Report_Open N° "
&
Err
.Number
&
" "
&
Err
.Description
End
Select
End
Sub
Private
Sub
EntêteGroupe0_Format
(
Cancel As
Integer
, FormatCount As
Integer
)
' Provoquer la réinitialisation de [Page] au changement de Groupe
Me.Page
=
1
End
Sub
Private
Sub
ZonePiedPage_Format
(
Cancel As
Integer
, FormatCount As
Integer
)
Call
MaJoColTable
(
Me
(
sChampGroupe), Me.Page
)
End
Sub
Private
Sub
Report_Close
(
)
Dim
E As
Integer
'Libérer l'objet collection de la mémoire
For
E =
1
To
oColTable.Count
oColTable.Remove
1
Next
Set
oColTable =
Nothing
End
Sub
Mais, si vous voulez comprendre pourquoi ça marche, faites l'effort de lire la suite…
III. L'idée qui sous-tend la programmation▲
III-A. À propos des propriétés Page et Pages d'un état dans Access▲
|
La propriété Page spécifie le numéro de la page en cours lors de l'impression. Sélectionnez
recommencera la numérotation à partir de 1 pour le groupe en cours de traitement. |
III-B. On va forcer Access à construire l'état en deux temps▲
- On place dans l'état, un contrôle avec comme source =
[Pages].
- À chaque changement de groupe, dans l'événement Au formatage de l'entête de groupe, on remet la propriété [Page] à 1.
- À chaque formatage d'une page, dans l'événement Au formatage du pied de page, on mémorise dans un tableau interne la paire : Nom du groupe/N° de page. Dans ce tableau, on ne retient pour un même Nom du groupe que la ligne qui contient le plus grand N° de page.
En d'autres mots, quand Access a fini sa première passe, le tableau contient une ligne par Nom de groupe et son N° de page le plus élevé, donc le nombre de pages de ce groupe.
- Au deuxième passage, Access sera en mesure de compléter la valeur du contrôle txtNumerotation dont la source a été construite à l'ouverture, dans notre exemple :
IV. Analyse détaillée du code VBA▲
IV-A. Définition des variables▲
Option
Compare Database
Option
Explicit
Dim
sCtlGroupe As
String
Dim
sValGroup As
String
Dim
sChampGroupe As
String
Dim
oColTable As
Collection
Elles sont définies en tête de module pour que leur valeur soit disponible tant que l'état est ouvert.
IV-B. Dans l'événement Sur ouverture▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
Private
Sub
Report_Open
(
Cancel As
Integer
)
On
Error
GoTo
GestionErreurs
'Recherche du nom du contrôle qui contient le champ de groupage
sChampGroupe =
Me.Report.GroupLevel
(
0
).ControlSource
'<----- le niveau de regroupement le plus élevé
'Construire la propriété Contrôle source du champ txtNumerotation
Me.txtNumerotation.ControlSource
=
"="" Page "" & [Page] & "" sur "" & getpages(["
&
sChampGroupe &
"])"
'Initialiser la collection
Set
oColTable =
New
Collection
GestionErreurs
:
Select
Case
Err
.Number
Case
0
'pas d'erreur
Case
Else
MsgBox
"Erreur dans Report_Open N° "
&
Err
.Number
&
" "
&
Err
.Description
End
Select
End
Sub
Commentaires
4 : syntaxe pour retrouver le nom de la colonne qui contient les valeurs à regrouper.
6 : par exemple, si l'instruction 4 a révélé que « Journal » est le nom de la colonne à regrouper, la propriété Contrôle source du champ txtNumerotation sera :
=" Page " & [Page] & " sur " & getpages([Journal]).
IV-C. Dans l'événement « Au formatage » entête de groupe▲
Private
Sub
EntêteGroupe0_Format
(
Cancel As
Integer
, FormatCount As
Integer
)
' Provoquer la réinitialisation de [Page] au changement de Groupe
Me.Page
=
1
End
Sub
On recommence la numérotation à 1.
IV-D. Dans l'événement « Au formatage » du pied de page▲
Private
Sub
ZonePiedPage_Format
(
Cancel As
Integer
, FormatCount As
Integer
)
Call
MaJoColTable
(
Me
(
sChampGroupe), Me.Page
)
End
Sub
Avec en paramètres la valeur du groupe et le N° de la page en cours, on appelle la routine de mise à jour de la table interne.
L'algorithme est le suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Public
Sub
MaJoColTable
(
Groupe As
String
, NumPage As
Integer
)
On
Error
GoTo
GestionErreurs
If
NumPage >
oColTable
(
Groupe) Then
oColTable.Remove
Groupe
oColTable.Add
NumPage, Groupe
End
If
GestionErreurs
:
Select
Case
Err
.Number
Case
0
'pas d'erreur
Case
5
'pas encore dans la collection
oColTable.Add
NumPage, Groupe
End
Select
End
Sub
Commentaire du code
3 : si la clé Groupe (la rubrique du journal) n'est pas encore dans la collection, une erreur N° 5 sera générée. On récupère cette dernière aux instructions 10 et 11, où on ajoute l'item à la collection.
Par contre, si la clé est déjà présente avec un N° de page inférieur, on l'élimine pour la remplacer par une paire Nouveau N° de page/Rubrique.
IV-E. À la fermeture de l'état▲
Private
Sub
Report_Close
(
)
Dim
E As
Integer
'Libérer l'objet collection de la mémoire
For
E =
1
To
oColTable.Count
oColTable.Remove
1
Next
Set
oColTable =
Nothing
End
Sub
V. Téléchargement▲
La base de données de test au format Access2000 est disponible ici.
VI. Remerciements▲
Merci à tee_grandbois pour ses remarques.
Merci à Jean-Philippe AMBROSINO (argyronet) pour la relecture technique et les corrections pour améliorer la qualité du code.
Merci à f-leb, Winjerome et dourouc05 pour la correction orthographique.