Developpez.com

Club des développeurs et IT pro
Plus de 4 millions de visiteurs uniques par mois

Dans un état Access, apprendre à numéroter les pages d'un groupe « page x sur y »

Centres d'intérêt dans ce tutoriel :

- [Page] et [Pages] sous la loupe ;

- création d'une table de paires Clé/Valeur en mémoire (utilisation de Collection).

Les commentaires et les suggestions d'amélioration sont les bienvenus, alors, après votre lecture, n'hésitez pas : 3 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Ce que l'on veut réaliser

Soit une table de mouvements comptables :

Image non disponible

On voudrait un état dans lequel chacun des journaux (Achats, Caisse…) est paginé individuellement :

Image non disponible
Image non disponible

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 :

Image non disponible
Cliquez sur l'image pour l'agrandir

- dans le module associé à l'état, vous collez aveuglément ce code :

 
Sélectionnez
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  " & 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

Image non disponible

La propriété Page spécifie le numéro de la page en cours lors de l'impression.
La propriété Pages spécifie le nombre total de pages.
Par défaut, Page commence sa numérotation à 1 et s'incrémente d'une unité à chaque page suivante.
Quand, dans un état, un champ fait référence à la propriété Pages, on oblige Access à procéder en deux temps :
- d'abord Access construit l'état sans l'imprimer, jusqu'à atteindre la dernière ligne pour déterminer le nombre de pages que contiendra finalement l'état. À ce stade, Access n'a pas encore garni les contrôles qui se réfèrent à Pages, mais il connaît maintenant le nombre de pages ;
- ensuite, en imprimant cette fois, Access recommence depuis le début en complétant la valeur de Pages dans les contrôles qui utilisent cette propriété.
Pages est disponible en lecture seule : l'utilisateur ne peut modifier sa valeur.
Par contre, avec des instructions VBA, on peut modifier la valeur de Page.
Par exemple, on peut forcer de recommencer à 1 à chaque changement d'une valeur de regroupement.
Dans l'événement Au formatage de la section qui contient le groupe, ce code :

 
Sélectionnez
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

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 :

Image non disponible

IV. Analyse détaillée du code VBA

IV-A. Définition des variables

 
Sélectionnez
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

 
Sélectionnez
1.
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  " & 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

 
Sélectionnez
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

 
Sélectionnez
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 :

Image non disponible
 
Sélectionnez
1.
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

 
Sélectionnez
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.

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.