I. Avant-propos▲
Ce document a pour but de vous montrer comment concevoir un formulaire permettant d'établir un lien direct vers un modèle Word selon la valeur d'un enregistrement.
Au final, lorsque vous serez sur le point de lancer l'impression d'une fiche exploitant un modèle Word spécifique, le processus sélectionnera le fichier selon l'enregistrement qui a été utilisé pour le définir.
Vous devez être relativement à l'aise avec Microsoft Access et connaître la conception de formulaires, mais également la manipulation des requêtes avec Visual Basic, en ayant une bonne approche de ce langage afin de mettre en pratique cet exemple.
I-A. Niveau▲
Ce tutoriel s'adresse plus particulièrement aux personnes qui possèdent déjà des notions concernant la gestion des événements avec Visual Basic sur Microsoft Access incluant la manipulation des données à l'aide de DAO.
I-B. Contact▲
Pour tous renseignements complémentaires, veuillez me contacter directement (Argyronet) par MP.
Si votre question est, disons publique, merci de poster un message dans le forum afin d'en faire partager le contenu...
I-C. Le projet proposé▲
Le projet abordé dans ce tutoriel est fourni sous forme de code source à titre d'exemple qui, une fois compilé, assemblé et interprété peut nécessiter des adaptations ou des modifications en rapport avec vos besoins.
Il est tout à fait possible que votre vision des choses à l'égard de la méthodologie employée au sein des différentes fonctions ou procédures soit différente de la mienne. Aussi, n'hésitez pas à proposer vos idées si vous pensez qu'elles peuvent apporter un plus à ce module.
Notez que j'ai cherché avant tout à simplifier l'ensemble pour que tout un chacun puisse l'assimiler de façon aisée.
II. Pourquoi ce projet▲
II-A. Contexte▲
Ce tutoriel est né, comme bien souvent, en ce qui me concerne, de l'idée d'une réalisation professionnelle qui m'a été demandée
et que j'ai souhaité partager avec vous, du fait je la trouve intéressante à exploiter. J'espère que ce sera le cas pour vous.
Pour clarifier un peu les choses, vous devez être dans une situation où votre application Access exploite l'édition de documents via le traitement de texte Microsoft Word, d'une part et que ces éditions se fassent sur des modèles différents selon un certain contexte d'autre part.
À ce jour, la sélection du modèle pour vous est manuelle et automatiser le processus serait une chose intéressante.
Imaginons que vous ayez à éditer des rapports de comptes-rendus pour différentes collectivités et que chacune d'entre elles exige qu'il y ait
son logo accouplé à quelques informations qui lui sont propres sur la page de garde du document...
Vous pouvez y répondre favorablement, mais vous être contraint de choisir manuellement le modèle prédéfini à chaque fois avant d'imprimer.
Si tel est le cas, ce tutoriel est fait pour vous.
Notez au passage que le code de ce projet a été modifié et adapté pour la circonstance afin que sa mise en place soit aisée et que sa présentation sous forme de formulaire autonome prêt à l'emploi le soit aussi.
II-B. De quoi avez-vous besoin ?▲
Pour mettre en œuvre le projet quasi complet de ce tutoriel, vous avez besoin :
- d'une version professionnelle de Microsoft Office ;
- d'un jeu de modèles Microsoft Word (2003-2013) ;
- que votre version d'Access soit identique à celle de Word ;
- d'un peu de temps pour réaliser le projet et modifier votre application pour l'intégrer.
Il est à considérer, et c'est sous-entendu, que les modèles sont pourvus de signets et que ces derniers sont alimentés avec la valeur des champs d'un Recordset par échange de données entre Microsoft Access et Microsoft Word via la technologie (OLE) Automation.
Note
Ce point ne sera abordé que succinctement dans ce tutoriel.
Remarque :dans ce tutoriel, j'ai considéré le cas d'école suivant :
- les modèles sont identifiés en fonction de communes. Dans notre exemple, je n'ai pris que les communes de l'Île de France, mais il est tout à fait envisageable d'y lister la totalité des communes de notre cher pays. Le procédé n'est guère plus long si vous n'êtes pas à quelques millisecondes près.
- l'ensemble est donc voué à proposer l'impression d'un document donné pour une commune qui lui est affectée. En d'autres termes, si votre application nécessite de générer des documents en fonction d'un critère cible comme justement une ville, c'est idéal pour vous. Sinon, il vous faudra procéder à quelques adaptations (noms des contrôles, des étiquettes et des messages affichés).
Ce tutoriel peut, dans son ensemble, être mis en application pour toutes les versions d'Access.
Il est présenté ici sous Access 2010 (14).
Toutefois, certaines méthodes seront inexistantes dans les versions antérieures à la version 2000 et des adaptations seront sans doute nécessaires.
III. Présentation du projet▲
Ce projet est un formulaire indépendant ouvert au moment voulu pour paramétrer les modèles Word.
On entend par paramétrer, le fait d'ajouter, supprimer ou modifier des modèles avec leurs clés cibles d'enregistrement qui permettront de les identifier pour les utiliser au moment de l'impression, qu'elle soit papier ou PDF.
L'appel de ce formulaire peut par exemple être effectué depuis la section "Préférences et paramètres" du menu principal de votre application.
Une fois ouvert, il se présente dépourvu de toute donnée (volontairement). S'il existe des modèles, la liste peut être consultée et éventuellement la faire évoluer.
Sinon, un message vous avertit qu'aucun modèle n'a été défini.
L'affichage présenté ci-dessus est le formulaire tel que chargé à l'ouverture.
Dans la table des modèles (voir §IV), il existe un modèle dont l'identifiant est 1 ; c'est le modèle par défaut.
En effet, lorsque vous lancerez une impression, pour peu qu'aucun modèle n'ait été affecté à la commune de la fiche à imprimer, il est nécessaire que le processus puisse choisir tout de même le modèle cible et donc, celui par défaut.
Ce bloc conditionnel sera à prendre en considération dans votre bloc de code qui gère les impressions.
En conséquence, vous devrez faire en sorte que ce modèle soit disponible d'une part et que son entrée dans la table comme enregistrement par défaut, soit effectuée manuellement.
Cette table ayant un compteur pour les identifiants des modèles, il faut que cette opération soit effectuée en premier ou bien que vous modifiiez l'interface en conséquence, car je n'ai pas prévu ce processus (version light du tutoriel).
III-A. Structure fonctionnelle du formulaire▲
La fenêtre est composée de différents contrôles dont certains sont masqués au démarrage, le chargement considérant que le mode ajout est le mode par défaut.
De ce fait, vous pouvez à l'ouverture, ajouter un nouveau modèle et l'enrichir des valeurs correspondant à son identification.
Pour ajouter un modèle, il vous faut le sélectionner via la boîte de dialogue Ouvrir qui est appelée avec la fameuse API GetOpenFileName(). Une fois le modèle sélectionné, le nom de ce dernier est greffé dans une zone de texte (Textbox) et l'ensemble des communes disponibles est listé dans la zone de liste (Listbox).
Il ne vous reste plus qu'à sélectionner les communes concernées une à une, la liste ayant sa propriété Multiselect définie en conséquence.Dès qu'une ou plusieurs communes sont sélectionnées, le bouton Valider est activé.
La validation stocke, après vérification, le modèle avec son chemin.
Une fois l'opération achevée, le formulaire repasse en mode saisie où il est possible d'ajouter un autre modèle avec le même procédé.
Vous pouvez alors ajouter un autre modèle ou consulter tous ceux que vous avez déjà stockés.
En mode consultation, vous accédez aux modèles existants depuis une liste déroulante ; celle-ci pilote la liste des communes lorsqu'un modèle est sélectionné et affiche alors les enregistrements correspondant au modèle.
Cette liste qui est en lecture seule ne peut faire l'objet d'aucune sélection. En cas de nécessité, il est donc possible de modifier le modèle pour ajuster les communes qui lui sont affectées, c'est à dire en supprimer ou en ajouter.
Lorsque le modèle est en mode modification, la liste de ses communes est remplacée par une autre liste qui propose alors toutes les communes disponibles à ceci près que celles affectées au modèle sont en surbrillance.
L'utilisateur peut sélectionner les communes en surbrillance pour les supprimer et sélectionner celles qui ne le sont pas pour les activer.
Une validation sera alors nécessaire.
Notez au passage qu'un bouton permettant de supprimer l'ensemble des communes pour un modèle donné a été prévu.
IV. Les tables du projet▲
Il y a trois tables nécessaires à la mise en œuvre de ce projet :
- tblOutputReportTemplates : table des modèles Word.
- tblTemplatesAndTowns : table de liaison modèles / communes.
- tblTowns : table des communes.
Descriptif des tables
- La table des modèles Word contient les modèles que vous allez sélectionner.
- La table de liaison modèles / communes contient les identifiants de chacune des tables.
- La table des communes doit contenir toutes les communes qui sont souhaitées (ou tout autre type de valeur si votre idée pour exploiter ce tutoriel concerne un autre sujet).
IV-A. La structure des tables▲
La structure des tables reste des plus simples ; quelques champs au bas mot.
La table des modèles Word
Nom du champ | Type du champ | Taille du champ |
---|---|---|
TemplateID | Primaire Numéro Auto | 4 |
TemplateName | Texte | 64 |
TemplatePath | Texte | 255 |
IsUsed | Oui/Non | 1 |
La table de liaison modèles/communes
Nom du champ | Type du champ | Taille du champ |
---|---|---|
TemplateID | Entier Long | 4 |
IDTown | Entier Long | 4 |
La table des communes
Nom du champ | Type du champ | Taille du champ |
---|---|---|
IDTown | Primaire Numéro Auto | 4 |
PostalCode | Texte | 5 |
TownName | Texte | 100 |
Notez au passage que la notion de taille de champ pour les champs de type numérique ne peut pas être définie par le développeur.
Il ne faut donc pas essayer de trouver comment l'attribuer, celle-ci l'étant automatiquement.
IV-B. Données des tables▲
Rappel :
La table des modèles reçoit une valeur par défaut avec un ID attribué à 1.
Prenez en considération que ce chiffre 1 est initialisé par un compteur et doit donc être entré en premier.
C'est la seule entrée manuelle dans cette table.
J'aborderai ce point à la fin de cet article.
Le modèle par défaut entré manuellement dans la table se doit d'exister en tant que fichier physique.
Sur ce point, je vous fais bien entendu un clin d'œil pour que vous mettiez en place une gestion d'erreur traitant le cas N°53.
IV-B-1. Exemple de données dans les tables▲
Les données affichées dans les illustrations ci-aprèsne sont représentatives que de mon projet.
Seuls les communes et le modèle par défaut ont été entrés manuellement dans leur table respective.
Une fois les tables conçues et alimentées comme il se doit, vous allez pouvoir vous attaquer à la conception du formulaire.
V. Conception du formulaire▲
Le formulaire est assez délicat à concevoir dans le sens où quelques contrôles se superposent, l'objectif ici étant de faire en sorte que selon le mode d'utilisation, il n'y ait pas de décalage visuel de pixel, notamment sur les cadres et les zones de liste accompagnés de leur étiquette.
C'est pourquoi je vous ai spécifié pour chacun d'eux, leur position et dimension si toutefois vous souhaitez reproduire à la lettre cet écran.
Pour mettre en œuvre ce tutoriel, vous allez donc ajouter dans un formulaire vierge un lot de contrôles qui sont listés ci-après :
- 13 contrôles Etiquette ;
- 2 contrôles Zone de texte ;
- 6 contrôles Rectangle ;
- 1 contrôle Groupe d'options ;
- 1 contrôle Zones de liste déroulante ;
- 2 contrôles Zone de liste ;
- 6 contrôles Bouton de commande.
Rappel
Chaque contrôle recevant ou affichant des données est systématiquement dessiné avec son étiquette ; de ce fait, vous n'avez pas à les ajouter.
Ces contrôles doivent tous être nommés (même les étiquettes - eh oui, c'est sans doute pénible, mais c'est plus pro, plus propre et en plus utile pour la lisibilité du code...).
V-A. Vue éclatée du formulaire▲
L'illustration ci-après montre le formulaire en vue éclatée pour que vous puissiez apprécier son agencement.
Dans une certaine mesure, je vous préconise :
- De dessiner d'abord tous les contrôles en mode éclaté également ;
- De leur affecter d'abord leur nom ;
- De leur affecter ensuite leurs dimensions ;
- De leur affecter (si nécessaire) leur couleur ;
- De leur affecter les propriétés techniques comme l'activation ou la visibilité ;
- Et enfin, de leur affecter leur position.
C'est plus commode et plus simple pour agencer des formulaires dont on possède les caractéristiques de leur contenu.
V-B. Description des contrôles▲
Vous allez donc dessiner les contrôles suivants.
Il est conseillé de dessiner les rectangles en dernier pour plus de commodité, notamment pour la sélection des autres contrôles devant être alignés sur les mêmes plans ou ceux devant être superposés.
Les zones de liste
Ces zones définissent respectivement la liste de toutes les communes et celle des communes déjà attribuées.
Liste des communes définies pour un modèle
Type = zone de liste Nom : lboTownsDefined
Position : Haut = 4,399 cm Gauche = 4,312 cm Largeur = 9,545 cm Hauteur = 4,813 cm
Liste des communes disponibles
Type = zone de liste Nom : lboTownToSet
Position : Haut = 4,392 cm Gauche = 18,254 cm Largeur = 9,545 cm Hauteur = 4,813 cm
La zone de liste déroulante
Cette liste permet de lister les modèles existants.
Liste des modèles
Type = zone de liste modifiable Nom : cboTemplateList
Position : Haut = 2,910 cm Gauche = 18,254 cm Largeur = 9,519 cm Hauteur = 0,584 cm
Les boutons de commande
Ces boutons sont dédiés aux actions de sélection, modification, suppression, consultation des modèles.
Bouton de validation du modèle ajouté ou modifié
Type = bouton de commande Nom : cmdValidate - Légende = &Valider ce modèle - Visible : OUI - Activé : NON
Position : Haut = 12,407 cm Gauche = 8,598 cm Largeur = 4,153 cm Hauteur = 0,700 cm
Bouton de fermeture (Fermer) ou de retour (Refermer)
Type = bouton de commande Nom : cmdClose - Légende = &Fermer ou &Refermer - Visible : OUI - Activé : OUI
Position : Haut = 12,407 cm Gauche = 12,751 cm Largeur = 2,354 cm Hauteur = 0,700 cm
Bouton de consultation des modèle ou leur modification
Type = bouton de commande Nom : cmdList - Légende = &Consulter la liste... ou &Modifier ce modèle... - Visible : OUI - Activé : NON
Position : Haut = 12,407 cm Gauche = 0,291 cm Largeur = 3,995 cm Hauteur = 0,700 cm
Bouton de sélection d'un fichier
Type = bouton de commande Nom : cmdOpenFile - Légende = ... - Visible : NON - Activé : OUI
Position : Haut = 2,884 cm Gauche = 13,280 cm Largeur = 0,593 cm Hauteur = 0,594 cm
Bouton de suppression des communes du modèle en cours
Type = bouton de commande Nom : cmdClearSelection - Légende = X - Visible : OUI - Activé : NON
Position : Haut = 9,286 cm Gauche = 13,175 cm Largeur = 0,698 cm Hauteur = 0,446 cm
Bouton de suppression du modèle actif
Type = bouton de commande Nom : cmdRemoveTemplate - Légende = &Supprimer ce modèle - Visible : OUI - Activé : NON
Position : Haut = 12,407 cm Gauche = 4,286 cm Largeur = 4,312 cm Hauteur = 0,700 cm
Les zones de texte
Une seule zone de texte reçoit une valeur, l'autre est dissimulée et sert au Focus.
Zone de texte dissimulée pour prendre le focus
Type = zone de texte Nom : txtVoid
Position : Haut = 0,000 cm Gauche = 0,000 cm Largeur = 0,000 cm Hauteur = 0,000 cm
Zone de texte définissant le modèle sélectionné
Type = zone de texte Nom : txtTemplateName
Position : Haut = 2,912 cm Gauche = 4,312 cm Largeur = 8,912 cm Hauteur = 0,582 cm
Le groupe d'options
Ce groupe sert à trier la liste des communes
Groupe de tri par commune ou code postal
(l'étiquette est stipulée plus bas lblSortBy)
Type = groupe d'options Nom : fraSortBy
Position : Haut = 6,164 cm Gauche = 1,402 cm Largeur = 2,702 cm Hauteur = 1,663 cm
Les boutons d'options
(les étiquettes sont stipulées plus bas lblByPostalCode et lblByTown)
Type = bouton d'option Nom : tgl1
Position : Haut = 6,584 cm Gauche = 1,730 cm Largeur = 0,459 cm Hauteur = 0,423 cm
Type = bouton d'options Nom : tgl2
Position : Haut = 7,166 cm Gauche = 1,730 cm Largeur = 0,459 cm Hauteur = 0,423 cm
Les étiquettes
Les étiquettes définissent les rôles des autres contrôles.
Étiquette des modèles existants
Type = étiquette Nom : lblTemplateList - Légende = Modèle &Word : - Visible : OUI - Couleur Texte : 0
Position : Haut = 2,917 cm Gauche = 15,212 cm Largeur = 2,899 cm Hauteur = 0,423 cm
Étiquette du groupe d'options
Type = étiquette Nom : lblSortBy - Légende = Trier par... - Visible : OUI - Couleur Texte : 0
Position : Haut = 5,952 cm Gauche = 1,614 cm Largeur = 1,534 cm Hauteur = 0,423 cm
Étiquette du bouton d'option tri par commune
Type = étiquette Nom : lblByTowns - Légende = Co&mmune - Visible : OUI - Couleur Texte : 0
Position : Haut = 6,534 cm Gauche = 2,136 cm Largeur = 1,402 cm Hauteur = 0,423 cm
Étiquette du groupe d'options tri par code postal
Type = étiquette Nom : lblByPostalCode - Légende = Co&de postal - Visible : OUI - Couleur Texte : 0
Position : Haut = 7,116 cm Gauche = 2,136 cm Largeur = 1,640 cm Hauteur = 0,423 cm
Étiquette masquée définissant le chemin du modèle (fait office de variable)
Type = étiquette Nom : lblTemplatePath* - Légende = #Path - Visible : NON - Couleur Texte : 255
Position : Haut = 1,984 cm Gauche = 12,090 cm Largeur = 1,194 cm Hauteur = 0,420 cm
Étiquette masquée définissant l'identifiant (ID) du modèle (fait office de variable)
Type = étiquette Nom : lblTempletaID* - Légende = #ID - Visible : NON - Couleur Texte : 255
Position : Haut = 1,984 cm Gauche = 13,360 cm Largeur = 0,873 cm Hauteur = 0,423 cm
Étiquette résumant le nombre de communes (disponibles, affectées...)
Type = étiquette Nom : lblTownsSelected - Légende = "" - Visible : OUI - Couleur Texte : 7633277
Position : Haut = 9,298 cm Gauche = 4,298 cm Largeur = 8,785 cm Hauteur = 0,446 cm
Étiquette de la zone de texte txtTemplateName
Type = étiquette Nom : lblTemplateName - Légende = Modèle &Word : - Visible : OUI - Couleur Texte : 0
Position : Haut = 2,919 cm Gauche = 1,270 cm Largeur = 2,899 cm Hauteur = 0,423 cm
Étiquette de la zone de liste lboTownToSet
Type = étiquette Nom : lblTownToSet - Légende = Communes associées : - Visible : OUI - Couleur Texte : 0
Position : Haut = 4,418 cm Gauche = 15,212 cm Largeur = 2,899 cm Hauteur = 0,476 cm
Étiquette de titre du formulaire (premier plan)
Type = étiquette Nom : lblTitleForm1* - Légende = Gestionnaire de modèles Word pour les communes - Visible : OUI - Couleur Texte : 8079968
Position : Haut = 0,397 cm Gauche = 0,000 cm Largeur = 15,450 cm Hauteur = 0,820 cm
Étiquette de titre du formulaire (arrière-plan)
Type = étiquette Nom : lblTitleForm2* - Légende = Gestionnaire de modèles Word pour les communes - Visible : OUI - Couleur Texte : 16764057
Position : Haut = 0,397 cm Gauche = 13,201 cm Largeur = 15,423 cm Hauteur = 0,820 cm
Étiquette de spécification de ce qu'il y a à faire
Type = étiquette Nom : lblWhatTodo* - Légende = "" - Visible : OUI - Couleur Texte : 16711680
Position : Haut = 1,984 cm Gauche = 1,085 cm Largeur = 10,926 cm Hauteur = 0,423 cm
Étiquette de la zone de liste lboTownsDefined
Type = étiquette Nom : lblTownsDefined - Légende = Communes associées : - Visible : OUI - Couleur Texte : 0
Position : Haut = 4,425 cm Gauche = 1,270 cm Largeur = 2,899 cm Hauteur = 0,476 cm
* Les étiquettes annotées d'un astérisque doivent être dessinées ; elles ne sont attachées à aucun contrôle
Les cadres de type Rectangle
Ces cadres permettent de déterminer des zones et de rendre le formulaire plus esthétique.
Cadre extérieur principal
Type = rectangle Nom : shpOutsideMain
Position : Haut = 1,534 cm Gauche = 0,661 cm Largeur = 14,051 cm Hauteur = 9,219 cm
Cadre intérieur principal (il entoure shpTemplate et shpTowns)
Type = rectangle Nom : shpInsideMain
Position : Haut = 1,693 cm Gauche = 0,794 cm Largeur = 13,734 cm Hauteur = 8,875 cm
Cadre du modèle en cours (il entoure txtTemplateName et cboTemplateList)
Type = rectangle Nom : shpTemplate
Position : Haut = 2,593 cm Gauche = 1,085 cm Largeur = 13,139 cm Hauteur = 1,205 cm
Cadre des boutons du bas
Type = rectangle Nom : shpButtons
Position : Haut = 11,190 cm Gauche = 0,185 cm Largeur = 15,055 cm Hauteur = 0,871 cm
Cadre de la liste des communes à définir(il entoure lboTownToSet)
Type = rectangle Nom : shpTowns
Position : Haut = 3,968 cm Gauche = 1,085 cm Largeur = 13,139 cm Hauteur = 6,257 cm
Cadre extérieur des modèles définis (il superpose shpOutsideMain)
Type = rectangle Nom : shpListOfTemplates
Position : Haut = 2,619 cm Gauche = 14,894 cm Largeur = 13,139 cm Hauteur = 7,633 cm
Les spécifications ci-dessus ne doivent être respectées que si vous souhaitez appliquer à la lettre la réalisation de ce formulaire. Vous pouvez bien entendu agencer ce dernier comme bon vous semble.
Notez toutefois qu'il est préférable de respecter les propriétés Caption, Visible et Enabled et surtout le nom des contrôles qui est en adéquation avec le code que je vais aborder plus loin.
Une fois le formulaire conçu et agencé comme il se doit, vous allez pourvoir vous attaquer au code événementiel qui permet son utilisation.
VI. Mode opératoire des événements pour les contrôles▲
Le module de classe du formulaire contient des procédures événementielles, des procédures et fonctions locales privées et aussi, des variables dites de module en en-tête.
VI-A. Le bloc d'en-tête▲
L'en-tête du module contient des constantes, des énumérations et des variables disponibles pour l'ensemble de la classe du formulaire.
- Les six constantes préfixées CMD définissent la légende des boutons (dynamiquement modifiées selon le contexte).
- Les trois constantes préfixées IS définissent le mot associé à la phrase inscrite dans le contrôle Label lblTownsSelected.
- L'énumération m_eSortBy, comme son nom l'indique, définit le sens su tri.
- L'énumération m_eUsingMode, comme son nom l'indique aussi, définit le mode d'utilisation en cours.
- Enfin, les trois variables m_blnIsNewTemplate, m_strSelectedTemplate et m_intUsingMode définissent respectivement le fait que vous êtes en train d'ajouter un nouveau modèle, le nom du modèle en cours et le mode d'utilisation en cours.
'**********************************************************************
' Project : WordTemplateManager
' Module : Form_frmTemplatesManager
' Type : Document VBA
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Review :
' Review date :
' Purpose : Module used to manage events and data from the form
'
'**********************************************************************
Option
Compare Database
Option
Explicit
Private
Const
CMD_SHOWLIST As
String
=
"&Consulter la liste..."
Private
Const
CMD_VALIDATE_TEMPLATE As
String
=
"&Valider ce modèle"
Private
Const
CMD_MODIFY_TEMPLATE As
String
=
"&Modifier ce modèle"
Private
Const
CMD_RECLOSE As
String
=
"&Refermer"
Private
Const
CMD_CLOSE As
String
=
"&Fermer"
Private
Const
CMD_CANCEL As
String
=
"&Annuler"
Private
Const
IS_AVAILABLE As
String
=
"disponible"
Private
Const
IS_DEFINED As
String
=
"affectée"
Private
Const
IS_SELECTED As
String
=
"selectionnée"
Private
Enum m_eSortBy
ByTown =
1
ByPostalCode =
2
End
Enum
Private
Enum m_eUsingMode
NotDefined =
0
UpdateTemplate =
1
ShowTemplateTowns =
2
CreateNewTemplate =
4
End
Enum
Private
m_blnIsNewTemplate As
Boolean
Private
m_strSelectedTemplate As
String
Private
m_intUsingMode As
m_eUsingMode
VI-B. Les procédures événementielles des contrôles▲
Pratiquement tous les contrôles se voient greffés d'un code événementiel.
Considérant que vous êtes censé n'avoir aucun modèle stocké (excepté le modèle par défaut, mais il n'est pas examiné), il est nécessaire d'afficher une information conséquente, traduite par un message régit dans l'événement Form_Load() :
Private
Sub
Form_Load
(
)
'Chargement du formulaire
'On rafraîchit alors l'affichage des contrôles
ShowHideControls False
'S'il n'existe aucun modèle...
If
TemplateIsDefined
(
True
, 0
) =
False
Then
'...on affiche un message
MsgBox
"Aucun modèle n'a été défini pour un jeu de communes donné."
&
vbCrLf
&
"Le modèle par défaut pour les éditions des rapports sera utilisé."
, vbInformation
, "Examen des modèles"
'et on désactive le bouton de consultation
cmdList.Enabled
=
False
'et on donne le focus au bouton Parcourir...
With
cmdOpenFile
.Enabled
=
True
.SetFocus
End
With
Else
'Sinon, le bouton de consultation est activé
cmdList.Enabled
=
True
End
If
'On met à jour la légende au bas de la liste avec aucune valeur
Me.lblTownsSelected.Caption
=
""
'On force le groupe à filtrer sur les communes et on le désactive
With
Me.fraSortBy
.Value
=
ByTown
.Enabled
=
False
End
With
'La variable de nouveau modèle est réinitialisée
m_blnIsNewTemplate =
False
End
Sub
La première chose que l'utilisateur aura sans doute envie de faire sera de consulter la liste, si liste il y a.
Le bouton cmdList portant deux légendes possibles, le bloc événementiel cmdList_Click est assez conséquent.
L'identification de ce qui va être exécuté lorsque l'on clique dessus est gérée par un Select Case basé sur sa légende.
Private
Sub
cmdList_Click
(
)
'Bouton Consulter/Modifier permettant d'afficher les modèles stockés ou de modifier un modèle
Dim
oLboDefined As
ListBox
Dim
oLboListToSet As
ListBox
Dim
lngTemplateID As
Long
Dim
SQLSelect As
String
Dim
lngCountTowns As
Long
Dim
I As
Long
Dim
J As
Long
Dim
T As
Long
Dim
lngaIDTown
(
) As
Long
Dim
lngIDTown As
Long
'Vérifie la légende du bouton Liste/Modifier
Select
Case
cmdList.Caption
Case
CMD_SHOWLIST
'Si l'on est en mode consultation
'On change la variable de module avec le flag correspondant
m_intUsingMode =
ShowTemplateTowns
'On construit une clause SQL permettant de lister tous les modèles exceptés celui par défaut
SQLSelect =
"SELECT T.TemplateID, T.TemplateName "
SQLSelect =
SQLSelect &
"FROM tblTemplatesAndTowns AS TT RIGHT JOIN tblOutputReportTemplates AS T ON TT.TemplateID = T.TemplateID "
SQLSelect =
SQLSelect &
"GROUP BY T.TemplateID, T.TemplateName "
SQLSelect =
SQLSelect &
"HAVING T.TemplateID > 1 "
SQLSelect =
SQLSelect &
"ORDER BY T.TemplateID;"
'On affecte le contrôle Listbox cible
With
Me.cboTemplateList
.RowSource
=
SQLSelect
.Value
=
vbNullString
End
With
'On met à jour la légende au bas de la liste avec aucune valeur
Me.lboTownsDefined.RowSource
=
vbNullString
'On gère l'affichage des contrôles
ShowHideControls True
Case
CMD_MODIFY_TEMPLATE
'Si l'on est en mode modification
'On change la variable de module avec le flag correspondant
m_intUsingMode =
UpdateTemplate
'On récupère l'ID du modèle
lngTemplateID =
Nz
(
Me.cboTemplateList
, 0
)
'S'il y a en a un, on établit la liste des communes selon le tri en cours
If
lngTemplateID Then
If
Me.fraSortBy
=
ByTown Then
SQLSelect =
"SELECT C.IDTown, TownName & ' (' & PostalCode & ')' AS City "
SQLSelect =
SQLSelect &
"FROM tblTowns AS C "
SQLSelect =
SQLSelect &
"ORDER BY C.TownName;"
Else
SQLSelect =
"SELECT C.IDTown, PostalCode & ' (' & TownName & ')' AS CP "
SQLSelect =
SQLSelect &
"FROM tblTowns AS C "
SQLSelect =
SQLSelect &
"ORDER BY C.PostalCode;"
End
If
'On affecte le contrôle ComboBox cible
Me.lboTownToSet.RowSource
=
SQLSelect
'On appose le nom du modèle sélectionné à la zone de texte
Me.txtTemplateName
=
Me.cboTemplateList.Column
(
1
)
'On efface le tableau des communes
Erase
lngaIDTown
(
)
'On affecte les variables objet à chacune des Listbox
Set
oLboDefined =
Me.lboTownsDefined
Set
oLboListToSet =
Me.lboTownToSet
'On compte le nombre d'éléments
lngCountTowns =
oLboDefined.ListCount
'Pour chaque commune appartenant à la liste des communes affectées au modèle,
'on alimente le tableau de type Long : lngaIDTown()
For
I =
0
To
lngCountTowns -
1
ReDim
Preserve
lngaIDTown
(
0
To
I)
lngaIDTown
(
I) =
oLboDefined.ItemData
(
I)
Next
I
'S'il y a des communes affectées (il peut ne pas y en avoir)
If
lngCountTowns Then
'Alors on compte le nombre de communes total
lngCountTowns =
oLboListToSet.ListCount
'Et pour chacune de ces communes dans la liste des communes à définir
For
I =
0
To
lngCountTowns -
1
With
oLboListToSet
'On récupère l'identifiant
lngIDTown =
.ItemData
(
I)
'Et pour chaque élément du tableau (représentant chaque commune affectée au modèle)
For
J =
LBound
(
lngaIDTown) To
UBound
(
lngaIDTown)
'Si elle correspond...
If
lngaIDTown
(
J) =
lngIDTown Then
'Alors on la met en surbrillance
.Selected
(
I) =
True
T =
T +
1
End
If
Next
J
End
With
Next
I
End
If
'On gère alors l'affichage des contrôles
ShowHideControls False
'On met à jour la légende au bas de la liste avec le nombre de communes sélectionnées
RefreshNumberOfTowns oLboListToSet, IS_SELECTED, False
, lngCountTowns
'On change l'état activé du bouton d'effacement des communes selon le cas
cmdClearSelection.Enabled
=
(
T >
0
)
Else
MsgBox
"Veuillez sélectionner le modèle à modifier..."
, vbExclamation
, "Aucun modèle"
End
If
End
Select
'On libère les varibel objet
Set
oLboDefined =
Nothing
Set
oLboListToSet =
Nothing
End
Sub
Dans la mesure où il n'y a rien à consulter, l'utilisateur va donc ajouter un modèle.
C'est le bouton cmdOpenFile qui s'en charge en affichant la boîte de dialogue Ouvrir.
Si un modèle est effectivement sélectionné, la procédure affiche toutes les communes disponibles, sinon, un message est affiché.
Private
Sub
cmdOpenFile_Click
(
)
'Bouton [...] permettant de sélectionner un modèle Word
Const
WORD_FILTER As
String
=
"Modèles Word 2007 (*.dotx)"
&
vbNullChar
&
"*.dotx"
&
vbNullChar
&
"Modèles Word 2007 avec macros (*.dotm)"
&
vbNullChar
&
"*.dotm"
&
vbNullChar
&
"Modèles Word 97-2003(*.dot)"
&
vbNullChar
&
"*.dot"
Dim
strTemplateName As
String
Dim
strTemplatePath As
String
Dim
SQLSelect As
String
On
Error
GoTo
L_ErrcmdOpenFile_Click
With
Application
'On appelle la fonction de sélection du fichier
If
OpenWordTemplateFile
(
Me.HWnd
, .hWndAccessApp
, "Sélection d'un modèle"
, .CurrentProject.Path
, WORD_FILTER, strTemplateName) =
False
Then
Err
.Raise
18
, "Sélection annulée"
, "Vous n'avez pas sélectionné de modèle à ajouter à votre liste."
End
If
End
With
If
Len
(
strTemplateName) =
0
Then
'Si aucun fichier n'a été sélectionné
MsgBox
"Vous devez sélectionner un document Word pour enrichir la liste des correspondances Modèle/Communes."
, vbExclamation
, "Sélection non valide"
Me.txtTemplateName
=
""
Else
'Si un fichier a bien été sélectionné...
'On récupère son chemin
strTemplatePath =
GetPathnameFromFullPath
(
strTemplateName, False
)
'On l'affecte au contrôle Label caché (pour le fun ; on aurait pu le mettre dans une variable)
Me.lblTemplatePath.Caption
=
strTemplatePath
'On affecte la zone de texte avec le nom du fichier
Me.txtTemplateName
=
GetFilenameFromFullPath
(
strTemplateName)
'On vérifie que le modèle n'a pas déjà été défini
If
IsTemplateAlreadyDefined
(
Me.txtTemplateName
, Me.lblTemplatePath.Caption
) Then
'Si oui, alors on désélectionne tous les items
UnselectAllItem lboTownToSet
'On lève l'erreur
err
.Raise
3022
, "Sélection incorrecte"
, "Le modèle '"
&
Me.txtTemplateName
&
"' que vous avez sélectionné a déjà été défini pour ce même dossier."
Else
'Sinon, selon l'option de tri...
With
Me.fraSortBy
If
.Value
=
ByTown Then
SQLSelect =
"SELECT C.IDTown, TownName & ' (' & PostalCode & ')' AS Town "
SQLSelect =
SQLSelect &
"FROM tblTowns AS C "
SQLSelect =
SQLSelect &
"ORDER BY C.TownName;"
Else
SQLSelect =
"SELECT C.IDTown, PostalCode & ' (' & TownName & ')' AS CP "
SQLSelect =
SQLSelect &
"FROM tblTowns AS C "
SQLSelect =
SQLSelect &
"ORDER BY C.PostalCode;"
End
If
.Enabled
=
True
End
With
'... on rempli la liste avec toutes les communes
Me.lboTownToSet.RowSource
=
SQLSelect
'On met à jour la légende au bas de la liste avec le nombre de communes disponibles
RefreshNumberOfTowns lboTownToSet, IS_AVAILABLE, False
'Et on modifie la valeur des variables en spécifiant que l'on ajoute un nouveau modèle
m_blnIsNewTemplate =
True
m_intUsingMode =
CreateNewTemplate
End
If
End
If
On
Error
GoTo
0
L_ExcmdOpenFile_Click
:
Exit
Sub
L_ErrcmdOpenFile_Click
:
MsgBox
Err
.Description
, 48
, Err
.Source
Resume
L_ExcmdOpenFile_Click
End
Sub
À tout instant, l'utilisateur peut fermer le formulaire sans avertissement (cela n'a pas été prévu ici).
Deux cas de figure existent pour les boutons de fermeture selon la légende qu'il porte.
Private
Sub
cmdClose_Click
(
)
'Selon la légende du bouton Fermer
Select
Case
cmdClose.Caption
Case
CMD_CLOSE
'Si c'est Fermer, on ferme le formulaire
DoCmd.Close
acForm, Me.Name
, acSaveYes
Case
CMD_RECLOSE
'Si c'est Refermer, on gère l'affichage des contrôles
ShowHideControls False
End
Select
End
Sub
Lorsque l'on est en mode consultation, la liste déroulante contient les modèles existants.
Dès la sélection d'un modèle depuis cette liste, l'événement AfterUpdate() est déclenché :
Private
Sub
cboTemplateList_AfterUpdate
(
)
'Zone de liste modifiable des modèles Word
'Une fois le modèle sélectionné, on affiche les communes qui lui sont affectées
RefreshTownList Me.cboTemplateList
, False
'On stocke l'ID du modèle dans un contrôle Label (pour le fun ; on aurait pu le mettre dans une variable)
Me.lblTempletaID.Caption
=
Me.cboTemplateList
'On change la légende du bouton Liste
With
cmdList
.Caption
=
CMD_MODIFY_TEMPLATE
.Enabled
=
True
End
With
'On change l'état des boutons Valider et Supprimer
cmdValidate.Enabled
=
False
cmdRemoveTemplate.Enabled
=
True
'Et celui du groupe d'options
fraSortBy.Enabled
=
True
'On vérifie que le modèle défini possède des communes
If
TemplateIsDefined
(
False
, Me.cboTemplateList
) =
False
Then
Me.lblTownsSelected.Caption
=
"Aucune commune n'a été définie pour ce modèle"
End
If
End
Sub
Dès qu'un modèle est affiché avec (ou sans) ses communes, l'utilisateur peut très bien souhaiter le supprimer.
Cette action est confirmée par un message.
Private
Sub
cmdRemoveTemplate_Click
(
)
'Bouton Supprimer autorisant la suppression d'un modèle
Dim
oLboDefined As
ListBox
Dim
SQLDelete As
String
Dim
lngTemplateID As
Long
On
Error
GoTo
L_ErrcmdRemoveTemplate_Click
'Message de confirmation
If
MsgBox
(
"Voulez-vous supprimer le modèle '"
&
Me.cboTemplateList.Column
(
1
) &
"' de l'application ?"
, vbQuestion
+
vbYesNo
+
vbDefaultButton2
, "Supprimer le modèle"
) =
vbYes
Then
'Si l'on confirme
Set
oLboDefined =
Me.lboTownsDefined
'On récupère l'ID du modèle
lngTemplateID =
Nz
(
Me.cboTemplateList
, 0
)
'S'il y en a un (ComboBox non Null)
If
lngTemplateID Then
'On supprime le modèle
SQLDelete =
"DELETE * FROM tblOutputReportTemplates WHERE TemplateID ="
&
lngTemplateID &
";"
CurrentDb.Execute
SQLDelete, dbFailOnError
'Puis on supprime sa définition de communes
SQLDelete =
"DELETE * FROM tblTemplatesAndTowns WHERE TemplateID ="
&
lngTemplateID &
";"
CurrentDb.Execute
SQLDelete, dbFailOnError
Else
MsgBox
"Veuillez sélectionner le modèle à supprimer..."
, vbExclamation
, "Aucun modèle"
End
If
'On rafraîchit la liste des modèles
Me.cboTemplateList.Requery
'La liste des communes est alors vide
oLboDefined.RowSource
=
vbNullString
'On met à jour la légende au bas de la liste avec aucune valeur
Me.lblTownsSelected.Caption
=
vbNullString
'On change l'état des boutons Consulter et Supprimer
Me.cmdList.Enabled
=
False
Me.cmdRemoveTemplate.Enabled
=
False
'Et celui du groupe d'options
Me.fraSortBy.Enabled
=
False
End
If
On
Error
GoTo
0
L_ExcmdRemoveTemplate_Click
:
Exit
Sub
L_ErrcmdRemoveTemplate_Click
:
MsgBox
Err
.Description
, 48
, Err
.Source
Resume
L_ExcmdRemoveTemplate_Click
End
Sub
Dans le même esprit, dès qu'un modèle est affiché avec ses communes, l'utilisateur peut très bien souhaiter effacer toutes ses communes pour lui en affecter d'autres lorsqu'il est en mode consultation, alors qu'en mode ajout ou en mode modification, il sélectionne ou désélectionne les communes à affecter au modèle Word en cours.
Quelle que soit l'opération, la validation est obligatoire pour prendre en compte sa demande.
Elle est régie par le biais du bouton cmdValidate et son événement Click dans lequel l'opération à effectuer est supervisée selon le mode d'utilisation en cours déterminé par la variable m_intUsingMode.
Private
Sub
cmdValidate_Click
(
)
'Bouton de validation du modèle
Dim
oDB As
DAO.Database
Dim
oRS As
DAO.Recordset
Dim
oLboTownToSet As
ListBox
Dim
lngTemplateID As
Long
Dim
SQLSelect As
String
Dim
SQLInsert As
String
Dim
SQLDelete As
String
Dim
lngCountTowns As
Long
Dim
I As
Long
Dim
T As
Long
Dim
lngaIDTown
(
) As
Long
Dim
lngIDTown As
Long
On
Error
GoTo
L_ErrcmdValidate_Click
'Sablier...
DoCmd.Hourglass
True
'Si ce n'est pas un nouveau modèle, on affecte l'ID à la variable
If
Not
m_blnIsNewTemplate Then
lngTemplateID =
Me.lblTempletaID.Caption
End
If
'S'il n'y a pas d'ID et que ce n'est pas un nouveau modèle
If
lngTemplateID =
0
And
m_blnIsNewTemplate =
False
Then
'On lève une erreur
err
.Raise
17
, "Aucun identifiant définissant le modèle n'a été défini..."
&
vbCrLf
&
vbCrLf
&
"Veuillez recommencer l'opération."
End
If
'On vide le tableau et on instancie la BDD
Erase
lngaIDTown
(
)
Set
oDB =
CurrentDb
'Si l'on est en mode Consultation...
If
m_intUsingMode =
ShowTemplateTowns Then
With
oDB
'On supprime toutes les communes du modèle (l'utilisateur à cliqué sur le bouton X)
SQLDelete =
"DELETE * FROM tblTemplatesAndTowns WHERE TemplateID = "
&
lngTemplateID &
";"
.Execute
SQLDelete, dbFailOnError
End
With
'On prévient que le modèle n'a plus de commune et on propose d'en affecter d'autres...
If
MsgBox
(
"Le modèle ne possède plus de communes associées."
&
vbCrLf
&
vbCrLf
&
"Voulez-vous lui affecter de nouvelles communes ?"
, vbQuestion
+
vbYesNo
, ""
) =
vbYes
Then
'On change le statut des variables
m_blnIsNewTemplate =
True
m_intUsingMode =
UpdateTemplate
'Puis on rafraîchit la liste avec les communes selon les paramètres de la procédure
RefreshTownList Me.cboTemplateList
, True
Else
'On change le statut des variables à NonDefini
m_intUsingMode =
NotDefined
'Et on modifie l'affichage des contrôles du formulaire
ShowHideControls False
End
If
Else
'Si l'on est dans un autre mode que Consultation...
'On affecte la variable de la liste des communes à affecter
Set
oLboTownToSet =
Me.lboTownToSet
'Compteur du tableau
T =
-
1
'On remplit le tableau avec les communes sélectionnées
With
oLboTownToSet
lngCountTowns =
.ListCount
If
lngCountTowns Then
For
I =
0
To
lngCountTowns -
1
If
.Selected
(
I) Then
T =
T +
1
ReDim
Preserve
lngaIDTown
(
T)
lngaIDTown
(
T) =
.ItemData
(
I)
End
If
Next
I
'Si aucune commune n'a été sélectionnée, on lève une erreur
If
T =
0
Then
Err
.Raise
17
, "Aucune commune sélectionnée"
, "Vous devez sélectionner les communes à affecter pour ce modèle !"
End
If
'Sinon, on démarre l'ajout du modèle
With
oDB
If
m_blnIsNewTemplate Then
'Si c'est un nouveau modèle... on l'ajoute et on récupère son ID
SQLSelect =
"SELECT TemplateID, TemplateName, TemplatePath, IsUsed FROM tblOutputReportTemplates;"
Set
oRS =
.OpenRecordset
(
SQLSelect, 2
)
With
oRS
.AddNew
lngTemplateID =
.Fields
(
"TemplateID"
).Value
.Fields
(
"TemplateName"
).Value
=
Me.txtTemplateName
.Fields
(
"TemplatePath"
).Value
=
Me.lblTemplatePath.Caption
.Fields
(
"IsUsed"
).Value
=
True
.Update
.Close
End
With
Else
'Sinon, on efface d'abord les communes déjà affectées à ce modèle
If
m_blnIsNewTemplate =
False
Then
SQLDelete =
"DELETE * FROM tblTemplatesAndTowns WHERE TemplateID = "
&
lngTemplateID &
";"
.Execute
SQLDelete, dbFailOnError
End
If
End
If
'Puis on les ajoute une par une selon les éléments du tableau
For
I =
0
To
T
SQLInsert =
"INSERT INTO tblTemplatesAndTowns (TemplateID, IDTown) VALUES ("
&
lngTemplateID &
","
&
lngaIDTown
(
I) &
");"
.Execute
SQLInsert, dbConsistent
Next
End
With
Else
'Si aucune commune n'existe pour ce modèle,on lève une erreur
err
.Raise
17
, "Aucune commune affectée à ce modèle n'a été définie..."
&
vbCrLf
&
vbCrLf
&
"Veuillez sélectionner des communes."
End
If
End
With
'On rafraîchit alors l'affichage des contrôles
ShowHideControls False
'On met à jour la légende au bas de la liste avec aucune valeur
Me.lblTownsSelected.Caption
=
vbNullString
'On change l'état du bouton d'effacement (des communes)
Me.cmdClearSelection.Enabled
=
(
T >
0
)
'On vide la zone de texte du nom du modèle
Me.txtTemplateName.Value
=
vbNullString
'On vide la liste
Me.lboTownToSet.RowSource
=
vbNullString
'On désactive les options de tri
Me.fraSortBy.Enabled
=
False
'On réinitialise la variable stipulant un nouveau modèle
m_blnIsNewTemplate =
False
End
If
On
Error
GoTo
0
L_ExcmdValidate_Click
:
'Sablier en pointeur
DoCmd.Hourglass
False
'Libération des objets
Set
oLboTownToSet =
Nothing
Exit
Sub
L_ErrcmdValidate_Click
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExcmdValidate_Click
End
Sub
En mode consultation comme en mode ajout, le tri sur les communes est possible pour une consultation plus aisée selon le cas.
Le groupe d'options est chargé de faire cette opération en appelant la procédure privée RefreshTownList.
Private
Sub
fraSortBy_AfterUpdate
(
)
'Tri des éléments (ici communes)
RefreshTownList Nz
(
Me.cboTemplateList
, 0
), False
End
Sub
Lorsque l'utilisateur sélectionne ou désélectionne une commune, la légende au-dessous des listes est rafraîchie en conséquence.
Cette procédure vérifie en parallèle que la commune sélectionnée ne l'a pas déjà été pour un autre modèle sans autres options.
Si vous souhaitez développer les répercutions de ce comportement, il est possible :
- d'empêcher/confirmer la sélection de cette commune (c'est le cas ici avec un message à confirmer);
- de ne lister que les communes qui n'ont pas déjà été sélectionnées ;
- de prévenir de choisir le modèle au moment de l'impression.
Private
Sub
lboTownToSet_AfterUpdate
(
)
'Rafraîchissement des informations sur le nombre de communes définies et confirmation des nouvelles sélections
Dim
lngCountTowns As
Long
Dim
oLboListToSet As
ListBox
Dim
lngItemSelected As
Long
Dim
strItemSeleted As
String
Set
oLboListToSet =
Me.lboTownToSet
With
oLboListToSet
lngItemSelected =
.ListIndex
If
.Selected
(
lngItemSelected) Then
lngCountTowns =
TownIsAlreadyAttached
(
.Column
(
0
))
strItemSeleted =
.Column
(
1
)
If
lngCountTowns Then
If
MsgBox
(
"La commune "
&
strItemSeleted &
" a déjà été définie pour "
&
PluralSingular
(
"un autre modèle"
, lngCountTowns) &
"."
&
vbCrLf
&
vbCrLf
&
"Voulez-vous toujours séléctionner cette commune ?"
, vbExclamation
+
vbYesNo
, "Attention"
) =
vbNo
Then
.Selected
(
lngItemSelected) =
False
End
If
End
If
End
If
RefreshNumberOfTowns oLboListToSet, IS_DEFINED, True
Set
oLboListToSet =
Nothing
End
With
End
Sub
Lorsque l'utilisateur souhaite supprimer toutes les communes d'un modèle pour lui en affecter d'autres, par exemple, il clique sur le bouton (pourvu d'une sorte de croix) situé sous la liste.
Cette opération n'est disponible qu'en mode consultation ; elle est à confirmer par un message :
Private
Sub
cmdClearSelection_Click
(
)
Dim
strMessage As
String
Dim
C As
Long
'Donne le focus à un champ invisible
Me.txtVoid.SetFocus
'Vérifie la légende du bouton Liste/Modifier
Select
Case
cmdList.Caption
Case
CMD_SHOWLIST
'Si l'on est en mode consultation
strMessage =
"Voulez-vous supprimer toutes les communes affectées au modèle"
&
vbCrLf
&
Me.cboTemplateList.Column
(
1
) &
vbCrLf
&
vbCrLf
&
"Vous devrez valider pour que cette action soit prise en compte."
If
MsgBox
(
strMessage, vbExclamation
+
vbYesNo
+
vbDefaultButton2
, "Confirmez l'action"
) =
vbYes
Then
'On désélectionne tous les éléments de la liste (ici les communes)
For
C =
0
To
lboTownToSet.ListCount
-
1
Me.lboTownToSet.Selected
(
C) =
False
Next
'On met à jour la légende au bas de la liste
RefreshNumberOfTowns lboTownToSet, IS_AVAILABLE, False
'On désactive le bouton Valider
Me.cmdValidate.Enabled
=
False
End
If
Case
CMD_MODIFY_TEMPLATE
'Si l'on est en mode modification
strMessage =
"Voulez-vous effacer toutes les communes sélectionnées pour le modèle"
&
vbCrLf
&
Me.cboTemplateList.Column
(
1
) &
" ?"
If
MsgBox
(
strMessage, vbExclamation
+
vbYesNo
+
vbDefaultButton2
, "Effacer la liste"
) =
vbYes
Then
'On active le bouton Valider en lui donnant le focus
With
Me.cmdValidate
.Enabled
=
True
.SetFocus
End
With
'On définit la propriété Contenu à NullString
Me.lboTownsDefined.RowSource
=
vbNullString
'On désactive les boutons Liste, Supprimer et le groupe d'options de tri.
Me.cmdList.Enabled
=
False
Me.cmdRemoveTemplate.Enabled
=
False
Me.fraSortBy.Enabled
=
False
End
If
End
Select
End
Sub
VI-C. Les fonctions et procédures locales▲
Il y a deux fonctions et quatre procédures locales dans la classe de ce formulaire.
Avant de pouvoir ajouter un modèle, il est nécessaire de contrôler s'il n'a pas déjà été créé.
En parallèle à cela, il existe aussi une vérification au chargement qui contrôle la présence de modèles (cas de première utilisation), mais également, lorsqu'un modèle existe, qu'il possède des communes.
Tout cela est supervisé par la fonction TemplateIsDefined() ci-après.
Dans cette fonction, les arguments Init et TemplateId servent respectivement :
- à la vérification des modèles au chargement du formulaire pour le premier ;
- et pour le second, si TemplateId possède une valeur, on considère alors qu'il s'agit de la vérification des communes d'un modèle donné.
Private
Function
TemplateIsDefined
(
ByVal
Init As
Boolean
, ByVal
TemplateId As
Long
) As
Boolean
'Fonction permettant de savoir si un modèle existe ou qu'il possède des communes
If
Init Then
TemplateIsDefined =
(
DCount
(
"TemplateID"
, "tblOutputReportTemplates"
) >
0
)
Else
If
TemplateId Then
TemplateIsDefined =
(
DCount
(
"TemplateID"
, "tblTemplatesAndTowns"
, "TemplateID="
&
TemplateId) >
0
)
Else
TemplateIsDefined =
(
DCount
(
"TemplateID"
, "tblTemplatesAndTowns"
) >
0
)
End
If
End
If
End
Function
À l'instar de la fonction ci-avant, la fonction TownIsAlreadyAttached permet de déterminer si une commune a déjà été attachée à un modèle auquel cas, un avertissement est affiché.
Private
Function
TownIsAlreadyAttached
(
ByVal
TownId As
Long
) As
Long
'Fonction permettant de savoir si une commune existe pour plusieurs modèles
If
TownId Then
TownIsAlreadyAttached =
DCount
(
"TemplateID"
, "tblTemplatesAndTowns"
, "IDTown="
&
TownId)
End
If
End
Function
Afin de rendre plus souple l'affichage et le masquage de certains contrôles ou de définir leur état activé ou non, la procédure ShowHideControls est mise en place.
Elle est appelée un grand nombre de fois dans presque tous les événements.
Private
Sub
ShowHideControls
(
ByVal
ShowIt As
Boolean
)
'Procédure de rafraîchissement des contrôles
Me.txtVoid.SetFocus
Me.shpTemplate.Visible
=
Not
ShowIt
Me.txtTemplateName.Visible
=
Not
ShowIt
Me.cmdOpenFile.Visible
=
Not
ShowIt
Me.shpTowns.Visible
=
Not
ShowIt
Me.lboTownToSet.Visible
=
Not
ShowIt
Me.shpListOfTemplates.Visible
=
ShowIt
Me.cboTemplateList.Visible
=
ShowIt
Me.lboTownsDefined.Visible
=
ShowIt
Me.cmdClearSelection.Visible
=
IIf
(
m_intUsingMode =
NotDefined, ShowIt, Not
ShowIt)
Me.lblTownsSelected.Caption
=
vbNullString
If
ShowIt Then
Me.lblWhatTodo.Caption
=
"Veuillez sélectionner le modèle Word pour connaître les communes associées :"
Else
Me.lblWhatTodo.Caption
=
"Veuillez sélectionner un modèle Word (*.dot) puis ses communes associées :"
End
If
With
cmdList
.Caption
=
IIf
(
ShowIt, CMD_MODIFY_TEMPLATE, CMD_SHOWLIST)
.Enabled
=
Not
ShowIt
End
With
Me.fraSortBy.Enabled
=
IIf
(
m_intUsingMode =
UpdateTemplate, True
, ShowIt)
cmdRemoveTemplate.Enabled
=
False
cmdValidate.Enabled
=
False
cmdClose.Caption
=
IIf
(
ShowIt, CMD_RECLOSE, CMD_CLOSE)
End
Sub
Pour tenir informé l'utilisateur des communes affectées, disponibles ou sélectionnées pour un modèle en cours, la procédure RefreshNumberOfTowns() est appelée.
Private
Sub
RefreshNumberOfTowns
(
ByVal
TargetList As
ListBox, ByVal
TownStatus As
String
, ByVal
ShowList As
Boolean
, Optional
ByVal
TotalCount As
Long
)
'Procédure de rafraîchissement des contrôles selon la liste passée en paramètre et le statut en cours
Dim
T As
Long
Dim
lngCount As
Long
'On donne le focus à un contrôle non visible
Me.txtVoid.SetFocus
'On énumère les communes sélectionnées
With
TargetList
For
T =
0
To
TargetList.ListCount
-
1
If
.Selected
(
T) Then
lngCount =
lngCount +
1
End
If
Next
End
With
'Selon le nombre, le bouton Valider est activé ou non
Me.cmdValidate.Enabled
=
(
lngCount >
0
)
If
lngCount =
0
Then
lngCount =
Me.lboTownsDefined.ListCount
End
If
'On met à jour la légende au bas de la liste en accordant en genre et en nombre
Me.lblTownsSelected.Caption
=
lngCount &
PluralSingular
(
"commune "
&
TownStatus, lngCount) &
IIf
(
TotalCount, "sur"
&
TotalCount &
PluralSingular
(
" est affectée "
, TotalCount) &
"à ce modèle"
, " pour ce modèle"
)
'On affecte l'état du bouton de suppression des communes
With
Me.cmdClearSelection
.Enabled
=
(
lngCount >
0
)
.Visible
=
ShowList
End
With
End
Sub
L'élément prépondérant du formulaire est avant tout l'affichage des communes d'un modèle donné.
Le procédure RefreshTownList se charge d'alimenter l'une ou l'autre liste selon le contexte.
En effet, il existe une liste chargée d'afficher toutes les communes lorsque l'utilisateur ajoute un modèle.
Cette même liste se remplit également avec ces communes, à la différence que certaines d'entre elles seront mises en surbrillance si l'on souhaite modifier un modèle.
Et puis il existe une autre liste, verrouillée cette fois, qui ne sert qu'à afficher les communes affectées à un modèle choisi.
En gros, le principe est le suivant :
s'il y a un TemplateId passé en paramètre, la procédure va ouvrir une requête avec la condition WHERE correspondante ;pour cette condition, il faut que le paramètre ResetListOfTowns soit à False.
Sinon, la liste est remplie avec toutes les communes selon le tri du groupe d'options.
Private
Sub
RefreshTownList
(
ByVal
TemplateId As
Long
, ByVal
ResetListOfTowns As
Boolean
)
'Procédure dédiées à rafraîchir la liste des communes
Dim
SQLSelect As
String
Dim
SQLWhere As
String
'S'il y a un ID et que l'on a pas effacé les communes
If
TemplateId <>
0
And
ResetListOfTowns =
False
Then
'On rempli la liste avec les communes du modèle selon le tri
If
Me.fraSortBy
=
ByTown Then
SQLSelect =
"SELECT C.IDTown, C.TownName & ' (' & C.PostalCode & ')' AS Town "
SQLSelect =
SQLSelect &
"FROM tblTemplatesAndTowns AS TT LEFT JOIN tblTowns AS C ON TT.IDTown = C.IDTown "
SQLSelect =
SQLSelect &
"WHERE TT.TemplateID="
&
TemplateId &
" "
SQLSelect =
SQLSelect &
"GROUP BY C.IDTown, C.TownName & ' (' & C.PostalCode & ')', C.TownName "
SQLSelect =
SQLSelect &
"ORDER BY C.TownName;"
Else
SQLSelect =
"SELECT C.IDTown, C.PostalCode & ' (' & C.TownName & ')' AS CP "
SQLSelect =
SQLSelect &
"FROM tblTemplatesAndTowns AS TT LEFT JOIN tblTowns AS C ON TT.IDTown = C.IDTown "
SQLSelect =
SQLSelect &
"WHERE TT.TemplateID="
&
TemplateId &
" "
SQLSelect =
SQLSelect &
"GROUP BY C.IDTown, C.PostalCode & ' (' & C.TownName & ')', C.PostalCode "
SQLSelect =
SQLSelect &
"ORDER BY C.PostalCode;"
End
If
Else
'Sinon, on rempli avec toutes les communes selon le tri
If
Me.fraSortBy
=
ByTown Then
SQLSelect =
"SELECT IDTown, TownName & ' (' & PostalCode & ')' AS Town "
SQLSelect =
SQLSelect &
"FROM tblTowns "
SQLSelect =
SQLSelect &
"ORDER BY TownName;"
Else
SQLSelect =
"SELECT IDTown, PostalCode & ' (' & TownName & ')' AS CP "
SQLSelect =
SQLSelect &
"FROM tblTowns "
SQLSelect =
SQLSelect &
"ORDER BY PostalCode;"
End
If
End
If
'Si l'on est en mode consultation
If
m_intUsingMode =
ShowTemplateTowns Then
'On rempli la liste des communes déjà définies
Me.lboTownsDefined.RowSource
=
SQLSelect
Else
'Sinon, on rempli la liste des communes à définir ou compléter
Me.lboTownToSet.RowSource
=
SQLSelect
'Si ce n'est pas un nouveau modèle...
If
Not
m_blnIsNewTemplate Then
'...alors, on rafraîchit l'affichage des contrôles
ShowHideControls True
End
If
End
If
'Et selon que ce sont des communes définies ou disponibles (à affecter), on change la légende au bas de la liste
RefreshNumberOfTowns lboTownsDefined, IIf
(
m_blnIsNewTemplate, IS_AVAILABLE, IS_DEFINED), (
m_intUsingMode =
ShowTemplateTowns)
'Le bouton de consultation est activé
cmdList.Enabled
=
True
End
Sub
La procédure UnselectAllItem, comme son nom l'indique, est dédiée à désélectionner tous les éléments de la liste passée en paramètre.
En parallèle à cela, certains contrôles sont réinitialisés.
Private
Sub
UnselectAllItem
(
ByRef
TargetList As
ListBox)
'Procédure dédiée à désélectionner tous les élements d'une liste
Dim
I As
Long
With
TargetList
For
I =
0
To
TargetList.ListCount
-
1
.Selected
(
I) =
False
Next
End
With
'On réinitialise les contrôles et les variables
Me.txtTemplateName
=
vbNullString
Me.lblTemplatePath.Caption
=
vbNullString
Me.lblTempletaID.Caption
=
vbNullString
m_intUsingMode =
NotDefined
m_blnIsNewTemplate =
False
End
Sub
C'en est fini du code pour la classe du formulaire.
Maintenant, il reste quelques fonctions à ajouter, mais vous allez les écrire (ou plutôt les copier) dans un module externe...
VII. Les modules externes▲
Les autres fonctions et procédures exploitées par l'application font partie intégrante du projet.
Vous devez donc ajouter le module spécifié ci-après avec le code qui le compose.
VII-A. Le Module basFunctions▲
Ajoutez un nouveau module que vous nommez basFunctions.
Le bloc de déclarations contient la structure m_tyOpenFileName que vous connaissez certainement déjà.
'**********************************************************************
' Project : WordTemplateManager
' Module : basFunctions
' Type : Module
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Review :
' Review date :
' Purpose : Module used to provide special functions for application
'
'**********************************************************************
Option
Compare Database
Option
Explicit
Private
Type
m_tyOpenFileName
lStructSize As
Long
hwndOwner As
Long
hInstance As
Long
lpstrFilter As
String
lpstrCustomFilter As
String
nMaxCustFilter As
Long
nFilterIndex As
Long
lpstrFile As
String
nMaxFile As
Long
lpstrFileTitle As
String
nMaxFileTitle As
Long
lpstrInitialDir As
String
lpstrTitle As
String
Flags As
Long
nFileOffset As
Integer
nFileExtension As
Integer
lpstrDefExt As
String
lCustData As
Long
lpfnHook As
Long
lpTemplateName As
String
End
Type
Private
Declare
Function
GetOpenFileName Lib
"comdlg32.dll"
Alias "GetOpenFileNameA"
(
pOpenfilename As
m_tyOpenFileName) As
Long
La fonction OpenWordTemplateFile() récupère le nom complet d'un fichier sélectionné depuis la boîte de dialogue Ouvrir.
Public
Function
OpenWordTemplateFile
(
ByVal
HWnd As
Long
, ByVal
HInst As
Long
, ByVal
Title As
String
, ByVal
InitialDir As
String
, ByVal
Filter
As
String
, ByRef
SelectedFile As
String
) As
Double
'---------------------------------------------------------------------------
' Function : OpenWordTemplateFile
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Purpose : This Function is used to select a file from the FileDdialogBox
'...........................................................................
' Parameters : HWnd : Handle de la fenêtre appelante
' HInst : Handle de l'instance
' Title : Titre de la fenêtre
' InitialDir : Dossier de départ
' Filter : Filtre sur fichier de type
' SelectedFile : Fichier sélectionné
' Return Codes : Double = Taille du fichier en octets
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
OFName As
m_tyOpenFileName
With
OFName
.lStructSize
=
Len
(
OFName)
.hwndOwner
=
HWnd
.hInstance
=
HInst
.lpstrFilter
=
Filter
.lpstrFile
=
Space
$(
254
)
.nMaxFile
=
255
.lpstrFileTitle
=
Space
$(
254
)
.nMaxFileTitle
=
255
.lpstrInitialDir
=
InitialDir
.lpstrTitle
=
Title
.Flags
=
0
If
GetOpenFileName
(
OFName) Then
SelectedFile =
Left
$(
.lpstrFile
, InStrRev
(
.lpstrFile
, vbNullChar
) -
1
)
OpenWordTemplateFile =
FileLen
(
SelectedFile)
Else
OpenWordTemplateFile =
0
End
If
End
With
End
Function
La fonction AddDirSeparator() ajoute une barre de fraction inversée pour délimiter un chemin.
Public
Function
AddDirSeparator
(
ByVal
PathName As
String
, Optional
ByVal
Separator As
String
=
"\"
) As
String
'---------------------------------------------------------------------------
' Function : AddDirSeparator
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Purpose : This Function is used to add a path separator
'...........................................................................
' Parameters : PathName : Chemin à formater
' Separator : Séparateur à apposer
' Return Codes : String = Chemin formaté
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
If
Right
$(
PathName, 1
) <>
Separator Then
AddDirSeparator =
PathName &
Separator
Else
AddDirSeparator =
PathName
End
If
End
Function
La fonction GetPathnameFromFullPath() retourne le nom du chemin d'un chemin complet.
Public
Function
GetPathnameFromFullPath
(
ByVal
PathName As
String
, KeepBackSlash As
Boolean
, Optional
ByVal
Separator As
String
=
"\"
) As
String
'---------------------------------------------------------------------------
' Function : GetPathnameFromFullPath
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Purpose : This Function is used to get the path from a full path
'...........................................................................
' Parameters : PathName : Chemin à examiner
' KeepBackSlash : True si l'on conserve le séparateur de fin
' Separator : Séparateur à apposer
' Return Codes : String = Chemin du fichier
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
If
InStr
(
1
, PathName, Separator, 1
) Then
GetPathnameFromFullPath =
Left
$(
PathName, InStrRev
(
PathName, Separator) -
IIf
(
KeepBackSlash, 0
, 1
))
End
If
End
Function
La fonction GetFilenameFromFullPath() retourne le nom du fichier d'un chemin complet.
Public
Function
GetFilenameFromFullPath
(
ByVal
PathName As
String
, Optional
ByVal
Separator As
String
=
"\"
) As
String
'---------------------------------------------------------------------------
' Function : GetFilenameFromFullPath
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Purpose : This Function is used to get the file from a full path according to separator value
'...........................................................................
' Parameters : PathName : Chemin à examiner
' Separator : Séparateur à identifier
' Return Codes : String = Nom du fichier
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
If
InStr
(
1
, PathName, Separator, 1
) Then
GetFilenameFromFullPath =
Mid
$(
PathName, InStrRev
(
PathName, Separator) +
1
)
End
If
End
Function
La fonction NotInList() permet de réagir avec l'événement NotInList des listes déroulantes.
Public
Function
NotInList
(
ByRef
F As
Form, ByRef
NewData As
String
, ByVal
ItemSubject As
String
) As
Long
'---------------------------------------------------------------------------
' Function : NotInList
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Purpose : This Function is used to show a message when a data is not belong to a Listbox
'...........................................................................
' Parameters : F : Formulaire cible
' NewData : Nouvelle valeur
' ItemSubject : Sujet du champ concerné
' Return Codes : Long = acDataErrContinue if Event is raised
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
MsgBox
ItemSubject &
" '"
&
NewData &
"' ne fait pas partie de la liste !"
, 48
, "Choix incorrect"
NotInList =
acDataErrContinue
End
Function
La fonction PluralSingular() transforme une occurrence au singulier ou au pluriel selon un tableau de correspondance prédéfini.
Public
Function
PluralSingular
(
ByVal
TextToChange As
String
, ByVal
CountData As
Long
, Optional
ByVal
CharBefore As
Integer
=
32
, Optional
ByVal
CharAfter As
Integer
=
0
) As
String
'---------------------------------------------------------------------------
' Function : PluralSingular
' DateTime : 13/05/2014
' Author : Jean-Philippe AMBROSINO
' Purpose : This Function is used to change the plural or singular of a given sentence
'...........................................................................
' Parameters : TextToChange : Texte à mettre au pluriel
' CountData : Caractère à insérer avant
' CharAfter : Caractère à insérer après
' Return Codes : String = Valeur retournée
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Const
SINGULAR_WORDS As
String
=
"le;la;du;dela;un;une;à;lequel;laquelle;ce;cet;cette;quelque;quel;quelle;a;été;est"
Const
PLURAL_WORDS As
String
=
"les;les;des;des;des;des;aux;lesquels;lesquelles;ces;ces;ces;quelques;quels;quelles;ont;été;sont"
Dim
straSingKeywords
(
) As
String
Dim
straPlurKeywords
(
) As
String
Dim
straSentence
(
) As
String
Dim
strNewWord As
String
Dim
strCurrentWord As
String
Dim
strSingKeyword As
String
Dim
strNewSentence As
String
Dim
blnKWfound As
Boolean
Dim
I As
Integer
Dim
W As
Integer
If
CountData >
1
Then
TextToChange =
Replace
(
TextToChange, " de la "
, " dela "
, , , 1
)
straSentence =
Split
(
TextToChange, " "
)
straSingKeywords =
Split
(
SINGULAR_WORDS, ";"
)
straPlurKeywords =
Split
(
PLURAL_WORDS, ";"
)
For
W =
LBound
(
straSentence) To
UBound
(
straSentence)
strCurrentWord =
straSentence
(
W)
If
Len
(
strCurrentWord) Then
For
I =
LBound
(
straSingKeywords) To
UBound
(
straSingKeywords)
strSingKeyword =
straSingKeywords
(
I)
If
StrComp
(
strCurrentWord, strSingKeyword, 0
) =
0
Then
strNewWord =
straPlurKeywords
(
I)
blnKWfound =
True
Exit
For
End
If
Next
If
blnKWfound Then
strNewSentence =
strNewSentence &
strNewWord &
Chr
(
32
)
Else
strCurrentWord =
strCurrentWord &
"s "
strNewSentence =
strNewSentence &
strCurrentWord
End
If
End
If
blnKWfound =
False
Next
Else
strNewSentence =
TextToChange
End
If
PluralSingular =
IIf
(
CharBefore, Chr
(
CharBefore), ""
) &
strNewSentence &
IIf
(
CharAfter, Chr
(
CharAfter), ""
)
End
Function
Une fois ce bloc terminé, pointez le menu Debogage et cliquez sur Compiler " Nom du projet ".
Aucune erreur ne doit apparaître.
Débogage du projet
Vous avez ici, terminé la conception du formulaire et le code qui l'accompagne, vous pouvez donc l'exécuter pour vos premiers tests.
Pour pouvoir tester, plusieurs solutions d'offrent à vous :
- créer une macro avec l'instruction OuvriFormulaire ;
- créer une procédure en VBA avec la méthode OpenForm de l'objet DoCmd ;
- ouvrir le formulaire en mode création et appuyer sur la touche F5 ;
- si le formulaire est fermé, l'ouvrir depuis le volet d'exploration.
DoCmd.OpenForm
"Nom du formulaire"
, acNormal, , , , acDialog
VIII. Mise en exécution▲
Considérant que vous êtes censé n'avoir aucun modèle stocké (excepté le modèle par défaut, mais il n'est pas examiné), il est nécessaire d'afficher une information conséquente, traduite par ce message à l'ouverture :
Quoi qu'il en soit, qu'il y ait ou non ce message, le formulaire s'ouvre avec cet aspect.
Si l'utilisateur clique sur le bouton parcourir (représenté par...), la boîte de dialogue Ouvrir est affichée; il est alors invité à sélectionner un fichier Word de format 97-2003 ou 2007.
Si finalement il annule, la boîte se referme et un message l'informe en conséquence de son action.
Si l'utilisateur clique sur le bouton Consulter la liste,
et qu'ensuite il sélectionne un modèle,
la liste des communes affectées à ce dernier est affichée selon l'ordre de tri du groupe d'options.
Si l'utilisateur clique sur le bouton Modifier ce modèle, le même modèle est ré-affiché avec l'ensemble des communes listées selon l'ordre de tri du groupe d'options et dont celles qui lui sont affectées sont en surbrillance.
Si entre temps, l'utilisateur a effectivement ajouté ou supprimé au moins une ou plusieurs communes et qu'il clique sur le bouton Valider,
le formulaire se réinitialise (prêt à une opération similaire ou un ajout).
Il se présente en fait comme lors du premier chargement.
Pour chaque modèle listé, s'il existe un jeu de communes, celles-ci sont listées.
L'utilisateur peut alors supprimer les communes affectées au modèle pour le cas où il souhaiterait lui en affecter d'autres.
Cette action est confirmée par un message.
Durant cette action, le message informe alors que le modèle ne possède plus de communes et propose à l'utilisateur d'en ajouter.
Selon sa réponse, le formulaire s'affichera en conséquence.
S'il répond oui, le modèle est prêt à recevoir les communes que vous voulez lui affecter.
Il n'aura plus qu'à valider s'il veut valider son modèle.
S'il ne le fait pas, le modèle restera stocké sans communes et le formulaire retournera à son état de premier chargement.
L'utilisation reste somme toute très simple.
Elle peut toutefois être améliorée sur certains points, comme ceux que j'ai évoqués dans les paragraphes précédents.
IX. Mise en pratique du projet▲
Une fois que vous avez paramétré vos modèles, il est possible de tester en mode réel, ce que vous permet ce tutoriel.
Le principe, rappelez-vous, consiste à lancer une impression sur une fiche spécifique qui contient un enregistrement qui a été défini pour gérer le modèle cible (ici, des communes).
Si aucune commune ne peut être trouvée par rapport à celle de la fiche à imprimer, alors le modèle identifié 1 sera utilisé.
Sinon, ce sera le modèle qui aura été paramétré qui sera utilisé.
Dans les blocs de code qui vont suivre, j'ai écrit une routine assez basique qui est déclenchée par l'événement Click d'un bouton nommé cmdPrintToWord.
Considérez également que ce code doit être adapté pour votre propre projet d'une part et qu'il est incomplet d'autre part.
Scénario du déroulement :
- On vérifie qu'une commune est sélectionnée et si tel est le cas ;
- On recherche le modèle selon la commune ;
- Puis on instancie de l'application Word ;
- Et on affecte du modèle à une variable objet de type document ;
- On affecte ensuite la collection de signets à une autre variable ;
- On vérifie par une fonction que tous les signets existent ;
- Le document se voit rempli ses signets avec la valeur des champs ;
- Une fois rempli, on propose d'imprimer ;
- Selon la réponse, on imprime et on quitte ou on affiche l'instance Word (prévoir un SetForeGround()).
Private
Sub
cmdPrintToWord_Click
(
)
Dim
oWordApp As
Word.Application
Dim
oDoc As
Word.Document
Dim
oBookmarks As
Word.Bookmarks
Dim
strErrMessage As
String
Dim
strTemplateFilename As
String
Dim
lngIDTown As
Long
Dim
lngIDRecord As
Long
On
Error
GoTo
L_ErrcmdPrintToWord
lngIDTown =
Nz
(
Me!cboTownList, 0
)
'Si une commune est sélectionnée
If
lngIDTown Then
'Récupération de l'ID de la fiche en cours
lngIDRecord =
Me!IDRecord
'On recherche d'abord leu modèle selon la commune...
If
GetWordTemplateFilename
(
lngIDTown, strTemplateFilename, strErrMessage) =
False
Then
'Une erreur est levée en cas d'échec
Err
.Raise
3021
, "Erreur interne"
, "Une erreur est survenue pendant que le programme recherchait le modèle cible :"
&
vbCrLf
&
strErrMessage
End
If
'Instanciation de l'application Word
Set
oWordApp =
New
Word.Application
With
oWordApp
'Affectation du modèle à l'objet document
Set
oDoc =
.Documents.Add
(
Template:=
strTemplateFilename, NewTemplate:=
False
, DocumentType:=
0
)
'Affectation de la collection de signets
Set
oBookmarks =
oDoc.Bookmarks
'Vérification des signets
If
TemplateHasAllItsBookmarks
(
oDoc, oBookmarks, strErrMessage) =
False
Then
'[...]
'Code non développé ici
'[...]
'Une erreur est levée en cas d'échec
Err
.Raise
17
, "Signets manquants"
, "Un ou plusieurs signets n'ont pas été trouvés dans le modèle."
&
vbCrLf
&
vbCrLf
&
"Veuillez vous assurer que le modèle n'a pas été modifié."
End
If
'Le modèle est ouvert et on remplit les signets avec la valeur des champs
If
FillBookmarksFromRecordset
(
oDoc, oBookmarks, strErrMessage) =
False
Then
'[...]
'Code non développé ici
'[...]
'Une erreur est levée en cas d'échec
Err
.Raise
17
, "Remplissage échoué"
, "L'opération d'alimentation du document a échoué pour la raison suivante :"
&
vbCrLf
&
strErrMessage
End
If
'Impression effective du document
If
MsgBox
(
"La génération est terminée :"
&
vbCrLf
&
vbCrLf
&
"Voulez-vous imprimer le document ?"
, vbQuestion
+
vbYesNo
+
vbDefaultButton2
, "Imprimer ou garder"
) =
vbYes
Then
'On imprime
oDoc.PrintOut
'On quitte Word
.Quit
Else
'On affiche l'instance Word
.Visible
=
True
End
If
End
With
Else
MsgBox
"Veuillez sélectionner une commune avant d'imprimer cette fiche."
, vbExclamation
, "Commune requise"
End
If
On
Error
GoTo
0
L_ExcmdPrintToWord
:
Set
oDoc =
Nothing
Set
oBookmarks =
Nothing
Exit
Sub
L_ErrcmdPrintToWord
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
oWordApp.Quit
Set
oWordApp =
Nothing
Resume
L_ExcmdPrintToWord
End
Sub
La fonction GetWordTemplateFilename() exécute une requête pour récupérer le modèle en fonction de la commune (pour ce cas précis).
Si le modèle n'est pas trouvé, c'est le modèle par défaut qui sera utilisé.
Private
Function
GetWordTemplateFilename
(
ByVal
IDTown As
Long
, ByRef
WordTemplate As
String
, ByRef
ErrMessage As
String
) As
Boolean
'Fonction permettant de récupérer le modèle selon la commune sélectionnée
Dim
oRS As
DAO.Recordset
Dim
strSQL As
String
Dim
strTemplatePath As
String
Dim
strTemplateName As
String
'La requête recherche le modèle en fonction de la ville
On
Error
GoTo
L_ErrGetWordTemplateFilename
strSQL =
"SELECT M.TemplatePath, M.TemplateName "
strSQL =
strSQL &
"FROM tblOutputReportTemplates AS M LEFT JOIN tblTemplatesAndTowns AS L ON M.TemplateID = L.TemplateID "
strSQL =
strSQL &
"WHERE (((M.IsUsed)=True) AND ((L.IDTown)="
&
IDTown &
"));"
Set
oRS =
CurrentDb.OpenRecordset
(
strSQL, dbOpenSnapshot)
If
Not
oRS.EOF
Then
'On récupère le chemin complet du modèle
strTemplatePath =
oRS.Fields
(
"TemplatePath"
).Value
strTemplateName =
oRS.Fields
(
"TemplateName"
).Value
'On ferme le Recordset
oRS.Close
Else
'Si il n'y a pas de correspondance, on prend le modèle par défaut
strSQL =
"SELECT TemplatePath, TemplateName FROM tblOutputReportTemplates WHERE TemplateID = 1;"
Set
oRS =
CurrentDb.OpenRecordset
(
strSQL, dbOpenSnapshot)
'On récupère le chemin complet du modèle
strTemplatePath =
Nz
(
oRS.Fields
(
"TemplatePath"
).Value
, ""
)
strTemplateName =
Nz
(
oRS.Fields
(
"TemplateName"
).Value
, ""
)
'On ferme le Recordset
oRS.Close
End
If
'Le paramètre passé par référence prend la valeur trouvée
WordTemplate =
AddDirSeparator
(
strTemplatePath) &
strTemplateName
'Si le modèle est inexistant
If
Len
(
Dir
(
WordTemplate, vbNormal)) =
0
Then
'On alimente le message d'erreur
ErrMessage =
"Le modèle '"
&
strTemplateName &
"' n'existe pas dans le dossier cible !"
Else
'Sinon, aucun message d'erreur
ErrMessage =
vbNullString
End
If
'La fonction prend True ou False selon la longueur du message d'erreur
GetWordTemplateFilename =
(
Len
(
ErrMessage) =
0
)
On
Error
GoTo
0
L_ExGetWordTemplateFilename
:
Exit
Function
L_ErrGetWordTemplateFilename
:
'L'erreur est remontée à la fonction appelante
ErrMessage =
"("
&
Err
.Number
&
") "
&
Err
.Description
Resume
L_ExGetWordTemplateFilename
End
Function
La fonction TemplateHasAllItsBookmarks() est chargée de parcourir la collection de signets du document pour déterminer s'ils sont tous présents et qu'aucun n'a été supprimé.
N.B. les signets du document sont stockés dans une table et c'est de cette table que l'on effectue la comparaison.
Private
Function
TemplateHasAllItsBookmarks
(
ByRef
Doc As
Word.Document
, ByRef
BookmarksColl As
Word.Bookmarks
, ByRef
ErrMessage As
String
) As
Boolean
'Fonction non documentée
TemplateHasAllItsBookmarks =
True
End
Function
La fonction FillBookmarksFromRecordset() est chargée de remplir le document depuis un Recordset qui est alimenté avec un jeu de données correspondant à l'IDRecord de la fiche.
Private
Function
FillBookmarksFromRecordset
(
ByVal
IDRecord As
Long
, ByRef
Doc As
Word.Document
, ByRef
BookmarksColl As
Word.Bookmarks
, ByRef
ErrMessage As
String
) As
Boolean
'Fonction non documentée
FillBookmarksFromRecordset =
True
End
Function
X. Conclusion▲
Ce petit tutoriel permettra aux personnes exigeantes à l'égard des applications de gestion et nécessitant des impressions sur des modèles Word d'apporter un plus à leur projet...
Si le besoin tourne autour du même thème, tant mieux, vous n'aurez pas de grosses modifications à apporter, mais dans le cas contraire, l'adaptation ne devrait pas poser trop de problèmes.
Je précise que j'ai volontairement modifié et simplifié quelques instructions pour que le code soit plus compréhensible pour tous...
De ce fait, les utilisateurs disposant d'un niveau avancé s'en apercevront et pourront adapter ces blocs selon leur propre méthode de développement.
XI. Sujets corrélatifs▲
Il existe quelques articles traitant de l'échange de données entre applications.
L'article Le publipostage avec AccessLe publipostage avec Access peut être intéressant à consulter, notamment concernant la manipulation des signets (bookmarks).
XII. Remerciements▲
Je tiens à remercier tous celles et ceux qui ont participé à la relecture de ce document en y incluant leurs remarques et en particulier :
jacques_jean pour la relecture corrective,
f-leb pour la gestion et le suivi,
sans oublier
Nono40 pour son outil permettant la rédaction des articles.