I. Avant-propos▲
Ce document a pour but de vous montrer comment concevoir un assistant de présaisie des données permettant à un panel d'utilisateurs de saisir les informations nécessaires à la mise à jour d'une base de données centrale située sur un serveur distant.
L'idée de ce tutoriel est née d'une situation existante pour laquelle j'ai été confronté à concevoir le même prototype d'outil que j'ai ici largement simplifié pour ne pas rendre la mise en œuvre trop complexe, notamment pour les débutants.
I-A. Niveau▲
Vous devez être relativement à l'aise avec Microsoft Access et connaître la conception avancée 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.
Ce tutoriel s'adresse plus particulièrement aux personnes qui possèdent déjà de bonnes 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 (Langue Argyronet) par MP.
Si votre question est, disons publique et technique, 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 projet.
Notez que j'ai cherché avant tout à simplifier l'ensemble pour que tout un chacun puisse l'assimiler de façon aisée.
I-D. Contexte métier▲
Le projet présenté ici concerne des données relatives à des prestations de service supervisées par certains sites pour certaines communes. Ces prestations sont soumises à des contrats nantis d'une durée de validité. Libre à vous de vous en inspirer pour votre propre situation métier ou tout autre développement particulier.
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, le projet présenté ici ne peut être mis en application que si vous êtes dans une situation où un besoin de centralisation des données est nécessaire, et qu'il faut préparer les données du serveur d'une part, mais aussi que votre application de gestion soit exploitée par différents sites où l'activité professionnelle (pour le cas présenté ici) exerce sur les communes spécifiques, ces dernières étant associées ou non à des contrats.
Bien entendu, il faut considérer que la présentation de ce projet reste surtout et avant tout théorique, car je suis bien conscient qu'il est difficile de se mettre dans une situation identique à celle qui m'a poussé à créer cet assistant.
Ceci dit, l'objectif est surtout de comprendre les points culminants de ce tutoriel à savoir :
- voir comment il est relativement aisé d'enchaîner dynamiquement l'ouverture de formulaires à l'image de ce que vous rencontrez lorsque vous lancez un programme d'installation ;
- approfondir vos connaissances concernant plus particulièrement l'usage de procédures génériques associées à des événements, qui évite ainsi la redondance de code et donc par voie de conséquence, une maintenance plus aisée ;
- voir également comment il est possible de vérifier qu'un sous-formulaire est complété comme attendu au moment de la saisie d'une part, et au moment de la validation globale d'autre part. J'entends par validation globale, les comportements associés au passage à l'écran précédent ou à l'écran suivant qui se traduit par le fait de conserver ou non le contenu (confirmé par un message).
D'une manière générale, du fait que cet assistant est destiné à des non-informaticiens, on fait en sorte de rendre les messages affichés qui concernent la sauvegarde, le soient de manière optimiste. En d'autres termes, si l'utilisateur n'est pas en mesure de renseigner une valeur, qu'il ne soit pas obligé de le faire.
II-B. De quoi avez-vous besoin ?▲
Pour mettre en œuvre ce projet, vous n'avez besoin que de Microsoft Access dans une version supérieure ou égale à la version 2000. Il n'y a pas de référence particulière autre que celles définies par défaut dans Microsoft Access lors de la création de nouveaux projets.
Libre à vous de préférer DAO 3.6 ou le nouveau moteur existant depuis la version 2007.
III. Présentation du projet▲
Le projet est ici et expressément une base de données Access non scindée. Je précise cela, car il est plus facile de distribuer une application dans cette configuration d'une part, et cela évite les problèmes d'installation d'autre part. Par ailleurs, du fait du côté volatil de l'application si je puis dire, il n'est pas nécessaire de s'investir dans une structure frontale/dorsale.
III-A. Structure fonctionnelle des formulaires▲
Dans le projet présenté ici, les éléments prépondérants sont bien entendu les formulaires. Ils sont au nombre de onze. Parmi ces formulaires, figure un formulaire d'accueil qui propose et énumère ce qui va être fait et un formulaire de fin qui récapitule la saisie.
Entre les deux, figurent tous les autres formulaires de saisie des données utilisateur qu'ils soient formulaires simples ou continus.
Concernant les formulaires de saisie, chacun d'entre eux est pourvu de boutons qui permettent de créer ou de supprimer un enregistrement, et également, d'accéder au formulaire précédent ou au formulaire suivant.
Pour chacun des formulaires qui contiennent des sous-formulaires, sont présentes deux étiquettes qui pour l'une, permet de savoir si le formulaire et dûment complété ou non et pour l'autre, le nombre d'enregistrements existants.
Il est rappelé ici que les écrans doivent être construits de telle sorte à ce qu'ils soient compris par des personnes qui n'ont pas l'habitude d'utiliser l'outil informatique et à qui l'on demande de saisir des informations avec un mode qualifié de simple.
IV. Les tables du projet▲
Au niveau des tables, du fait que ce projet concerne dans son côté métier l'exploitation de prestations de services par rapport à des communes, certaines tables contiennent des valeurs prédéfinies.
Dans l'exemple présenté, trois tables contiennent respectivement l'ensemble des communes, des départements et des régions pour la France.
Les autres tables contiennent des valeurs qui concernent les types de contrats ou les privilèges utilisateur. Si vous décidez de mettre en œuvre ce projet dans son intégralité, il vous faudra sans doute procéder à des adaptations selon votre propre contexte professionnel.
IV-A. La structure des tables de données fixes▲
IV-A-1. tbl_ListeDepartements (les départements*)▲
Cette table possède trois champs :
- le champ IDDepartement de type Texte limité à trois caractères ;
- le champ Departements de type Texte limité à soixante-quatre caractères ;
- le champ IDRegion de type numérique Entier long .
La clé primaire est affectée au champ IDDepartement.
IV-A-2. tbl_ListeDesCommunes (Les communes*)▲
Cette table possède cinq champs :
- le champ IDCommune représenté par un identifiant de type Numérotation automatique ;
- le champ CodeINSEE de type Texte limité à cinq caractères ;
- le champ NomCommune de type Texte limité à soixante-quatre caractères ;
- le champ CodePostal de type Texte limité à cinq caractères ;
- le champ IDDepartement de type Texte limité à trois caractères .
La clé primaire est affectée aux champs CodeINSEE + NomCommune (CodeINSEE indexé sans doublons).
IV-A-3. tbl_ListeDesRegions (les régions*)▲
Cette table possède deux champs :
- le champ IDRegion de type Numérotation automatique ;
- le champ Region de type Texte limité à soixante-quatre caractères.
La clé primaire est affectée au champ IDRegion.
Du fait que ces tables (*) sont facultatives, dans la mesure où elles ne sont utilisées dans ce projet qu'à titre d'exemple, vous n'êtes pas obligé de les mettre en œuvre…
IV-A-4. tbl_Privileges (les privilèges utilisateur**)▲
Cette table possède trois champs :
- le champ IDPrivilege de type Numérique Entier long ;
- le champ CodePrivilege de type Texte limité à cinq caractères ;
- le champ LibellePrivilege de Texte limité à soixante-quatre caractères.
La clé primaire est affectée aux champs IDPrivilege + CodePrivilege tous indexés sans doublon.
IV-A-5. tbl_TypesContrat (les types de contrats**)▲
Cette table possède deux champs :
- le champ IDTypeContrat de type Numérique Entier long ;
- le champ TypeContrat de type Texte limité à soixante-quatre caractères.
La clé primaire est affectée au champ IDTypeContrat indexé sans doublon.
IV-B. La structure des tables de données utilisateur▲
IV-B-1. tblCommunesSite (les associations communes et site)▲
Cette table possède trois champs :
- le champ IDCommune de type Numérique Entier long ;
- le champ NoSite de type Numérique Entier long ;
- le champ IDDepartement de type Texte limité à trois caractères.
La clé primaire est affectée aux champs IDCommune + NoSite tous indexés avec doublons.
IV-B-2. tblContratCommunes (les associations contrat et communes)▲
Cette table possède deux champs :
- le champ IDCommune de type Numérique Entier long ;
- le champ IDContrat de type Texte limité à cinq caractères.
La clé primaire est affectée aux champs IDCommune + IDContrat tous indexés avec doublons.
IV-B-3. tblContrats (Les contrats)▲
Cette table possède cinq champs :
- le champ IDCommune représenté par un identifiant de type Numérotation automatique ;
- le champ IDContrat de type Texte limité à cinq caractères ;
- le champ LibelleContrat de type Texte limité à 128 caractères ;
- le champ DateFin de type Date ;
- le champ IDTypeContrat de type Numérique Entier long.
La clé primaire est affectée au champ IDContrat indexé sans doublon.
IV-B-4. tblPersonnel (Le personnel)▲
Cette table possède six champs :
- le champ IDPersonne représenté par un identifiant de type Numérotation automatique ;
- le champ NomFamille Texte limité à soixante-quatre caractères ;
- le champ Prenom de type Texte limité à soixante-quatre caractères ;
- le champ EMAIL de type Texte limité à soixante-quatre caractères ;
- le champ Login de type Texte limité à soixante-quatre caractères ;
- le champ NoSite de type Numérique Entier long ;
- le champ IDPrivileges de type Numérique Entier long.
La clé primaire est affectée aux champs NomFamille + Prenom + NoSite tous indexés avec doublons.
IV-B-5. tblSites (Les sites)▲
Cette table possède quatre champs :
- le champ NoSite de type Numérique Entier long ;
- le champ LibelleSite de type Texte limité à soixante-quatre caractères ;
- le champ IDCommune de type Numérique Entier long ;
- le champ DateOuverture de type Date.
La clé primaire est affectée aux champs NoSite + LibelleSite
NoSite est indexé sans doublon et LibelleSite est indexé avec doublons.
IV-C. Données des tables▲
Pour simplifier les choses pour le développeur, j'ai adopté intentionnellement une convention de nommage pour les tables qui contiennent des données prédéfinies avec un caractère underscore (_).
Rappel
Celles qui possèdent un astérisque(*) sont des tables facultatives puisqu'elles ne contiennent que les régions, les départements et les communes, et concernent plus particulièrement ce projet.
Celles qui possèdent deux astérisques(**) sont des tables directement liées au projet si l'on s'en réfère à l'aspect métier de ce dernier.
Toutes les autres tables sont dédiées à recevoir des données saisies par les utilisateurs. Ce seront ces tables qui seront remises à blanc, si toutefois l'utilisateur en fait la demande au chargement du projet. Nous verrons cela un petit peu plus bas dans le processus d'utilisation des formulaires.
Exemple de données dans les tables
IV-C-1. Liste des départements (tbl_ListeDepartements)▲
IDDepartement |
Departement |
IDRegion |
01 |
Ain |
23 |
02 |
Aisne |
20 |
03 |
Allier |
3 |
04 |
Alpes-de-Haute-Provence |
22 |
05 |
Hautes-Alpes |
22 |
06 |
Alpes-Maritimes |
22 |
… |
… |
… |
IV-C-2. Liste des régions (tbl_ListeDesRegions)▲
IDRegion |
Region |
1 |
Alsace |
2 |
Aquitaine |
3 |
Auvergne |
4 |
Basse-Normandie |
5 |
Bourgogne |
… |
… |
Liste des communes (tbl_ListeDesCommunes)
IDCommune |
Code INSEE |
Commune |
Code Postal |
IDDepartement |
447 |
98611 |
ALO |
98610 |
98 |
603 |
98711 |
ANAA |
98760 |
98 |
1307 |
98712 |
ARUE |
98701 |
98 |
1308 |
98713 |
ARUTUA |
98761 |
98 |
3007 |
98801 |
BELEP |
98811 |
98 |
4276 |
98714 |
BORA BORA |
98730 |
98 |
4510 |
98802 |
BOULOUPARI |
98812 |
98 |
4524 |
98803 |
BOURAIL |
98870 |
98 |
5855 |
98804 |
CANALA |
98813 |
98 |
10485 |
98805 |
DUMBEA |
98837 |
98 |
11481 |
98715 |
FAAA |
98704 |
98 |
11508 |
98716 |
FAKARAVA |
98790 |
98 |
… |
… |
… |
… |
… |
IV-C-3. Liste des types de contrats (tbl_TypesContrat)▲
IDTypeContrat |
Type de contrat |
1 |
Contrat communal |
2 |
Contrat intercommunal |
3 |
Contrat fictif |
IV-C-4. tbl_Privileges▲
IDPrivilege |
Code Privilège |
Libellé Privilèges |
1 |
ADMR |
Administrateur Régional |
2 |
ADMS |
Administrateur du Site |
3 |
USERA |
Utilisateur Agence |
4 |
GUEST |
Invité ou Externe |
V. Le schéma relationnel de l'application▲
Bien qu'il ne soit pas obligatoire d'en élaborer un, le schéma relationnel a été mis en place dans ce projet. Il est représenté par l'illustration ci-dessous :
Cela permet, en tout cas ici, de mieux appréhender la structure…
Vous pouvez remarquer qu'il y a deux jeux de tables distincts :
- un jeu de tables concernant les données utilisateur ;
- un jeu de tables concernant uniquement les communes, leur département et leur région.
VI. Conception des formulaires▲
Il existe autant de formulaires qu'il y a d'étapes.
Dans l'exemple présenté ici, je me suis limité à cinq écrans qualifiés à proprement parler de saisies, auxquels j'ai ajouté un formulaire d'accueil et un formulaire final récapitulatif.
Ce projet comporte donc onze formulaires :
- le premier et le dernier sont les formulaires de début et de fin ;
- trois d'entre eux possèdent un sous-formulaire ;
- un autre est un sous-formulaire de type pop-up ;
- deux autres sont des formulaires simples.
VI-A. Les différents formulaires (en mode utilisation)▲
Dans cet assistant, parmi les cinq formulaires de saisie, se trouvent des formulaires dits « simples ». Les autres seront élaborés avec une structure Parent/Enfant, autrement dit, un formulaire principal et un sous-formulaire, ce dernier possédant une structure continue.
VI-A-1. Le formulaire d'accueil▲
VI-A-2. Le formulaire de saisie du site▲
VI-A-3. Le formulaire de saisie du personnel▲
VI-A-4. Le formulaire de saisie des communes▲
VI-A-5. Le formulaire de saisie des contrats▲
VI-A-6. Le formulaire de saisie de l'association Contrat-Communes▲
VI-A-7. Le formulaire de fin▲
VII. Description structurelle des formulaires▲
VII-A. La source de données formulaires▲
Tous les formulaires dédiés à la saisie se voient affecter leur source de données dynamiquement par code. Il est rappelé ici que l'objectif de ce tutoriel est de vous apprendre à minimiser l'écriture du code d'une part, et de faire en sorte que chaque feuille de code représentée par la classe des formulaires soit la plus générique possible.
Considérant que pratiquement tous les écrans restent identiques selon leur type (simple ou continu), il était important de faire en sorte que la source de données bénéficie des mêmes privilèges.
Vue éclatée des formulaires (description des contrôles)
Pour faciliter la mise en œuvre des formulaires, les paragraphes qui vont suivre vous présentent une photographie du formulaire en Mode création tel qu'il est vu à l'écran lorsqu'il s'agit d'un formulaire simple, et en vue éclatée lorsqu'il s'agit d'un sous-formulaire.
En effet, du fait que certains contrôles sont volontairement cachés en mode formulaire, il est plus aisé de se rendre compte de la façon dont l'ensemble des contrôles a été agencé et disposé.
VII-B. Les formulaires simples ▲
Ils sont au nombre de quatre :
deux formulaires sans données saisies et deux avec données saisies par l'utilisateur.
VII-B-1. Formulaire sans données utilisateur▲
Ces formulaires ne sont pas structurés de la même façon.
Ils sont essentiellement composés de contrôles étiquette informative et de boutons de navigation.
Ces deux formulaires sont :
- le formulaire d'accueil : frmStart ;
- le formulaire de fin : frmEnd.
VII-B-2. Formulaire avec données utilisateur▲
Ces formulaires sont tous structurés de la même façon.
Ils possèdent tous un contrôle étiquette permettant d'affecter dynamiquement le contenu du titre qui est alimenté directement au moment du chargement.
Juste au-dessous de celui-ci se trouvent les contrôles des champs de la source.
Dans la partie basse de chacun d'eux, se trouvent quatre boutons de commande :
- un bouton Supprimer qui recevra la légende Sauvegarder en cours de saisie ;
- un bouton Ajouter qui recevra la légende Annuler en cours de saisie ;
- un bouton intitulé Précédent qui permet de revenir à l'écran précédent ;
- et un bouton Suivant qui permet de passer à l'écran suivant.
Au niveau des propriétés
Vous définirez les propriétés ci-après comme suit :
- Cycle à « Enregistrement en cours » ; cette propriété permet de spécifier ce qui se produit lorsque vous appuyez sur la touche TAB pendant que le dernier contrôle d'un formulaire dépendant est activé ;
- Menu Contextuel à « Non » ; cette propriété permet de spécifier s'il doit être affiché lorsque vous cliquez sur un objet d'un formulaire à l'aide du bouton droit de la souris ;
- Type Recordset à « Feuille de réponse dynamique » pour permettre de spécifier quel genre de jeu d'enregistrements est disponible pour le formulaire ;
- Propriété Remarque (Tag) définie à Null ou NotNull selon les champs pour lesquels vous souhaitez ne pas considérer la nullité comme bloquante.
Explications
Tous les champs des formulaires simples voient leur propriété
Tag
définie à
Null
ou
NotNull
:
cette propriété est utilisée dans une fonction qui contrôle le bon contenu des champs.
Voir cette rubrique pour plus d'informations ici.
VII-C. Les formulaires avec un sous-formulaire ▲
VII-C-1. Les formulaires parents▲
Ils sont au nombre de trois…
Ces formulaires sont tous structurés de la même façon.
Ils possèdent tous un contrôle étiquette permettant d'affecter dynamiquement le titre, le sujet et juste au-dessous de ceux-ci, se trouvent des zones de texte cachées que j'ai intentionnellement coloriées en jaune avec une police de couleur rouge.
Attention
Ces champs voient leur propriété Visible dépendante de la constante SHOW_HIDDEN_CONTROLS.
En leur milieu se trouve un sous-formulaire pour lequel il n'y a volontairement pas de notion Champs pères et Champs fils.
Les sous-formulaires portent toujours le même nom (sfrmDataWizard), et ce, quel que soit leur formulaire Parent.
En dessous de leur sous-formulaire se trouvent deux contrôles étiquette, l'un spécifiant le nombre d'enregistrements inscrits dans le sous-formulaire, l'autre spécifiant par effet de clignotement que la ligne est complète ou incomplète dans le sous-formulaire.
Cette dernière étiquette clignote grâce à l'événement Timer.
Dans la partie basse de chacun des formulaires parents sont dessinés quatre boutons de commande :
- un bouton Supprimer qui recevra la légende Sauvegarder en cours de saisie ;
- un bouton Ajouter qui recevra la légende Annuler en cours de saisie ;
- un bouton Précédent qui permet de revenir à l'écran précédent ;
- et un bouton Suivant qui permet de passer à l'écran suivant.
VII-C-2. Les formulaires enfants (ou sous-formulaire)▲
Chacun des sous-formulaires possède dans la partie droite de sa zone de détail, une case à cocher dont la formule calcule en permanence (donc au moment de la saisie) le fait que la ligne est complétée ou non.
On considère que la ligne est complétée à partir du moment où la formule stockée dans le champ caché (de couleur jaune) nommé txtCheckdata renvoie bien le résultat attendu.
Ce champ possède une formule appellant une fonction écrite en VBA qui calcule la somme de la nullité des champs de données avec leur type associé via la fonction Nz().
La fonction en elle-même retourne 0 ou 1 selon que le champ est nul ou non, et ce, quel que soit son type. Selon le nombre de champs où la valeur est requise, une certaine somme est attendue.
Ainsi, pour la table du personnel du site, l'ensemble des six champs est obligatoire ; cela implique que la formule doit renvoyer tout simplement 6.
La case à cocher prendra la valeur True ou False selon ce résultat.
Exemple de formule pour un sous-formulaire :
la zone de texte cachée « txtCheckdata »
=(
NullData
(
[NomDuChamp1];4
)+
NullData
(
[NomDuChamp2];10
)+
NullData
(
[NomDuChamp3];10
))
et la case à cocher associée « chkCompleted »
=(
[txtCheckdata]=
3
)
la fonction NullData() sera expliquée un peu plus loin dans ce tutoriel.
Dans la partie basse de chacun des sous-formulaires, au niveau du pied de formulaire, se trouvent des zones de texte cachées dont deux d'entre elles calculent en permanence le nombre d'enregistrements pour l'une et la valeur de la case à cocher pour l'autre.
Les autres zones de texte cachées reprennent selon la source de données, les champs utilisés pour accéder à l'enregistrement, et donc leur identifiant d'une part et leur libellé d'autre part ; les valeurs de ces champs sont utilisées au niveau du formulaire parent pour pouvoir afficher le contenu dans un message, notamment lorsqu'il s'agit de supprimer la ligne.
Remarque
Chacune des zones de texte cachées situées dans le pied de formulaire a une propriété Visible définie à False et une hauteur fixée à 0.
VII-C-3. Au niveau des propriétés▲
Vous définirez les propriétés ci-après comme suit :
- Cycle à « Tous les enregistrements » ; cette propriété permet de spécifier ce qui se produit lorsque vous appuyez sur la touche TAB pendant que le dernier contrôle d'un formulaire dépendant est activé ;
- Menu Contextuel à « Non » ; cette propriété permet de spécifier s'il doit être affiché lorsque vous cliquez sur un objet d'un formulaire à l'aide du bouton droit de la souris ;
- Type Recordset à « Feuille de réponse dynamique » pour permettre de spécifier quel genre de jeu d'enregistrements est disponible pour le formulaire.
VIII. Description détaillée des formulaires▲
VIII-A. Le formulaire d'accueil▲
Ce formulaire se nomme frmStart.
Ce formulaire dépourvu de données est composé principalement de contrôles étiquette dédiés à présenter quelque peu l'interface, mais aussi :
- d'une image représentant un logo par exemple ;
- d'une case à cocher permettant de remettre à blanc les données ;
- et de boutons de commande, un pour quitter, l'autre pour démarrer.
Le titre de ce formulaire est statique du fait que c'est le formulaire d'accueil.
VIII-B. Le formulaire de saisie du site▲
Ce formulaire se nomme frmDataWizard1.
Il s'agit du formulaire qui contient les coordonnées du site.
Ce formulaire possède :
- un contrôle de type étiquette présentant succinctement l'objet du formulaire ;
- trois zones de texte et deux listes déroulantes ;
- et trois boutons de commande.
La première zone de texte définira le numéro du site, la deuxième, le libellé et la troisième, la date d'ouverture du site.
La zone de liste déroulante indépendante permet de lister les départements et leur région et possède le code événementiel associé pour pouvoir filtrer les communes correspondant à celui sélectionné.
La zone de liste des communes contient l'ensemble des communes issues de la table via une instruction SQL filtrée sur le critère précité.
Dans la partie basse du formulaire se trouvent trois boutons :
- un bouton intitulé Effacer qui permet de remettre à blanc la saisie en cours ;
- un bouton intitulé Précédent qui permet de revenir à l'écran précédent ;
- et un bouton Suivant qui permet de passer à l'écran suivant.
VIII-C. Le formulaire de saisie du personnel▲
Ce formulaire est nommé : frmDataWizard2.
Il s'agit du formulaire permettant de saisir les employés du site.
La partie haute du formulaire contient les cinq champs cachés qui récupèrent les valeurs du pied de formulaire du sous-formulaire.
Juste en dessous du sous-formulaire, se trouvent les deux étiquettes qui calculent par programme le nombre d'employés enregistrés d'une part et si la ligne en cours de saisie dans le sous-formulaire est complète d'autre part.
N° |
Champ |
Formule ou Source |
Description |
|
txtTotalRows |
=[frmDataWizard2_sub]![txtCountRows] |
Valeur de txtCountRows* |
|
txtNoSite |
=[frmDataWizard2_sub]![txtNoSite] |
Valeur de txtNoSite* |
|
txtIDPersonne |
=[frmDataWizard2_sub]![txtIDPersonne] |
Valeur de txtIDPersonne* |
|
txtNomPrenom |
=[frmDataWizard2_sub]![txtNomPrenom] |
Valeur de txtNomPrenom* |
|
txtRowCompleted |
=[frmDataWizard2_sub]![txtCompleted] |
Valeur de txtCompleted* |
* issues des champs du sous-formulaire de la zone pied de formulaire (les champs portent le même nom pour plus de commodité).
VIII-C-1. Le sous-formulaire de saisie du personnel▲
Ce formulaire est nommé : frmDataWizard2_sub.
Il possède tous les champs de la table du personnel (tblPersonnel).
Dans la partie En-tête sont posées des étiquettes correspondant à chacun des champs de la table et dans la partie Détail, les champs eux-mêmes.
Dans la zone de détail se trouvent les champs cachés :
-
la zone de texte « txtCheckdata » dont la formule associée est :
Formule de txtCheckdataSélectionnez=(
NullData
(
[NoSite];4
)+
NullData
(
[Prenom];10
)+
NullData
(
[NomFamille];10
)+
NullData
(
[EMAIL];10
)+
NullData
(
[LOGIN];10
)+
NullData
(
[IDPrivileges];4
)) - la case à cocher « chkCompleted » dont la formule associée est :
=(
[txtCheckdata]=
6
)
Dans le pied du formulaire se trouvent les champs cachés dont les formules permettent de comptabiliser le nombre d'employés, de renvoyer l'identifiant, le libellé (ici nom et prénom) et la complétion de l'enregistrement recevant le focus (donc en cours).
N° |
Champ |
Formule ou Source |
Description |
|
txtCheckdata |
=NullData(de chaque champ) |
Calcule la somme des Nz()+Nz()+… |
|
txtCountRows |
=Compte([IDPersonne]) |
Compte le nombre d'enregistrements |
|
txtNoSite |
NoSite |
Renvoie le numéro du site en cours |
|
txtIDPersonne |
IDPersonne |
Renvoie l'ID de l'employé en cours |
|
txtNomPrenom |
=[Prenom] & " " & [NomFamille] |
Renvoie le nom et le prénom en cours |
|
txtCompleted |
=[chkCompleted] |
Renvoie la valeur de la case à cocher |
VIII-D. Le formulaire de saisie des communes▲
Ce formulaire est nommé : frmDataWizard3.
Il s'agit du formulaire permettant de sélectionner les communes exploitées par le site.
À l'instar du formulaire de saisie des employés, celui-ci possède quatre champs cachés dont les formules restent identiques à ceci près qu'elles ne pointent pas vers les mêmes champs, excepté bien entendu celle qui compte le nombre de lignes et celle qui retourne la complétion de l'enregistrement en cours.
N° |
Champ |
Formule ou Source |
Description |
|
txtTotalRows |
=[frmDataWizard3_sub]![txtCountRows] |
Valeur de txtCountRows* |
|
txtIDCommune |
=[frmPerimeter3_sub]![txtIDCommune] |
Valeur de txtIDCommune* |
|
txtCommune |
=[frmPerimeter3_sub]![txtCommune] |
Valeur de txtCommune* |
|
txtRowCompleted |
=[frmDataWizard3_sub]![txtCompleted] |
Valeur de txtCompleted* |
* issues des champs du sous-formulaire de la zone pied de formulaire (les champs portent le même nom pour plus de commodité).
VIII-D-1. Le sous-formulaire de saisie des communes▲
Ce formulaire est nommé : frmDataWizard3_sub.
Il possède tous les champs de la table du personnel (tblCommunesSite).
Dans la partie En-tête seront posées des étiquettes correspondant à chacun des champs de la table et dans la partie Détail, les champs eux-mêmes.
Dans la zone de détail se trouvent les champs cachés :
-
la zone de texte « txtCheckdata » dont la formule associée est :
Formule de txtCheckdataSélectionnez=(
NullData
(
[NoSite];4
)+
NullData
(
[IDCommune];4
)) - la case à cocher « chkCompleted » dont la formule associée est :
=(
[txtCheckdata]=
2
)
Dans le pied du formulaire se trouvent les champs cachés dont les formules permettent de comptabiliser le nombre de communes, de renvoyer l'identifiant, le libellé (ici nom de la commune) et la complétion de l'enregistrement recevant le focus (donc en cours).
N° |
Champ |
Formule ou Source |
Description |
|
txtCheckdata |
=NullData(de chaque champ) |
Calcule la somme des Nz()+Nz()+… |
|
txtCountRows |
=Compte([IDPersonne]) |
Compte le nombre d'enregistrements |
|
txtIDCommune |
IDCommune |
Renvoie l'ID de la commune en cours |
|
txtCommune |
=[IDCommune].[column](1) |
Valeur de txtNomCommune |
|
txtCompleted |
=[chkCompleted] |
Valeur de la case à cocher |
VIII-E. Le formulaire de saisie des contrats▲
Ce formulaire est nommé : frmDataWizard4_Popup.
Il s'agit du formulaire qui contient les différents contrats.
Ce formulaire possède :
- quatre zones de texte et une liste déroulante pour les données propres au contrat ;
- cinq boutons de commande.
La première zone de texte définira le numéro du contrat, la seconde, son libellé, et les deux dernières, respectivement la date de début et la date de fin du contrat.
La zone de liste déroulante permet de lister les types de contrats.
Dans la partie basse du formulaire se trouvent les cinq boutons : - un bouton intitulé Supprimer qui permet de remettre à blanc la saisie en cours ;
- un bouton intitulé Ajouter qui permet d'ajouter un nouveau contrat ;
- un bouton intitulé Voir les contrats déjà saisis qui permet de visualiser tous les contrats déjà enregistrés ;
- un bouton intitulé Précédent qui permet de revenir à l'écran précédent ;
- et un bouton Suivant qui permet de passer à l'écran suivant.
|
Le champ IDTypeContrat représenté par une Zone de liste déroulante est attaché à la table tbl_TypesContrat à l'aide d'une requête : |
SELECT
tbl_TypesContrat.IDTypeContrat, tbl_TypesContrat.TypeContrat
FROM
tbl_TypesContrat;
Pour plus de commodité, j'ai stocké cette clause SQL dans une requête nommée :
qry_CBOListeTypesDeContrat.
VIII-E-1. Le formulaire « popup » des contrats▲
Ce formulaire est nommé : frmDataWizard4_Popup
Il s'agit du formulaire qui contient l'ensemble des contrats que vous avez déjà saisis.
Il est à noter que le bouton d'accès à ce formulaire reste grisé tant que le nombre de contrats est inférieur ou égal à un.
Ce formulaire est construit en mode continu avec une structure En-tête et Pied de formulaire.
- Dans la partie En-tête seront posées des étiquettes correspondant à chacun des champs de la table et dans la partie Détail, les champs eux-mêmes.
- Dans le Pied du formulaire se trouvent :
- Un champ avec une formule qui permet de comptabiliser le nombre de contrats existants ;
- Et sur la droite, un bouton permettant de refermer la fenêtre.
Dans ce formulaire, tous les contrôles sont verrouillés là où la propriété Arrêt tabulation est définie à False.
En haut à gauche et de façon invisible, se trouve un champ nommé txtFocus et qui reçoit le focus en permanence.
La formule du champ de comptabilisation est la suivante :
=
Compte
(
[IDContrat]) &
" contrats enregistrés."
VIII-F. Le formulaire de saisie de l'association Contrat-Communes▲
Ce formulaire est nommé : frmDataWizard5.
Il s'agit du formulaire permettant de sélectionner les communes exploitées par le site.
À l'instar du formulaire de saisie des employés, celui-ci possède quatre champs cachés dont les formules restent identiques à ceci près qu'elles ne pointent pas vers les mêmes champs, excepté bien entendu celle qui compte le nombre de lignes et celle qui retourne la complétion de l'enregistrement en cours.
N° |
Champ |
Formule ou Source |
Description |
|
txtTotalRows |
=[frmDataWizard5_sub]![txtCountRows] |
Valeur de txtCountRows* |
|
txtIDContrat |
=[frmPerimeter5_sub]![IDContrat] |
Valeur de txtIDContrat* |
|
txtIDCommune |
=[frmPerimeter5_sub]![txtIDCommune] |
Valeur de txtIDCommune* |
|
txtNomCommune |
=[frmPerimeter5_sub]![txtNomCommune] |
Valeur de txtNomCommune* |
|
txtRowCompleted |
=[frmDataWizard5_sub]![txtCompleted] |
Valeur de txtCompleted* |
* issues des champs du sous-formulaire de la zone pied de formulaire (les champs portent le même nom pour plus de commodité).
VIII-F-1. Le sous-formulaire de saisie de l'association Contrat-Communes▲
Ce formulaire est nommé : frmDataWizard5_sub.
Ce formulaire possède tous les champs de la table du personnel (tblContratCommunes).
Dans la partie En-tête seront posées des étiquettes correspondant à chacun des champs de la table et dans la partie Détail, les champs eux-mêmes.
Dans la zone de détail se trouvent les champs cachés :
-
la zone de texte « txtCheckdata » dont la formule associée est :
Formule de txtCheckdataSélectionnez=(
NullData
(
[IDContrat];10
)+
NullData
(
[IDCommune];4
)) - la case à cocher « chkCompleted » dont la formule associée est :
=(
[txtCheckdata]=
2
)
Dans le pied du formulaire se trouvent les champs cachés dont les formules permettent de comptabiliser le nombre d'employés, de renvoyer l'identifiant, le libellé (ici nom de la commune et N° du contrat) et la complétion de l'enregistrement recevant le focus (donc en cours).
N° |
Champ |
Formule ou Source |
Description |
|
txtCheckdata |
=NullData(de chaque champ) |
Calcule la somme des Nz()+Nz()+… |
|
txtCountRows |
=Compte([IDContrat]) |
Compte le nombre d'enregistrements |
|
txtIDContrat |
IDContrat |
Renvoie l'ID du contrat en cours |
|
txtIDCommune |
IDCommune |
Renvoie l'ID de la commune en cours |
|
txtNomCommune |
=[IDCommune].[column](1) |
Renvoie le nom de la commune en cours |
|
txtCompleted |
=[chkCompleted] |
Renvoie la valeur de la case à cocher |
VIII-G. Le formulaire de fin▲
C'est le dernier formulaire qui s'affiche pour résumer les étapes omises (s'il y en a) et pour clore l'application après confirmation.
Le projet a été élaboré pour être ouvert autant de fois que nécessaire de manière à ce que l'enrichissement des informations puisse se faire sur plusieurs jours.
Ce formulaire, tout comme le formulaire d'accueil, est composé essentiellement de contrôles type étiquette et trois boutons de commande.
Deux de ces étiquettes sont alimentées par code, les autres possèdent un texte statique.
Dans la partie basse du formulaire se trouvent les trois boutons :
- un bouton intitulé Début qui permet de revenir au début des étapes ;
- un bouton intitulé Précédent qui permet de revenir à l'écran précédent ;
- et un bouton Terminer qui permet de fermer l'application après confirmation.
N° |
Contrôle |
Source |
Description |
|
lblStepStatus |
Code |
Affiche la mention de complétion selon les étapes |
|
lblStepList |
Code |
Affiche la liste des étapes qui ont été omises |
IX. Démarrage du projet▲
IX-A. Chargement par macro exemple 1▲
Dans le cas présenté ici, le projet démarre à l'aide d'une macro AutoExec qui pilote l'ouverture du formulaire d'accueil via l'action OuvrirFormulaire, le formulaire étant frmStart (formulaire d'accueil) et le mode de fenêtre étant Boîte de dialogue.
IX-B. Chargement par macro exemple 2▲
Autre possibilité, vous pouvez encore appeler une fonction personnalisée via une macro AutoExec qui ouvrira davantage de possibilités qu'offrent les actions des macros. Vous utiliserez alors la méthode OpenForm de l'objet DoCmd avec le paramètre acDialog.
IX-C. Chargement par propriété intrinsèque de la base de données▲
Autre solution, vous pouvez tout aussi bien définir les propriétés de démarrage de la base de données et sélectionner ce même formulaire.
X. Description des événements au sein des formulaires▲
Nous allons décrire ici les procédures événementielles qui se trouvent au sein des différentes classes de formulaire.
Pour chaque feuille, l'Option Explicit a été affectée et ne doit pas être supprimée.
Cette option se définit d'elle-même si vous cochez la case de l'éditeur VBE.
Tous les formulaires des étapes (ceux où l'utilisateur saisit des données) possèdent à peu de choses près, le même jeu de constantes dans l'en-tête :
Constante |
Description |
PREVIOUS_FORM_ID |
Index du formulaire précédent |
NEXT_FORM_ID |
Index du formulaire suivant |
TARGET_TABLE |
Nom de la table source |
FIELD_COLLECTION |
Chaîne de tableau contenant la liste des champs utilisés |
RECORD_SOURCE |
Clause SELECT basée sur TARGET_TABLE |
DELETE_RECORD_SQL |
Clause DELETE basée sur TARGET_TABLE |
WHERE_CONDITION |
Clause WHERE de la clause DELETE_RECORD_SQL |
FORM_CAPTION |
Légende de la barre de titre du formulaire |
MAX_STEP_WIZ |
Constante globale (autre module) définissant le nombre d'étapes |
FORM_SUBJECT |
Sujet du formulaire (mot clé utilisé dans le code) |
FORM_TITLE |
Titre du formulaire situé en haut de celui-ci |
XI. Les procédures événementielles des formulaires▲
XI-A. Le formulaire d'accueil (frmStart)▲
XI-A-1. L'en-tête de la feuille▲
L'en-tête ici comporte l'index du formulaire suivant et le titre de la fenêtre dans deux constantes dûment nommées.
Option
Compare Database
Option
Explicit
Private
Const
NEXT_FORM_ID As
Integer
=
1
Private
Const
FORM_CAPTION As
String
=
"Écran d'accueil"
XI-A-2. Les événements de formulaire▲
La procédure SurChargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On désactive les alertes système
DoCmd.SetWarnings
False
'On réinitialise les variables et les contrôles
Me.chkRAZData
=
False
g_strDataPage =
""
'On efface le tableau des étapes
Erase
g_intCompletionIndex
Me.Caption
=
FORM_CAPTION
End
Sub
On désactive les alertes système.
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
On force la valeur False à la case à cocher et on attribue une valeur vide à g_strDataPage.
Quelques explications…
- Le contrôle case à cocher chkRAZData (Langue que vous reconnaissez grâce à son préfixe) est mis à False.
- Le tableau d'entiers nommé g_intCompletionIndex est vidé ; c'est lui qui contient la liste des étapes écran par écran et affecte une valeur True ou False à chacun des éléments selon que le formulaire est complété ou non.
Il n'y a pas d'autre événement pour ce formulaire.
XI-B. Le formulaire de saisie du site (frmDataWizard1)▲
XI-B-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
PREVIOUS_FORM_ID As
Integer
=
0
Private
Const
NEXT_FORM_ID As
Integer
=
2
Private
Const
TARGET_TABLE As
String
=
"tblSites"
Private
Const
FIELD_COLLECTION As
String
=
"NoSite;LibelleSite;IDCommune;DateOuverture"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE
Private
Const
DELETE_RECORD_SQL As
String
=
"DELETE * FROM "
&
TARGET_TABLE &
" "
Private
Const
WHERE_CONDITION As
String
=
"WHERE NoSite = #1"
Private
Const
FORM_CAPTION As
String
=
"Saisie des données : étape #1/"
&
MAX_STEP_WIZ
Private
Const
FORM_SUBJECT As
String
=
"du Site"
Private
Const
FORM_TITLE As
String
=
" Assistant de saisie des données "
&
FORM_SUBJECT
Vous reconnaîtrez parmi elles, les index des formulaires suivant et précédent, le titre et le sujet de la fenêtre. Les autres constantes concernent la navigation, la source de données et les différentes clauses SQL.
XI-B-2. Les événements de formulaire▲
La procédure SurChargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'Le formulaire est raccordé à la source de données de la constante
Me.RecordSource
=
RECORD_SOURCE
'On applique le titre de la barre de titre dynamiquement
Me.Caption
=
Replace
(
FORM_CAPTION, "#1"
, NEXT_FORM_ID -
1
)
'On applique le titre de la fenêtre dynamiquement
Me.lblTitle.Caption
=
FORM_TITLE
'On appelle InitIDCommune()
Call
InitIDCommune
End
Sub
Quelques explications…
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
La fonction InitIDCommune() remplit la zone de liste indépendante en fonction d'une commune qui aurait préalablement été renseignée (cas de navigation en allers et retours).
La fonction privée se trouve ici : InitIDCommune.
La procédure SurErreur()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
Dim
strErrMessage As
String
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
If
FormDataErrors
(
DataErr, strErrMessage, Response
, Me) Then
MsgBox
strErrMessage, vbExclamation
, "Erreur de saisie"
Me.ActiveControl.Undo
End
If
End
Sub
Quelques explications…
Cet événement appelle FormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
Il n'y a pas d'autre événement pour ce formulaire.
XI-C. Le formulaire de saisie du personnel (frmDataWizard2)▲
XI-C-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
PREVIOUS_FORM_ID As
Integer
=
1
Private
Const
NEXT_FORM_ID As
Integer
=
3
Private
Const
TARGET_TABLE As
String
=
"tblPersonnel"
Private
Const
FIELD_COLLECTION As
String
=
"NoSite;Prenom;NomFamille;Email;Login;IDPrivileges"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE &
";"
Private
Const
DELETE_RECORD_SQL As
String
=
"DELETE * FROM "
&
TARGET_TABLE &
" "
Private
Const
WHERE_CONDITION As
String
=
"WHERE IDPersonne = #1 AND NoSite = '#2'"
Private
Const
FORM_CAPTION As
String
=
"Saisie des données : étape #1/"
&
MAX_STEP_WIZ
Private
Const
FORM_SUBJECT As
String
=
"des employés rattachés au Site"
Private
Const
FORM_TITLE As
String
=
" Assistant de saisie des données "
&
FORM_SUBJECT
XI-C-2. Les événements de formulaire▲
La procédure Sur_Activation()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Current
(
)
'On appelle la procédure événementielle générique du même nom
Call
FormCurrent
(
Me, "Prenom"
)
End
Sub
Quelques explications…
On appelle la procédure générique FormCurrent avec le paramètre Me pour identifier le formulaire en cours et le nom du contrôle devant être sollicité dans celle-ci.
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
Dim
strErrMessage As
String
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
If
FormDataErrors
(
DataErr, strErrMessage, Response
, Me) Then
MsgBox
strErrMessage, vbExclamation
, "Erreur de saisie"
Me.ActiveControl.Undo
End
If
End
Sub
Quelques explications…
Cet événement appelle FormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On désactive les alertes
DoCmd.SetWarnings
False
'On masque ou affiche les contrôles selon le mode (Prod ou Test)
Me.txtTotalRows.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtNoSite.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtIDPersonne.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtNomPrenom.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtTotalRows.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtRowCompleted.Visible
=
SHOW_HIDDEN_CONTROLS
'Le formulaire est raccordé à la source de données de la constante
Me.RecordSource
=
RECORD_SOURCE
'On applique le titre de la barre de titre dynamiquement
Me.Caption
=
Replace
(
FORM_CAPTION, "#1"
, NEXT_FORM_ID -
1
)
'On applique le titre de la fenêtre dynamiquement
Me.lblTitle.Caption
=
FORM_TITLE
End
Sub
Quelques explications…
On affecte la visibilité des contrôles de sous-totaux via la constante SHOW_HIDDEN_CONTROLS.
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
La procédure Sur_Minuterie()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Timer
(
)
'On provoque un clignotement du texte de complétion des données
Me.lblRecCompleted.Visible
=
Not
lblRecCompleted.Visible
End
Sub
Cet événement provoque ici le clignotement du texte de complétion des données selon la valeur du champ situé dans le sous-formulaire.
Il n'y a pas d'autre événement pour ce formulaire.
XI-D. Le sous-formulaire de saisie des communes (frmDataWizard2_sub)▲
XI-D-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
TARGET_TABLE As
String
=
"tblPersonnel"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE &
";"
XI-D-2. Les événements de formulaire▲
La procédure Sur_Activation()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Current
(
)
'On appelle la procédure événementielle générique du même nom
Call
SubFormCurrent
(
Me, "employé"
, False
)
End
Sub
Quelques explications…
On appelle la procédure générique FormCurrent avec le paramètre Me pour identifier le formulaire en cours et le nom du contrôle devant être sollicité dans celle-ci.
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
SubFormDataError Me, DataErr, Response
, "même nom / même prénom / même N° de site"
End
Sub
Quelques explications…
Cet événement appelle FormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On affecte la source de données
Me.RecordSource
=
RECORD_SOURCE
End
Sub
Quelques explications…
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
Il n'y a pas d'autre événement pour ce formulaire.
XI-E. Le formulaire de saisie des communes (frmDataWizard3)▲
XI-E-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
PREVIOUS_FORM_ID As
Integer
=
2
Private
Const
NEXT_FORM_ID As
Integer
=
4
Private
Const
TARGET_TABLE As
String
=
"tblCommunesSite"
Private
Const
FIELD_COLLECTION As
String
=
"IDCommune;NoSite"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE &
";"
Private
Const
DELETE_RECORD_SQL As
String
=
"DELETE * FROM "
&
TARGET_TABLE &
" "
Private
Const
WHERE_CONDITION As
String
=
"WHERE IDCommune = #1 AND NoSite = #2"
Private
Const
FORM_CAPTION As
String
=
"Saisie des données : étape #1/"
&
MAX_STEP_WIZ
Private
Const
FORM_SUBJECT As
String
=
"des communes du site"
Private
Const
FORM_TITLE As
String
=
" Assistant de saisie des données "
&
FORM_SUBJECT
XI-E-2. Les événements de formulaire▲
La procédure Sur_Activation()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Current
(
)
'On appelle la procédure événementielle générique du même nom
Call
FormCurrent
(
Me, "IDDepartement"
)
End
Sub
Quelques explications…
On appelle la procédure générique FormCurrent avec le paramètre Me pour identifier le formulaire en cours et le nom du contrôle devant être sollicité dans celle-ci.
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
Dim
strErrMessage As
String
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
If
FormDataErrors
(
DataErr, strErrMessage, Response
, Me) Then
MsgBox
strErrMessage, vbExclamation
, "Erreur de saisie"
Me.ActiveControl.Undo
End
If
End
Sub
Quelques explications…
Cet événement appelle FormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On désactive les alertes
DoCmd.SetWarnings
False
'On masque ou affiche les contrôles selon le mode (Prod ou Test)
Me.txtTotalRows.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtIDCommune.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtCommune.Visible
=
SHOW_HIDDEN_CONTROLS
Me.txtRowCompleted.Visible
=
SHOW_HIDDEN_CONTROLS
'Le formulaire est raccordé à la source de données de la constante
Me.RecordSource
=
RECORD_SOURCE
'On applique le titre de la barre de titre dynamiquement
Me.Caption
=
Replace
(
FORM_CAPTION, "#1"
, NEXT_FORM_ID -
1
)
'On applique le titre de la fenêtre dynamiquement
Me.lblTitle.Caption
=
FORM_TITLE
End
Sub
Quelques explications…
On affecte la visibilité des contrôles de sous-totaux via la constante SHOW_HIDDEN_CONTROLS.
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
La procédure Sur_Minuterie()
Private
Sub
Form_Timer
(
)
Dim
lngCount As
Long
'On provoque un clignotement du texte de complétion des données
Me.lblRecCompleted.Visible
=
Not
lblRecCompleted.Visible
End
Sub
Quelques explications…
Cet événement provoque ici le clignotement du texte de complétion des données selon la valeur du champ situé dans le sous-formulaire.
Il n'y a pas d'autre événement pour ce formulaire.
XI-F. Le sous-formulaire de saisie des communes (frmDataWizard3_sub)▲
XI-F-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
TARGET_TABLE As
String
=
"tblCommunesSite"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE &
";"
XI-F-2. Les événements▲
La procédure Sur_Activation()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Current
(
)
'On appelle la procédure événementielle générique du même nom
Call
SubFormCurrent
(
Me, "cboDepartement"
, False
)
End
Sub
Quelques explications…
On appelle la procédure générique FormCurrent avec le paramètre Me pour identifier le formulaire en cours et le nom du contrôle devant être sollicité dans celle-ci.
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
SubFormDataError Me, DataErr, Response
, "même département / même commune / même N° de site"
End
Sub
Quelques explications…
Cet événement appelle SubFormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On affecte la source de données
Me.RecordSource
=
RECORD_SOURCE
End
Sub
Quelques explications…
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
Il n'y a pas d'autre événement pour ce formulaire.
XI-G. Le formulaire de saisie des contrats (frmDataWizard4)▲
XI-G-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
PREVIOUS_FORM_ID As
Integer
=
3
Private
Const
NEXT_FORM_ID As
Integer
=
5
Private
Const
TARGET_TABLE As
String
=
"tblContrats"
Private
Const
FIELD_COLLECTION As
String
=
"IDContrat;LibelleContrat;IDTypeContrat;DateDebut;DateFin"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE
Private
Const
FORM_CAPTION As
String
=
"Saisie des données : étape #1/"
&
MAX_STEP_WIZ
Private
Const
FORM_SUBJECT As
String
=
"des Contrats"
Private
Const
FORM_TITLE As
String
=
" Assistant de saisie des données "
&
FORM_SUBJECT
XI-G-2. Les événements de formulaire▲
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
Dim
strErrMessage As
String
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
If
FormDataErrors
(
DataErr, strErrMessage, Response
, Me) Then
MsgBox
strErrMessage, vbExclamation
, "Erreur de saisie"
Me.ActiveControl.Undo
End
If
End
Sub
Quelques explications…
Cet événement appelle FormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
Dim
oRS As
DAO.Recordset
Dim
lngRecordCount As
Long
'Le formulaire est raccordé à la source de données de la constante
Me.RecordSource
=
RECORD_SOURCE
'On applique le titre de la barre de titre dynamiquement
Me.Caption
=
Replace
(
FORM_CAPTION, "#1"
, NEXT_FORM_ID -
1
)
'On applique le titre de la fenêtre dynamiquement
Me.lblTitle.Caption
=
FORM_TITLE
'On compte le nombre de contrats afin de libérer le bouton donnant accès à la liste
Set
oRS =
Me.RecordsetClone
With
oRS
If
Not
.EOF
Then
.MoveLast
lngRecordCount =
.RecordCount
.MoveFirst
End
If
.Close
End
With
Me.cmdShowExistingContracts.Enabled
=
(
lngRecordCount >
1
)
Set
oRS =
Nothing
End
Sub
Quelques explications…
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
On compte alors le nombre d'enregistrements que l'on affecte à la variable lngRecordCount dont la valeur détermine l'activation du bouton cmdShowExistingContracts permettant d'afficher un popup si elle supérieure à 1.
Il n'y a pas d'autre événement pour ce formulaire.
XI-H. Le formulaire listant les contrats (frmDataWizard4_Popup)▲
XI-H-1. L'en-tête de la feuille▲
L'en-tête ici ne comporte aucune déclaration.
Option
Compare Database
Option
Explicit
XI-H-2. Les événements▲
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
Me.txtFocus.SetFocus
End
Sub
Quelques explications…
On donne le focus au contrôle txtFocus dissimulé, mais pas invisible (enfin, il faut de bons yeux tout de même).
Il est situé en haut et à gauche avec des dimensions et positions, toutes définies à zéro.
Il n'y a pas d'autre événement pour ce formulaire.
XI-I. Le formulaire de saisie de l'association Contrat-Communes (frmDataWizard5)▲
XI-I-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Option
Compare Database
Option
Explicit
Private
Const
PREVIOUS_FORM_ID As
Integer
=
4
Private
Const
NEXT_FORM_ID As
Integer
=
MAX_STEP_WIZ +
1
Private
Const
FINAL_FORM_ID As
Integer
=
LAST_FORM_INDEX
Private
Const
TARGET_TABLE As
String
=
"tblContratCommunes"
Private
Const
FIELD_COLLECTION As
String
=
"IDCommune;IDContrat"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE &
";"
Private
Const
DELETE_RECORD_SQL As
String
=
"DELETE * FROM "
&
TARGET_TABLE &
" "
Private
Const
WHERE_CONDITION As
String
=
"WHERE IDCommune = #1 AND IDContrat = '#2'"
Private
Const
FORM_CAPTION As
String
=
"Saisie des données : étape #1/"
&
MAX_STEP_WIZ
Private
Const
FORM_SUBJECT As
String
=
"des contrats des communes du site"
Private
Const
FORM_TITLE As
String
=
" Assistant de saisie des données "
&
FORM_SUBJECT
XI-I-2. Les événements de formulaire▲
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
Dim
strErrMessage As
String
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
If
FormDataErrors
(
DataErr, strErrMessage, Response
, Me) Then
MsgBox
strErrMessage, vbExclamation
, "Erreur de saisie"
Me.ActiveControl.Undo
End
If
End
Sub
Quelques explications…
Cet événement appelle FormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On désactive les alertes
DoCmd.SetWarnings
False
'On masque ou affiche les contrôles selon le mode (Prod ou Test)
Me.txtTotalRows.Visible
=
SHOW_HIDDEN_CONTROLS
'Me.txtIDCommune.Visible = SHOW_HIDDEN_CONTROLS
'Me.txtCommune.Visible = SHOW_HIDDEN_CONTROLS
Me.txtRowCompleted.Visible
=
SHOW_HIDDEN_CONTROLS
'Le formulaire est raccordé à la source de données de la constante
Me.RecordSource
=
RECORD_SOURCE
'On applique le titre de la barre de titre dynamiquement
Me.Caption
=
Replace
(
FORM_CAPTION, "#1"
, NEXT_FORM_ID -
1
)
'On applique le titre de la fenêtre dynamiquement
Me.lblTitle.Caption
=
FORM_TITLE
End
Sub
Quelques explications…
On affecte la visibilité des contrôles de sous-totaux via la constante SHOW_HIDDEN_CONTROLS.
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
La procédure Sur_Minuterie()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Timer
(
)
'On provoque un clignotement du texte de complétion des données
Me.lblRecCompleted.Visible
=
Not
lblRecCompleted.Visible
End
Sub
Quelques explications…
Cet événement provoque ici le clignotement du texte de complétion des données selon la valeur du champ situé dans le sous-formulaire.
XI-J. Le sous-formulaire de saisie des communes (frmDataWizard5_sub)▲
XI-J-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Private
Const
TARGET_TABLE As
String
=
"tblContratCommunes"
Private
Const
RECORD_SOURCE As
String
=
"SELECT * FROM "
&
TARGET_TABLE &
";"
XI-J-2. Les événements▲
La procédure Sur_Activation()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Current
(
)
'On appelle la procédure événementielle générique du même nom
Call
SubFormCurrent
(
Me, "Contrat / Communes"
, False
)
End
Sub
Quelques explications…
On appelle la procédure générique FormCurrent avec le paramètre Me pour identifier le formulaire en cours et le nom du contrôle devant être sollicité dans celle-ci.
La procédure Sur_Erreur ()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Error
(
DataErr As
Integer
, Response
As
Integer
)
'On appelle FormDataErrors() selon DataErr si une erreur est rencontrée
SubFormDataError Me, DataErr, Response
, "même département / même commune / même N° de site"
End
Sub
Quelques explications…
Cet événement appelle SubFormDataErrors() avec le paramètre DataErr si une erreur est rencontrée et affiche un message circonstanciel.
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On affecte la source de données
Me.RecordSource
=
RECORD_SOURCE
End
Sub
Quelques explications…
Le formulaire voit sa propriété RecordSource affectée à la constante du même nom RECORD_SOURCE.
Il n'y a pas d'autre événement pour ce formulaire.
XI-K. Le formulaire de fin (frmEnd)▲
XI-K-1. L'en-tête de la feuille▲
L'en-tête ici comporte le lot de constantes définies dans ce tableau.
Private
Const
PREVIOUS_FORM_ID As
Integer
=
5
Private
Const
NEXT_FORM_ID As
Integer
=
0
Private
Const
FORM_CAPTION As
String
=
"Saisie des données : dernière étape"
Private
Const
FORM_SUBJECT As
String
=
"pour l'ensemble des modules"
Private
Const
FORM_TITLE As
String
=
"Fin de l'Assistant de saisie des données "
&
FORM_SUBJECT
Private
m_blnCompleted As
Boolean
Private
m_intCount As
Integer
Quelques explications…
La variable m_blnCompleted est utilisée pour déterminer la complétude des étapes et la variable m_intCount pour les compter.
XI-K-2. Les événements▲
La procédure Sur_Chargement()
Elle est invoquée et se traduit par le code suivant :
Private
Sub
Form_Load
(
)
'On applique le titre de la barre de titre dynamiquement
Me.Caption
=
FORM_CAPTION
'On applique le titre de la fenêtre dynamiquement
Me.lblTitle.Caption
=
FORM_TITLE
'On initialise la variable selon la résultante de la fonction
m_blnCompleted =
AllStepsAreCompleted
(
m_intCount)
'On affiche la liste des étapes manquantes s'il y en a
If
Not
m_blnCompleted Then
Me.lblStepList.Caption
=
g_strDataPage
lblStepStatus.Visible
=
True
Else
Me.lblStepList.Caption
=
"Aucune étape n'a été omise."
lblStepStatus.Visible
=
False
End
If
End
Sub
Quelques explications…
La propriété Légende (titre de la fenêtre) voit sa valeur modifiée via la constante FORM_CAPTION.
Le titre (lblTitle) dessiné dans le formulaire est lui aussi alimenté dynamiquement via la constante FORM_TITLE.
On affecte à la variable m_blnCompleted le fait que toutes les étapes sont complétées et on change l'intitulé des étiquettes en conséquence.
XII. Les procédures événementielles des contrôles▲
XII-A. Le formulaire d'accueil (frmStart)▲
XII-A-1. L'en-tête de la feuille▲
L'en-tête ici comporte l'index du formulaire suivant et le titre de la fenêtre dans deux constantes dûment nommées.
Option
Compare Database
Option
Explicit
Private
Const
NEXT_FORM_ID As
Integer
=
1
Private
Const
FORM_CAPTION As
String
=
"Écran d'accueil"
XII-A-2. Les événements▲
La procédure événementielle des boutons est systématiquement appelée via l'événement SurClic() ; ces procédures se traduisent par les blocs de code suivants :
Le bouton Quitter
Private
Sub
cmdQuit_Click
(
)
Dim
strMsgData As
String
Dim
intCount As
Integer
'Appelle la fonction pour déterminer si toutes les étapes sont complétées
If
AllStepsAreCompleted
(
intCount) Then
'La chaîne prend alors le message correspondant (ici positif)
strMsgData =
vbCrLf
&
vbCrLf
&
"Tous les modules sont complétés"
Else
'La chaîne prend alors le message correspondant (ici négatif)
strMsgData =
vbCrLf
&
vbCrLf
&
"Toutes les données n'ont pas été saisies."
&
vbCrLf
&
vbCrLf
&
IIf
(
intCount =
0
, "Aucune étape n'a été correctement remplie !"
, Trim
(
str
(
intCount)) &
" étape(s) a été correctement remplie(s) sur un total de "
&
MAX_STEP_WIZ &
"."
)
End
If
'On demande confirmation avant de quitter l'application
If
MsgBox
(
"Êtes-vous certain de vouloir quitter ?"
&
strMsgData, vbQuestion
+
vbYesNo
+
vbDefaultButton2
, "Quitter"
) =
vbYes
Then
Application.Quit
acQuitSaveAll
End
If
End
Sub
Quelques explications…
On appelle la fonction AllStepsAreCompleted() pour prévenir (toujours de façon optimiste) la complétude des données, avant de quitter l'application, par un message à l'utilisateur.
Le bouton Démarrer
Private
Sub
cmdStart_Click
(
)
Dim
strErrDescription As
String
On
Error
GoTo
L_ErrcmdStart_Click
'Si la remise à blanc des données est demandée...
If
Nz
(
Me.chkRAZData
, False
) Then
'On confirme par un message la remise à blanc avant de passer la première étape
Select
Case
MsgBox
(
"Êtes-vous certain de vouloir supprimer toutes les données déjà inscrites avant de continuer ?"
&
vbCrLf
&
_
"Cette action est irréversible..."
, vbExclamation
+
vbYesNoCancel
+
vbDefaultButton2
, "Effacer toutes les données"
)
Case
vbYes
'On appelle la fonction qui retourne un succès ou un échec
If
EraseAllDataBefore
(
strErrDescription) =
False
Then
'On génère l'erreur d'exécution si la fonction échoue
Err
.Raise
17
, "Remise à blanc"
, strErrDescription
End
If
Case
vbCancel
'On ne fait rien
Exit
Sub
Case
Else
End
Select
End
If
'On ferme cet écran
DoCmd.Close
acForm, Me.Name
'On ouvre l'écran de l'étape 1
DoCmd.OpenForm
FORM_DATA_WIZ &
NEXT_FORM_ID, , , , , acDialog
On
Error
GoTo
0
L_ExcmdStart_Click
:
Exit
Sub
L_ErrcmdStart_Click
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExcmdStart_Click
End
Sub
Quelques explications…
Si la case de remise à blanc est cochée, alors :
- on confirme par un message cette remise à blanc avant de passer la première étape ;
- on appelle alors la fonction EraseAllDataBefore qui retourne un succès ou un échec ;
- on ferme cet écran ;
- on ouvre l'écran de l'étape 1.
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-B. Le formulaire de saisie du site (frmDataWizard1)▲
Le contrôle cboDeptRegion
Private
Sub
cboDeptRegion_Click
(
)
Dim
SQLListeCommunes As
String
Dim
strNoDepartement As
String
'On construit la clause SQL selon le département sélectionné
strNoDepartement =
Me.cboDeptRegion
SQLListeCommunes =
"SELECT IDCommune, [NomCommune] & ' (' & [CodePostal] & ')' AS Commune, IDDepartement "
SQLListeCommunes =
SQLListeCommunes &
"FROM tbl_ListeDesCommunes WHERE IDDepartement='"
&
strNoDepartement &
"';"
'On affecte la requête à la liste des communes, filtrée sur le département sélectionné
With
Me.IDCommune
.RowSource
=
SQLListeCommunes
'On active la liste, lui donne le focus et lui force le déroulement
.Enabled
=
True
.SetFocus
.Dropdown
End
With
End
Sub
Quelques explications…
Le contrôle IDCommune se voit affecter la requête source SQL en fonction du numéro du département choisi.
Le bouton Supprimer
Private
Sub
cmdDelete_Click
(
)
Dim
SQLDelete As
String
Dim
strSubject As
String
'S'il n'y a pas de nullité
If
Not
IsNull
(
Me.NoSite
) And
Not
IsNull
(
Me.LibelleSite
) Then
strSubject =
"le site "
&
Me.LibelleSite
&
" ("
&
Me.NoSite
&
") "
SQLDelete =
DELETE_RECORD_SQL &
Replace
(
WHERE_CONDITION, "#1"
, Me.NoSite
)
'On appelle la méthode DeleteOrSaveRecord avec les paramètres attendus
DeleteOrSaveRecord Me, 3
, Me.NoSite
, SQLDelete, strSubject
End
If
End
Sub
Quelques explications…
Si l'identifiant cible et le libellé ne sont pas nuls alors :
- on alimente la chaîne strSubject du contexte qui fera office de confirmation du message de suppression ;
- on élabore la clause SQL de suppression dans la variable SQLDelete avec les constantes de l'en-tête dûment remplacées par la fonction Replace() ;
- on appelle la procédure DeleteOrSaveRecord () avec les paramètres attendus.
Le bouton Suivant
Private
Sub
cmdNext_Click
(
)
'On affecte l'identifiant du site à la variable globale (elle est exploitée pour tout l'assistant)
g_strNoSiteEnCours =
Nz
(
Me.NoSite
, ""
)
'On suppose (c'est un exemple) que le nom du site est le nom du domaine
g_strDomaineSiteEnCours =
Replace
(
LCase
(
Nz
(
Me.LibelleSite
, ""
)), " "
, ""
) &
".com"
'On appelle la procédure pour ouvrir le formulaire suivant
OpenTheForm GotoNext, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, False
End
Sub
Quelques explications…
On accède au formulaire suivant à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le bouton Précédent
Private
Sub
cmdPrevious_Click
(
)
'On appelle la procédure pour ouvrir le formulaire précédent
OpenTheForm GotoPrevious, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, False
End
Sub
Quelques explications…
On accède au formulaire précédent à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le contrôle LibelleSite
Private
Sub
LibelleSite_AfterUpdate
(
)
'On force la casse en majuscules
Me.LibelleSite
=
UCase
(
Me.LibelleSite
)
Me.cmdDelete.Enabled
=
(
Nz
(
Me.NoSite
, 0
) And
Len
(
Nz
(
Me.LibelleSite
, ""
)))
End
Sub
Quelques explications…
On force la casse du libellé du site en majuscules et on active le bouton de suppression en fonction de la valeur de deux champs.
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-C. Le formulaire de saisie du personnel (frmDataWizard2)▲
Le bouton Ajouter
Private
Sub
cmdAdd_Click
(
)
'On appelle la méthode AddNewOrCancel avec les paramètres attendus
AddNewOrCancel Me, NEXT_FORM_ID -
1
, TARGET_TABLE, FIELD_COLLECTION, "Prenom"
, True
, NEXT_FORM_ID
End
Sub
Quelques explications…
On appelle ici la procédure AddNewOrCancel () vue et détaillée ci-après pour ajouter ou annuler un enregistrement.
Le bouton Supprimer
Private
Sub
cmdDelete_Click
(
)
Dim
SQLDelete As
String
Dim
strSubject As
String
If
Not
IsNull
(
Me.txtIDPersonne
) Then
strSubject =
"l'employé "
&
IIf
(
Len
(
Nz
(
Me.txtNomPrenom
, ""
)), " ("
&
txtNomPrenom &
") "
, "non spécifié"
)
SQLDelete =
DELETE_RECORD_SQL &
Replace
(
Replace
(
WHERE_CONDITION, "#1"
, Me.txtIDPersonne
), "#2"
, g_strNoSiteEnCours)
'On appelle la méthode DeleteOrSaveRecord avec les paramètres attendus
DeleteOrSaveRecord Me, 3
, Me.txtIDPersonne
, SQLDelete, strSubject
End
If
End
Sub
Quelques explications…
Si l'identifiant cible n'est pas nul alors :
- on alimente la chaîne strSubject du contexte qui fera office de confirmation du message de suppression ;
- on élabore la clause SQL de suppression dans la variable SQLDelete avec les constantes de l'en-tête dûment remplacées par la fonction Replace() ;
- on appelle la procédure DeleteOrSaveRecord () avec les paramètres attendus.
Le bouton Suivant
Private
Sub
cmdNext_Click
(
)
'On appelle la procédure pour ouvrir le formulaire suivant
OpenTheForm GotoNext, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, True
End
Sub
Quelques explications…
On accède au formulaire suivant à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le bouton Précédent
Private
Sub
cmdPrevious_Click
(
)
'On appelle la procédure pour ouvrir le formulaire précédent
OpenTheForm GotoPrevious, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, True
End
Sub
Quelques explications…
On accède au formulaire précédent à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
XII-D. Le sous-formulaire de saisie des communes (frmDataWizard2_sub)▲
Le contrôle chkCompleted
Private
Sub
chkCompleted_MouseUp
(
Button As
Integer
, Shift As
Integer
, X As
Single
, Y As
Single
)
'On donne le focus : la case à cocher ne doit pas être cliquée
Me.Prenom.SetFocus
End
Sub
Quelques explications…
Si l'utilisateur tente de cliquer sur la case à cocher, on donne le focus au premier contrôle.
Le contrôle Email
Private
Sub
EMAIL_AfterUpdate
(
)
Me.EMAIL
=
LCase
(
Me.EMAIL
)
Me.NoSite
=
g_strNoSiteEnCours
End
Sub
Quelques explications…
On force la casse de l'adresse mail en minuscules et le champ NoSite prend la valeur de la variable globale représentant le numéro du site, initialisée dans le premier formulaire de saisie.
Le contrôle IDPrivileges
Private
Sub
IDPrivileges_AfterUpdate
(
)
Me.NoSite
=
g_strNoSiteEnCours
End
Sub
Quelques explications…
Le champ NoSite prend la valeur de la variable globale représentant le numéro du site.
Le contrôle IDPrivileges
Private
Sub
IDPrivileges_NotInList
(
NewData As
String
, Response
As
Integer
)
'On appelle la méthode NotInList pour avertir de la non-correspondance
Response
=
NotInList
(
NewData, "Le droit attribué"
)
End
Sub
Quelques explications…
On appelle ici la fonction NotInList() vue et détaillée ci-après…
Le contrôle Login
Private
Sub
Login_AfterUpdate
(
)
Me.NoSite
=
g_strNoSiteEnCours
End
Sub
Quelques explications…
Le champ NoSite prend la valeur de la variable globale représentant le numéro du site.
Le contrôle NomFamille
Private
Sub
NomFamille_AfterUpdate
(
)
'On force en MAJUSCULES
Me.NomFamille
=
UCase
(
Me.NomFamille
)
'On force le champ avec la valeur commune de l'identifiant
Me.NoSite
=
g_strNoSiteEnCours
'On construit l'adresse mail si on peut
Me.EMAIL
=
LCase
(
Nz
(
Me.Prenom
, "???"
) &
"."
&
Me.NomFamille
&
"@"
&
g_strDomaineSiteEnCours)
'Le login est par défaut le Nom.P
Me.Login
=
UCase
(
Me.NomFamille
) &
"."
&
Left
(
Nz
(
Me.Prenom
, " "
), 1
)
End
Sub
Quelques explications…
On force la casse du nom de famille en majuscules et on finit de composer l'adresse mail fondée sur la règle supposée Email = .
Le contrôle Prenom
Private
Sub
Prenom_AfterUpdate
(
)
'On force en Nom Propre
Me.Prenom
=
StrConv
(
Me.Prenom
, vbProperCase)
'On force le champ avec la valeur commune de l'identifiant
Me.NoSite
=
g_strNoSiteEnCours
'On construit l'adresse mail si on peut
Me.EMAIL
=
LCase
(
Me.Prenom
&
"."
&
Nz
(
Me.NomFamille
, "???"
) &
"@"
&
g_strDomaineSiteEnCours)
End
Sub
Quelques explications…
On force la casse du prénom en nom propre et on finit de composer l'adresse mail fondée sur la règle supposée Email = .
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-E. Le formulaire de saisie des communes (frmDataWizard3)▲
Le bouton Ajouter
Private
Sub
cmdAdd_Click
(
)
'On appelle la méthode AddNewOrCancel avec les paramètres attendus
AddNewOrCancel Me, NEXT_FORM_ID -
1
, TARGET_TABLE, FIELD_COLLECTION, "cboDepartement"
, True
, NEXT_FORM_ID
End
Sub
Quelques explications…
On appelle ici la procédure AddNewOrCancel () vue et détaillée ci-après pour ajouter ou annuler un enregistrement.
Le bouton Supprimer
Private
Sub
cmdDelete_Click
(
)
Dim
SQLDelete As
String
Dim
strSubject As
String
If
Not
IsNull
(
Me.txtIDCommune
) Then
strSubject =
"la commune "
&
Me.txtCommune
SQLDelete =
DELETE_RECORD_SQL &
Replace
(
Replace
(
WHERE_CONDITION, "#1"
, Me.txtIDCommune
), "#2"
, g_strNoSiteEnCours)
'On appelle la méthode DeleteOrSaveRecord avec les paramètres attendus
DeleteOrSaveRecord Me, 3
, Me.txtIDCommune
, SQLDelete, strSubject
End
If
End
Sub
Quelques explications…
Si l'identifiant cible n'est pas nul alors :
- on alimente la chaîne strSubject du contexte qui fera office de confirmation du message de suppression ;
- on élabore la clause SQL de suppression dans la variable SQLDelete avec les constantes de l'en-tête dûment remplacées par la fonction Replace() ;
- on appelle la procédure DeleteOrSaveRecord () avec les paramètres attendus.
Le bouton Suivant
Private
Sub
cmdNext_Click
(
)
'On appelle la procédure pour ouvrir le formulaire suivant
OpenTheForm GotoNext, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, True
End
Sub
Quelques explications…
On accède au formulaire suivant à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le bouton Précédent
Private
Sub
cmdPrevious_Click
(
)
'On appelle la procédure pour ouvrir le formulaire précédent
OpenTheForm GotoPrevious, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, True
End
Sub
Quelques explications…
On accède au formulaire précédent à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-F. Le sous-formulaire de saisie des communes (frmDataWizard3_sub)▲
Le contrôle cboDepartement (1)
Private
Sub
cboDepartement_AfterUpdate
(
)
Const
TOWN_LIST As
String
=
"SELECT C.IDCommune, [NomCommune] & ' (' & [CodePostal] & ')' AS Commune, C.CodePostal FROM tbl_ListeDepartements AS D INNER JOIN tbl_ListeDesCommunes AS C ON D.IDDepartement = C.IDDepartement WHERE (D.IDDepartement = '#') ORDER BY C.CodePostal;"
Dim
strRowSource As
String
'On construit la clause SQL selon le département sélectionné
strRowSource =
Replace
(
TOWN_LIST, "#"
, Nz
(
Me.cboDepartement.Column
(
0
), ""
))
'On affecte la requête à la liste des communes, filtrée sur le département sélectionné
With
Me.IDCommune
.RowSource
=
strRowSource
'On lui donne le focus et lui force le déroulement
.SetFocus
.Dropdown
End
With
End
Sub
Quelques explications…
Le contrôle IDCommune se voit affecter la requête source SQL en fonction du numéro du département choisi.
Le contrôle cboDepartement (2)
Private
Sub
cboDepartement_NotInList
(
NewData As
String
, Response
As
Integer
)
'On appelle la méthode NotInList pour avertir de la non-correspondance
Response
=
NotInList
(
NewData, "Le département"
)
End
Sub
Quelques explications…
On appelle ici la fonction NotInList() vue et détaillée ci-après…
Le contrôle chkCompleted
Private
Sub
chkCompleted_MouseUp
(
Button As
Integer
, Shift As
Integer
, X As
Single
, Y As
Single
)
'On donne le focus : la case à cocher ne doit pas être cliquée
Me.cboDepartement.SetFocus
End
Sub
Quelques explications…
Si l'utilisateur tente de cliquer sur la case à cocher, on donne le focus au premier contrôle.
Le contrôle IDCommune (1)
Private
Sub
IDCommune_AfterUpdate
(
)
Me.NoSite
=
g_strNoSiteEnCours
End
Sub
Quelques explications…
Le champ NoSite prend la valeur de la variable globale représentant le numéro du site.
Le contrôle IDCommune (2)
Private
Sub
IDCommune_NotInList
(
NewData As
String
, Response
As
Integer
)
'On appelle la méthode NotInList pour avertir de la non-correspondance
Response
=
NotInList
(
NewData, "La commune"
)
End
Sub
Quelques explications…
On appelle ici la fonction NotInList() vue et détaillée ci-après…
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-G. Le formulaire de saisie des contrats (frmDataWizard4)▲
Le contrôle LibelleContrat
Private
Sub
LibelleContrat_AfterUpdate
(
)
'On force la casse en majuscules
Me.LibelleContrat
=
UCase
(
Me.ibelleContrat
)
End
Sub
Quelques explications…
La zone de texte se voit attribuer sa valeur en MAJUSCULES.
Le bouton cmdShowExistingContracts
Private
Sub
cmdShowExistingContracts_Click
(
)
DoCmd.OpenForm
Me.Name
&
"_Popup"
, , , , , acDialog
End
Sub
Quelques explications…
On ouvre le formulaire via l'objet DoCmd et sa méthode OpenForm.
Remarque
Le fait de nommer correctement les objets permet de faciliter la rédaction du code sans galérer à chercher comment tel ou tel objet se nomme et en pouvant en plus, user ici du nom du formulaire parent…
Le bouton Suivant
Private
Sub
cmdNext_Click
(
)
'On appelle la procédure pour ouvrir le formulaire suivant
OpenTheForm GotoNext, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, False
End
Sub
Quelques explications…
On accède au formulaire suivant à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le bouton Précédent
Private
Sub
cmdPrevious_Click
(
)
'On appelle la procédure pour ouvrir le formulaire précédent
OpenTheForm GotoPrevious, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, False
End
Sub
Quelques explications…
On accède au formulaire précédent à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
XII-H. Le formulaire listant les contrats (frmDataWizard4_Popup)▲
Le bouton Fermer
Private
Sub
cmdClose_Click
(
)
DoCmd.Close
acForm, Me.Name
End
Sub
Quelques explications…
Ici, on ferme simplement le formulaire.
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-I. Le formulaire de saisie de l'association Contrat-Communes (frmDataWizard5)▲
Le bouton Ajouter
Private
Sub
cmdAdd_Click
(
)
'On appelle la méthode AddNewOrCancel avec les paramètres attendus
AddNewOrCancel Me, NEXT_FORM_ID -
1
, TARGET_TABLE, FIELD_COLLECTION, "cboDepartement"
, True
, NEXT_FORM_ID
End
Sub
Quelques explications…
On appelle ici la procédure AddNewOrCancel () vue et détaillée ci-après pour ajouter ou annuler un enregistrement.
Le bouton Supprimer
Private
Sub
cmdDelete_Click
(
)
Dim
SQLDelete As
String
Dim
strSubject As
String
If
Not
IsNull
(
Me.txtIDCommune
) Then
strSubject =
"Le contrat "
&
Me.txtIDContrat
&
"de la commune "
&
Me.txtNomCommune
SQLDelete =
DELETE_RECORD_SQL &
Replace
(
Replace
(
WHERE_CONDITION, "#1"
, Me.txtIDCommune
), "#2"
, Me.txtIDContrat
)
'On appelle la méthode DeleteOrSaveRecord avec les paramètres attendus
DeleteOrSaveRecord Me, 3
, Me.txtIDCommune
, SQLDelete, strSubject
End
If
End
Sub
Quelques explications…
Si l'identifiant cible n'est pas nul alors :
- on alimente la chaîne strSubject du contexte qui fera office de confirmation du message de suppression ;
- on élabore la clause SQL de suppression dans la variable SQLDelete avec les constantes de l'en-tête dûment remplacées par la fonction Replace() ;
- on appelle la procédure DeleteOrSaveRecord () avec les paramètres attendus.
Le bouton Suivant
Private
Sub
cmdNext_Click
(
)
'On appelle la procédure pour ouvrir le formulaire suivant
OpenTheForm GotoNext, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, True
, False
End
Sub
Quelques explications…
On accède au formulaire suivant à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le bouton Précédent
Private
Sub
cmdPrevious_Click
(
)
'On appelle la procédure pour ouvrir le formulaire précédent
OpenTheForm GotoPrevious, Me, NEXT_FORM_ID, PREVIOUS_FORM_ID, TARGET_TABLE, FIELD_COLLECTION, True
, False
End
Sub
Quelques explications…
On accède au formulaire précédent à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-J. Le sous-formulaire de saisie des communes (frmDataWizard5_sub)▲
Le contrôle chkCompleted
Private
Sub
chkCompleted_MouseUp
(
Button As
Integer
, Shift As
Integer
, X As
Single
, Y As
Single
)
Me.IDContrat.SetFocus
End
Sub
Quelques explications…
Si l'utilisateur tente de cliquer sur la case à cocher, on donne le focus au premier contrôle.
Le contrôle IDCommune
Private
Sub
IDCommune_NotInList
(
NewData As
String
, Response
As
Integer
)
'On appelle la méthode NotInList pour avertir de la non-correspondance
Response
=
NotInList
(
NewData, "La commune"
)
End
Sub
Quelques explications…
On appelle ici la fonction NotInList() vue et détaillée ci-après…
Le contrôle IDContrat
Private
Sub
IDContrat_NotInList
(
NewData As
String
, Response
As
Integer
)
'On appelle la méthode NotInList pour avertir de la non-correspondance
Response
=
NotInList
(
NewData, "Le contrat"
)
End
Sub
Quelques explications…
On appelle ici la fonction NotInList() vue et détaillée ci-après…
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XII-K. Le formulaire de fin (frmEnd)▲
Le bouton Début
Private
Sub
cmdFirst_Click
(
)
'On accède au premier écran
DoCmd.Close
acForm, Me.Name
DoCmd.OpenForm
FORM_START, , , , , acDialog
End
Sub
Quelques explications…
Très simplement, ici on ferme ce formulaire et on ouvre le premier, c'est-à-dire celui de l'accueil défini par la constante FORM_START.
Le bouton Précédent
Private
Sub
cmdPrevious_Click
(
)
'On bascule sur l'écran précédent selon l'index
If
PREVIOUS_FORM_ID Then
DoCmd.Close
acForm, Me.Name
DoCmd.OpenForm
FORM_DATA_WIZ &
PREVIOUS_FORM_ID, , , , , acDialog
Else
DoCmd.Close
acForm, Me.Name
DoCmd.OpenForm
FORM_START, , , , , acDialog
End
If
End
Sub
Quelques explications…
S'il existe une constante PREVIOUS_FORM_ID avec une valeur différente de zéro alors on considère qu'il y a un formulaire à afficher autre que celui de l'accueil ; sinon, on accède à ce dernier.
On accède alors au formulaire ciblé à l'aide de la fonction OpenTheForm () vue et détaillée ci-après…
Le bouton Terminer
Private
Sub
cmdEnd_Click
(
)
Dim
strMsgData As
String
'On vérifie que tout est rempli par étape :
'On initialise le message en conséquence
If
m_blnCompleted Then
strMsgData =
"Tous les modules sont complétés"
&
vbCrLf
&
vbCrLf
&
"Voulez-vous quitter l'application ?"
Else
strMsgData =
"Toutes les données n'ont pas été saisies."
&
vbCrLf
&
vbCrLf
&
IIf
(
m_intCount =
0
, "Aucune étape n'a été correctement remplie !"
, Trim
(
str
(
m_intCount)) &
" étape(s) a été correctement remplie(s) sur un total de "
&
MAX_STEP_WIZ &
"."
) &
vbCrLf
&
vbCrLf
&
"Êtes-vous certain de vouloir quitter ?"
End
If
'On affiche alors le message
If
MsgBox
(
strMsgData, 292
, "Quitter"
) =
6
Then
'On quitte
Application.Quit
acQuitSaveAll
End
If
End
Sub
Quelques explications…
Selon l'état de m_blnCompleted, le message de la variable strMsgData change.
Un MsgBox est affiché pour confirmer la fermeture de l'application.
Il n'y a pas d'autre événement sur les contrôles pour ce formulaire.
XIII. Les fonctions et procédures locales au sein des différents formulaires▲
Seul le formulaire de saisie du Site possède une procédure privée locale.
XIII-A. Le formulaire de saisie du site (frmDataWizard1)▲
SIGNET InitIDCommune
XIII-A-1. La procédure locale InitIDCommune▲
Private
Sub
InitIDCommune
(
)
Dim
strIDDepartement As
String
'Vérifie si une commune a déjà été spécifiée et agit en conséquence sur
'la zone modifiable (qui est indépendante) qui contient les départements
With
Me.IDCommune
If
Nz
(
.Value
, 0
) Then
strIDDepartement =
.Column
(
2
)
.Enabled
=
True
End
If
End
With
Me.cboDeptRegion.Value
=
strIDDepartement
End
Sub
Quelques explications…
Cette procédure vérifie s'il y a une commune définie pour le site et le cas échéant, affecte la valeur du département et de la région en conséquence dans la zone de liste cboDeptRegion, du fait que celle-ci est indépendante et donc attachée à aucune source de contrôle.
Il est à noter que lors de la première utilisation, chacune des zones reste vide.
XIV. Les modules externes▲
Dans ce projet se trouvent deux modules :
- un dédié aux fonctions diverses ;
- l'autre dédié à encapsuler l'ensemble des fonctions et procédures liées directement aux formulaires.
XIV-A. VII-A. Le Module basFormsFunctions▲
XIV-A-1. L'en-tête de la feuille▲
L'en-tête ici ne comporte aucune constante ou variable.
'**********************************************************************
' Module : basFormsFunctions
' Type : Module
' DateTime : 30/07/2015
' Author : Argyronet
' Review : 23/09/2015 - Jean-Philippe AMBROSINO
' Review date : 27/11/2015
' Purpose : Module contenant les procédures et fonctions génériques [événementielles] des formulaires
'**********************************************************************
Option
Compare Database
Option
Explicit
XIV-A-2. La procédure événementielle FormCurrent▲
Cette procédure se substitue à la procédure événementielle Form_Current qui se traduit dans les propriétés événementielles par Sur activation.
Dans ce projet, cette procédure est uniquement utilisée au sein des formulaires.
On affecte à l'objet oSubForm le formulaire basé sur la constante SUBFORM_DATA_WIZ puisque tous les sous-formulaires portent le même nom, quel que soit le formulaire parent.
Ceci est plus commode pour la souplesse du code et de l'usage d'appels génériques d'objets comme les formulaires.
L'objet DoCmd exploite la méthode GoToRecord avec le paramètre acLast afin de positionner le sous-formulaire sur le dernier enregistrement.
Il donne alors le focus au contrôle FirstControl passé en paramètre.
Public
Sub
FormCurrent
(
ByRef
TargetForm As
Form, ByVal
FirstControl As
String
)
'---------------------------------------------------------------------------
' Sub : FormCurrent
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Procédure générique de substitution de l'événement Current d'un formulaire simple
'...........................................................................
' Parameters : TargetForm : Formulaire cible
' FirstControl : Nom du 1er contrôle
' Return Codes : None
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
oSubForm As
SubForm
Dim
oControl As
Control
With
TargetForm
'On définit le sous-formulaire
Set
oSubForm =
.Form
(
SUBFORM_DATA_WIZ)
'On donne le focus au sous-formulaire
With
oSubForm
.SetFocus
On
Error
Resume
Next
'On pointe le dernier enregistrement s'il en existe (erreur optimiste)
DoCmd.GoToRecord
, , acLast
'On définit le contrôle auquel donner le focus
Set
oControl =
.Controls
(
FirstControl)
oControl.SetFocus
End
With
End
With
'Libération des objets
Set
oControl =
Nothing
Set
oSubForm =
Nothing
End
Sub
XIV-A-3. La procédure événementielle SubFormCurrent▲
Cette procédure se substitue elle aussi à la procédure événementielle Form_Current qui se traduit dans les propriétés événementielles par Sur activation.
Dans ce projet, cette procédure est uniquement utilisée au sein des sous-formulaires.
Comme il est fort probable qu'une erreur soit levée par le fait que le formulaire réagit en fonction des données, on pose une instruction d'erreur optimiste.
En effet, les fonctions de domaines sont susceptibles de renvoyer les erreurs à partir du moment où les champs ne permettent pas d'établir le calcul attendu.
On emploie alors l'instruction On Error Resume Next parce qu'ici, elle est maîtrisée.
Rappel
Vous ne devez employer cette instruction que si, et seulement si, vous en maîtrisez l'exécution.
Cet événement est produit lorsque le focus passe à un enregistrement donné pour en faire l'enregistrement activé, ou lorsque le formulaire est actualisé ou qu'il fait l'objet d'une nouvelle requête.
- La variable lngCount récupère la valeur du champ txtCountRows et la variable blnCompleted récupère la valeur du champ txtCompleted, tous deux situés dans le formulaire parent.
- Par prudence, et surtout pour les débutants, j'ai greffé l'interception de l'erreur 2147352567 afin de prévenir le développeur qu'il a oublié un truc quelque part…
Dans l'absolu, cette erreur ne devrait jamais être levée. - Si lngCount retourne une valeur, alors le contrôle étiquette lblCountRows reçoit une chaîne récapitulant le nombre d'enregistrements en genre et en nombre et sa couleur passe du vert au rouge selon que la ligne est complétée ou non.
Public
Sub
SubFormCurrent
(
ByRef
TargetSubForm As
Form, ByVal
ItemData As
String
, ByVal
IsFemale As
Boolean
)
'---------------------------------------------------------------------------
' Sub : SubFormCurrent
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Procédure générique de substitution de l'événement Current d'un formulaire simple
'...........................................................................
' Parameters : TargetForm : Formulaire cible
' ItemData : Sujet du contenu
' IsFemale : True pour changer le genre des textes
' Return Codes : None
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
lngCount As
Long
Dim
blnCompleted As
Boolean
'On pose une gestion d'erreurs optimiste contrôlée
On
Error
Resume
Next
'On compte le nombre d'enregistrements
lngCount =
Nz
(
TargetSubForm.txtCountRows
, 0
)
'On vérifie si la ligne en cours est complète
blnCompleted =
Nz
(
TargetSubForm.txtCompleted
, False
)
'Il est probable qu'une erreur définie par l'application ou par l'objet soit levée :
'on la gère de façon optimiste et n'en tient pas compte
If
Err
=
-
2147352567
Then
MsgBox
"Attention..."
&
vbCrLf
&
"Vérifier que la source de contrôle du sous-formulaire '"
&
TargetSubForm.Name
&
"' est correcte !"
, vbExclamation
, "Message développeur"
Err
.Clear
End
If
'S'il existe des enregistrements
If
lngCount Then
With
TargetSubForm.Parent
'On adapte l'intulé du label avec le nombre
.lblCountRows.Caption
=
lngCount &
ItemData &
"(s) enregistré"
&
IIf
(
IsFemale, "e"
, ""
) &
"(s)"
With
.lblRecCompleted
'On adapte l'intitulé du label avec le texte et la couleur correspondante
.Caption
=
"Ligne "
&
IIf
(
blnCompleted, "complète"
, "incomplète"
)
.ForeColor
=
IIf
(
blnCompleted, CLR_GREENCOLOR, CLR_REDCOLOR)
End
With
.cmdDelete.Caption
=
CMD_DELETE
End
With
End
If
End
Sub
XIV-A-4. La procédure OpenTheForm▲
Cette procédure publique permet d'ouvrir un formulaire de façon personnalisée.
Elle est utilisée ici dans la navigation depuis les boutons intitulés Précédent et Suivant avec par le paramètre GotoDirection.
Avant de fermer le formulaire en cours et ouvrir l'autre, selon que l'on ait affaire à un formulaire simple ou un sous-formulaire, les fonctions DataFormCompleted() ou DataSubFormCompleted() sont appelées afin d'avertir, par l'intermédiaire d'un MsgBox(),que les données ne sont pas complétées comme il se doit.
Du fait que ce message permette d'ignorer, l'utilisateur peut faire abstraction de cette alerte et continuer pour passer effectivement au formulaire qu'il a choisi, en cliquant respectivement sur le bouton approprié dans le sens de la navigation souhaitée, selon la valeur du paramètre GotoDirection.
Le formulaire courant est alors fermé :
- un examen du paramètre IsLastStep est effectué afin de vérifier si l'on est à la dernière étape ou non, auquel cas on ouvre le formulaire de fin frmEnd ;
- sinon, on ouvre le formulaire basé sur l'index.
Public
Sub
OpenTheForm
(
ByVal
GotoDirection As
ge_FormDirection, ByRef
TargetForm As
Form, ByVal
NextFormID As
Long
, ByVal
PreviousFormID As
Long
, ByVal
TableSource As
String
, ByVal
FieldCollection As
String
, ByVal
FormWithSubForm As
Boolean
, Optional
ByVal
IsLastStep As
Boolean
=
False
)
'---------------------------------------------------------------------------
' Sub : OpenTheForm
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Procédure générique de substitution de la méthode OpenForm
'...........................................................................
' Parameters : GotoDirection : Sens (précédent/suivant)
' TargetForm : Formulaire cible
' NextFormID : ID du formulaire suivant
' PreviousFormID : ID du formulaire précédent
' TableSource : Table ou requête source
' FieldCollection : Noms des champs utilisés
' FormWithSubForm = True s'il y a un sous-formulaire
' Return Codes : None
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
SQLSelect As
String
Dim
intFormIndex As
Integer
On
Error
GoTo
L_ErrOpenTheForm
'On établit la clause Select fondée sur la table source
SQLSelect =
"SELECT * FROM "
&
TableSource
'Si l'on vérifie le sous-formulaire...
If
FormWithSubForm Then
'Si tous les champs du sous-formulaire ne sont pas renseignés...
If
DataSubFormCompleted
(
TableSource, FieldCollection, False
, NextFormID, IsLastStep) =
vbNo
Then
Exit
Sub
Else
'Si tous les champs du formulaire ne sont pas renseignés...
If
DataFormCompleted
(
TargetForm, False
, FieldCollection, NextFormID, IsLastStep) =
vbNo
Then
Exit
Sub
End
If
'Selon le sens de navigation, on définit la variable de l'index du formulaire cible
If
GotoDirection =
GotoNext Then
intFormIndex =
NextFormID
Else
intFormIndex =
PreviousFormID
End
If
'On ferme ce formulaire
DoCmd.Close
acForm, TargetForm.Name
'Si l'on arrive à la dernière étape...
If
IsLastStep Then
'Dernier identifiant : on ouvre le formulaire de fin
DoCmd.OpenForm
FORM_END, , , , , acDialog
Else
'On ouvre le suivant ou précédent
If
intFormIndex Then
DoCmd.OpenForm
FORM_DATA_WIZ &
intFormIndex, , , , , acDialog
Else
DoCmd.OpenForm
FORM_START, , , , , acDialog
End
If
End
If
On
Error
GoTo
0
L_ExOpenTheForm
:
Exit
Sub
L_ErrOpenTheForm
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExOpenTheForm
End
Sub
XIV-A-5. La fonction événementielle FormDataErrors()▲
Cette procédure générique se substitue de façon enrichie à l'événement Form_Error().
Du fait de la différence possible entre formulaire simple et sous-formulaire, cette fonction est indépendante.
On utilise ici un Select Case où l'on passe des conditions émises par des constantes dont les valeurs sont expressément les valeurs typiquement rencontrées dans cet événement.
Je suis bien conscient qu'il peut y en avoir d'autres, d'où le Case Else (à ne jamais oublier dans un tel bloc), mais pour ce projet tel que développé, cela n'entrait pas en considération.
La fonction retourne la valeur conséquente à la valeur logique de (Response = acDataErrContinue).
Public
Function
FormDataErrors
(
ByVal
DataErr As
Integer
, ByRef
Message As
String
, ByRef
Response
As
Integer
, Optional
ByRef
TargetForm As
Form) As
Boolean
'---------------------------------------------------------------------------
' Function : FormDataErrors
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Procédure générique de substitution de l'événement Form_Error
'...........................................................................
' Parameters : DataErr : Erreur de données
' Message : Message de retour
' Response : Flag de comportement de la réponse suite à l'erreur
' TargetForm : Formulaire cible
' Return Codes : Boolean = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Const
RESET_VBA_CODE As
Integer
=
29013
Const
INDEX_DOUBLONS As
Integer
=
3022
Const
INPUT_MASK_VIOLATION As
Integer
=
2279
Const
NOT_IN_LIST As
Integer
=
2237
Const
INVALID_INPUTMASK As
Integer
=
2113
Message =
vbNullString
Select
Case
DataErr
'Non-respect du masque de saisie
Case
INPUT_MASK_VIOLATION
Response
=
acDataErrContinue
Message =
"Attention !"
&
vbCrLf
&
"Le masque de saisie du champ doit être respecté."
'Élément absent de la liste
Case
NOT_IN_LIST
Response
=
acDataErrContinue
Message =
"Attention !"
&
vbCrLf
&
"Veuillez choisir un élément dans la liste..."
'Doublon ou tentative d'action de réinitialisation du code en cours d'exécution
Case
INDEX_DOUBLONS, RESET_VBA_CODE
Response
=
acDataErrDisplay
Message =
"Attention !"
&
vbCrLf
&
"Vous avez déjà saisi ou bien il existe un enregistrement identique dans la base !"
'Mauvais usage du masque de saisie
Case
INVALID_INPUTMASK
Response
=
acDataErrContinue
Message =
"Attention !"
&
vbCrLf
&
"La valeur est non valide pour ce champ..."
&
vbCrLf
&
vbCrLf
&
"Vous avez peut-être entré du texte dans un champ numérique ou un nombre supérieur à ce que permet la taille du champ ou encore une date incohérente."
'Toute autre cause...
Case
Else
Response
=
acDataErrContinue
Message =
"Attention !"
&
vbCrLf
&
"La valeur que vous avez tapée est incorrecte..."
If
Not
TargetForm Is
Nothing
Then
With
TargetForm.ActiveControl
On
Error
Resume
Next
'On annule le contenu du champ s'il est accessible
.Undo
Err
.Clear
.SetFocus
End
With
End
If
End
Select
'Valeur de retour
FormDataErrors =
(
Response
=
acDataErrContinue)
End
Function
XIV-A-6. La procédure événementielle SubFormDataError▲
Cette procédure générique se substitue de façon enrichie à l'événement Form_Error() et est écrite dans le même esprit que la fonction ci-avant FormDataErrors() à ceci près qu'elle est exploitée uniquement par les sous-formulaires.
Public
Sub
SubFormDataError
(
TargetForm As
Form, DataErr As
Integer
, Response
As
Integer
, ByVal
TargetDataName As
String
)
'---------------------------------------------------------------------------
' Function : SubFormDataError
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Procédure générique de substitution de l'événement Form_Error pour les sous-formulaires
'...........................................................................
' Parameters : TargetForm : Formulaire cible
' DataErr : Erreur de données
' Response : Flag de comportement de la réponse suite à l'erreur
' TargetDataName : Sujet de la donnée concernée
'
' Return Codes : Boolean = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Const
INVALID_INPUTMASK As
Integer
=
2113
Const
INDEX_DOUBLONS As
Integer
=
3022
Const
VALUE_IS_REQUIRED As
Integer
=
3314
Select
Case
DataErr
Case
INVALID_INPUTMASK
'Ne devrait jamais arriver sauf si vous avez inversé la colonne liée
MsgBox
"Attention : "
&
vbCrLf
&
"Valeur non valide pour ce champ.Vous avez peut-être entré du texte dans un champ numérique ou un nombre supérieur à ce que permet sa taille."
, vbExclamation
, "Valeur incompatible"
Case
VALUE_IS_REQUIRED
'Donnée requise
If
MsgBox
(
"Vous devez d'abord inscrire une valeur dans chaque champ."
&
vbCrLf
&
vbCrLf
&
"Voulez-vous annuler cet enregistrement ?"
, 52
, "Ligne incomplète"
) =
6
Then
On
Error
Resume
Next
DoCmd.RunCommand
acCmdUndo
On
Error
GoTo
0
With
TargetForm.Parent
.cmdAdd.Caption
=
CMD_ADD
.cmdDelete.Caption
=
CMD_DELETE
End
With
End
If
Case
INDEX_DOUBLONS
'Risque de doublons dans champs index
MsgBox
"Attention : "
&
vbCrLf
&
"Vous avez créé un doublon :"
&
vbCrLf
&
"("
&
TargetDataName &
")."
&
vbCrLf
&
"Veuillez modifier votre saisie ou bien annuler la ligne (Echap)."
, vbExclamation
, "Ligne dupliquée"
Case
Else
'Toute autre raison
MsgBox
"Attention : "
&
vbCrLf
&
"Veuillez d'abord compléter la ligne avant de passer à une autre ou d'effectuer une autre opération."
, vbExclamation
, "Action non conventionnelle"
End
Select
Response
=
acDataErrContinue
End
Sub
XIV-A-7. La fonction publique DataFormCompleted()▲
Cette fonction permet de vérifier qu'un formulaire simple est correctement alimenté, sous-entendu, qu'il ne manque pas une valeur dans un des champs.
Cette fonction parcourt tous les champs du formulaire afin d'en vérifier la nullité.
Pour ce faire, on utilise un tableau de Strings alimenté avec la collection de champs et on affecte chacun d'eux à une variable objet de type Control.
Rappel
Tous les champs des formulaires simples voient leur propriété Tag définie à Null ou NotNull :
- Null : la valeur vide ou nulle est autorisée :
- NotNull : la valeur vide ou nulle est interdite.
Il est vrai que l'on aurait pu exploiter la propriété Null Interdit issue de la table, mais je pars du principe que pour ce projet, c'était démesuré et cela aurait nécessité du code un peu plus complexe pour finalement, aboutir au même résultat.
Illustration de la propriété :
Une erreur est levée à partir du moment où la nullité est rencontrée…
- Si tout va bien que l'analyse aboutit, cette procédure appelle FillDataChecker afin d'enrichir le tableau g_intCompletionIndex des étapes.
- Si elle échoue, sous-entendu qu'il manque une valeur dans un des champs, la fonction retourne un MsgBox où la question autorise malgré tout à continuer (opération voulue expressément dans le contexte de ce projet puisque l'on considère que l'opérateur peut très bien ne pas connaître l'information manquante).
Public
Function
DataFormCompleted
(
ByRef
TargetForm As
Form, ByVal
AddNewRecord As
Boolean
, ByVal
FieldControlCollection As
String
, ByVal
NextFormID As
Integer
, Optional
ByVal
IsLastStep As
Boolean
=
False
) As
VbMsgBoxResult
'---------------------------------------------------------------------------
' Function : DataFormCompleted
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Vérifie que les données du formulaire sont complétées
'...........................................................................
' Parameters : TargetForm : Formulaire cible
' AddNewRecord : True si mode ajout
' FieldControlCollection : Liste des champs utilisés
' NextFormID : ID du formulaire suivant
' Return Codes : VbMsgBoxResult = Réponse au Msgbox
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Const
ADD_MESSAGE As
String
=
"Avant d'ajouter un nouvel enregistrement, vous devez faire en sorte que l'enregistrement en cours soit complété."
Const
ERR_MESSAGE As
String
=
"Avant de changer d'écran, vous devez faire en sorte que ce formulaire possède au moins un enregistrement représentant un site."
Const
IGNORE_MESSAGE As
String
=
vbCrLf
&
vbCrLf
&
"Voulez-vous ignorer ce message et continuer ?"
Dim
strMessage As
String
Dim
straFieldControlCollection
(
) As
String
Dim
D As
Integer
Dim
oControl As
Control
On
Error
GoTo
L_ErrDataFormCompleted
'On affecte le bon message selon le mode
If
AddNewRecord Then
strMessage =
ADD_MESSAGE &
IGNORE_MESSAGE
Else
strMessage =
ERR_MESSAGE &
IGNORE_MESSAGE
End
If
'Affectation du tableau de champs
straFieldControlCollection =
Split
(
FieldControlCollection, ";"
)
'Pour chacun des champs
For
D =
LBound
(
straFieldControlCollection) To
UBound
(
straFieldControlCollection)
'On affecte l'objet au contrôle du formulaire
Set
oControl =
TargetForm.Controls
(
straFieldControlCollection
(
D))
With
oControl
'S'il est nul
If
IsNull
(
.Value
) Then
'Si la propriété Remarque spécifie l'interdiction du Null
If
.Tag
=
"NotNull"
Then
'On lève une erreur
Err
.Raise
94
, "Donnée requise"
, strMessage
End
If
End
If
End
With
Next
'On enrichit le tableau récapitulatif de vérification
If
IsLastStep Then
'Si c'est la dernière, on prend l'index de la constante
Call
FillDataChecker
(
MAX_STEP_WIZ, True
)
Else
'Celle en cours
Call
FillDataChecker
(
NextFormID -
1
, True
)
End
If
DataFormCompleted =
True
On
Error
GoTo
0
L_ExDataFormCompleted
:
Set
oControl =
Nothing
Exit
Function
L_ErrDataFormCompleted
:
'En cas d'erreur (optimiste, on vérifie les data), la fonction retourne un MsgBox
DataFormCompleted =
MsgBox
(
Err
.Description
, vbExclamation
+
vbYesNo
, Err
.Source
)
'On décrémente le tableau récapitulatif de vérification pour cette étape
If
Not
IsLastStep Then
Call
FillDataChecker
(
NextFormID -
1
, False
)
End
If
Resume
L_ExDataFormCompleted
End
Function
XIV-A-8. La fonction publique DataSubFormCompleted()▲
Cette fonction permet de vérifier qu'un sous-formulaire est correctement alimenté, sous-entendu, qu'il ne manque pas une valeur dans un des champs.
Elle appelle la fonction privée VerifyFormDataTable() afin de lire chaque enregistrement, champ par champ.
- Si tout va bien que l'analyse aboutit, cette procédure appelle FillDataChecker afin d'enrichir le tableau g_intCompletionIndex des étapes.
- Si elle échoue, sous-entendu qu'il manque une valeur quelque part, la fonction retourne un MsgBox où la question autorise malgré tout à continuer (opération voulue expressément dans le contexte de ce projet puisque l'on considère que l'opérateur peut très bien ne pas connaître l'information manquante).
Public
Function
DataSubFormCompleted
(
ByVal
TargetTable As
String
, ByVal
FieldCollection As
String
, ByVal
AddNewRecord As
Boolean
, ByVal
NextFormID As
Integer
, Optional
ByVal
IsLastStep As
Boolean
=
False
) As
VbMsgBoxResult
'---------------------------------------------------------------------------
' Function : DataSubFormCompleted
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Vérifie que les données du sous-formulaire sont complétées
'...........................................................................
' Parameters : TargetTable : Table source
' FieldControlCollection : Liste des champs utilisés
' AddNewRecord : True si mode ajout
' NextFormID : ID du formulaire suivant
' Return Codes : VbMsgBoxResult = Réponse au Msgbox
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Const
ADD_MESSAGE As
String
=
"Avant d'ajouter un nouvel enregistrement, vous devez faire en sorte que l'enregistrement en cours soit complété."
Const
ERR_MESSAGE As
String
=
"Avant de changer d'écran, vous devez faire en sorte que : "
&
vbCrLf
&
" - que l'enregistrement en cours soit complété."
&
vbCrLf
&
" - le formulaire possède au moins un enregistrement."
Const
IGNORE_MESSAGE As
String
=
vbCrLf
&
vbCrLf
&
"Voulez-vous ignorer ce message et continuer ?"
Dim
strMessage As
String
Dim
blnAddNew As
Boolean
On
Error
GoTo
L_ErrDataSubFormCompleted
'On affecte le bon message selon le mode
If
AddNewRecord Then
strMessage =
ADD_MESSAGE &
IGNORE_MESSAGE
Else
strMessage =
ERR_MESSAGE &
IGNORE_MESSAGE
End
If
'On appelle la fonction de vérification des données dans la table
If
VerifyFormDataTable
(
TargetTable, FieldCollection) =
False
Then
Err
.Raise
94
, "Données requises"
, strMessage
Else
'On enrichit le tableau récapitulatif de vérification
If
IsLastStep Then
'Si c'est la dernière, on prend l'index de la constante
Call
FillDataChecker
(
MAX_STEP_WIZ, True
)
Else
'Celle en cours
Call
FillDataChecker
(
NextFormID -
1
, True
)
End
If
End
If
On
Error
GoTo
0
L_ExDataSubFormCompleted
:
Exit
Function
L_ErrDataSubFormCompleted
:
'En cas d'erreur (optimiste, on vérifie les data), la fonction retourne un MsgBox
DataSubFormCompleted =
MsgBox
(
Err
.Description
, vbExclamation
+
vbYesNo
, Err
.Source
)
'On décrémente le tableau récapitulatif de vérification pour cette étape
If
NextFormID <>
LAST_FORM_INDEX Then
Call
FillDataChecker
(
NextFormID -
1
, False
)
End
If
Resume
L_ExDataSubFormCompleted
End
Function
XIV-A-9. La fonction privée VerifyFormDataTable()▲
Cette fonction permet de vérifier la complétude de la table source et la collection de champs de cette table utilisée dans les sous-formulaires (certes, on aurait pu parcourir cette collection via l'objet Fields, mais ce n'est pas nécessaire ici).
Private
Function
VerifyFormDataTable
(
ByVal
TargetTable As
String
, ByVal
FieldCollection As
String
) As
Boolean
'---------------------------------------------------------------------------
' Function : VerifyFormDataTable
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Contrôle champ par champ la nullité du contenu
'...........................................................................
' Parameters : TargetTable : Table ou requête source
' FieldCollection : Champs de la source
' Return Codes : Boolean = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
SQLSelect As
String
Dim
oRS As
DAO.Recordset
Dim
straFields
(
) As
String
Dim
strFieldName As
String
Dim
vntValue As
Variant
Dim
F As
Integer
Dim
lngNBRecords As
Long
Dim
lngRowCount As
Long
Dim
blnDataMissing As
Boolean
On
Error
GoTo
L_ErrVerifyFormDataTable
blnDataMissing =
False
'Clause SQL sélectionnant tous les enregistrements de la table
SQLSelect =
"SELECT * FROM "
&
TargetTable &
";"
'Ouverture du Recordset
Set
oRS =
CurrentDb.OpenRecordset
(
SQLSelect, 2
)
'Affectation du tableau de champs
straFields =
Split
(
FieldCollection, ";"
)
With
oRS
If
Not
.EOF
Then
.MoveLast
'On compte le nombre d'enregistrements
lngNBRecords =
.RecordCount
.MoveFirst
Do
While
Not
.EOF
lngRowCount =
lngRowCount +
1
'Pour chacun des champs
For
F =
LBound
(
straFields) To
UBound
(
straFields)
'On attribue son nom à la variable
strFieldName =
straFields
(
F)
'On verifie s'il est null
If
IsNull
(
.Fields
(
strFieldName)) Then
'Auquel cas, on sort en attribuant True à la variable
blnDataMissing =
True
Exit
For
End
If
Next
'À partir du moment où la variable est True, il est inutile de continuer, il y a une omission.
If
blnDataMissing Then
Exit
Do
End
If
.MoveNext
Loop
Else
'S'il n'y a aucun enregistrement
Err
.Raise
3021
End
If
'On ferme le Recordset
.Close
End
With
'La fonction retourne la négation logique de la valeur de la variable
VerifyFormDataTable =
Not
blnDataMissing
On
Error
GoTo
0
L_ExVerifyFormDataTable
:
'On libère l'objet
Set
oRS =
Nothing
Exit
Function
L_ErrVerifyFormDataTable
:
VerifyFormDataTable =
False
Resume
L_ExVerifyFormDataTable
End
Function
XIV-A-10. La procédure publique AddNewOrCancel▲
Cette procédure permet d'ajouter ou d'annuler un enregistrement selon l'intitulé du bouton passé en paramètre par le biais de l'objet Form.
On lui passe l'index du sous-formulaire, le nom de la table source, la collection de champs de cette table, le nom du premier contrôle devant être focalisé, la valeur de l'ID principal (ici celui du site), la valeur de l'index du prochain formulaire et la valeur permettant de savoir si on arrive à la dernière étape…
-
Si le bouton porte l'intitulé Ajouter :
- s'il s'agit d'un sous-formulaire, on ajoute une ligne vide via la méthode GoToRecord avec le paramètre acNewRec de l'objet DoCmd ;
- s'il s'agit d'un formulaire simple, on appelle la fonction DataFormCompleted() afin d'empêcher l'ajout s'il n'est pas complété.
- Si le bouton porte l'intitulé Annuler, on invoque un simple RunCommand avec le paramètre acCmdUndo de l'objet DoCmd.
Public
Sub
AddNewOrCancel
(
ByRef
TargetForm As
Form, ByVal
SubFormIndex As
Integer
, ByVal
TableSource As
String
, ByVal
FieldCollection As
String
, ByVal
FirstControl As
String
, ByVal
SharedForeignIdentity As
Boolean
, ByVal
NextFormID As
Integer
, Optional
ByVal
IsLastStep As
Boolean
=
False
)
'---------------------------------------------------------------------------
' Sub : AddNewOrCancel
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Double procédure permettant d'ajouter un nouvel enregistrement ou d'annuler celui en cours de saisie
'...........................................................................
' Parameters : TargetForm : Formulaire cible
' SubFormIndex : Si <> 0 signifie qu'il y a un sous-formulaire
' TableSource : Table ou requête source
' FieldCollection : Liste des champs de la source
' FirstControl : Nom du 1er contrôle
' SharedForeignIdentity : True si la source contient une valeur primaire commune (ici NoSite)
' NextFormID = ID du formulaire suivant
' Return Codes : None
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
oSubForm As
Form
With
TargetForm
'Si la légende est {Annuler}
Select
Case
.cmdAdd.Caption
Case
CMD_CANCEL
'On demande confirmation de l'annulation
If
MsgBox
(
"Voulez-vous annuler l'ajout en cours ?"
, vbQuestion
+
vbYesNo
, "Annuler"
) =
vbYes
Then
'On pose une gestion d'erreurs optimiste
On
Error
Resume
Next
'On appelle la méthode RunCommand de la constante AcCommand permettant l'annulation en cours
DoCmd.RunCommand
acCmdUndo
'On réinitialise le gestionnaire d'erreurs
On
Error
GoTo
0
'On change l'intitulé des boutons
.cmdAdd.Caption
=
CMD_ADD
.cmdDelete.Caption
=
CMD_DELETE
End
If
'Si la légende est {Ajouter}
Case
CMD_ADD
'On met à jour les données sous-jacentes du formulaire en actualisant les modifications apportées aux enregistrements
TargetForm.Requery
'S'il y existe un index, on affecte l'objet oSubForm au sous-formulaire
'(SubFormIndex=0 s'il n'y a pas de sous-formulaire)
If
SubFormIndex Then
'On affecte l'objet à ce sous-formulaire
Set
oSubForm =
Forms
(
FORM_DATA_WIZ &
SubFormIndex)
With
oSubForm
'On donne le focus au sous-formulaire
.SetFocus
On
Error
Resume
Next
DoCmd.GoToRecord
, , acNewRec
'Si la table contient le N° du site...
If
SharedForeignIdentity Then
'On affecte au champ (ici : [NoSite]), la valeur de la variable publique
'qui contient sa valeur en cours.
.Form.NoSite
=
g_strNoSiteEnCours
End
If
'On donne le focus au premier contrôle disponible
.Form.Controls
(
FirstControl).SetFocus
'On réinitialise le gestionnaire d'erreurs
On
Error
GoTo
0
End
With
Else
'On appelle la fonction interne DataFormCompleted() afin de vérifier si l'ajout est possible
If
DataFormCompleted
(
TargetForm, False
, FieldCollection, NextFormID, IsLastStep) =
vbNo
Then
Exit
Sub
End
If
'On change l'intitulé des boutons
.cmdAdd.Caption
=
CMD_CANCEL
.cmdDelete.Caption
=
CMD_SAVE
End
Select
End
With
'On libère l'objet...
Set
oSubForm =
Nothing
End
Sub
XIV-A-11. La procédure publique DeleteOrSaveRecord▲
Cette procédure permet de supprimer ou de sauvegarder un enregistrement selon l'intitulé du bouton passé en paramètre par le biais de l'objet Form.
On lui passe l'index du sous-formulaire, la valeur cible (ID), la clause SQL de suppression et le sujet illustrant le contexte.
- Si le bouton porte l'intitulé Supprimer, on invoque un Excecute de l'objet CurrentDB.
- Si le bouton porte l'intitulé Sauvegarder, on invoque un simple Requery.
Public
Sub
DeleteOrSaveRecord
(
ByRef
TargetForm As
Form, ByVal
SubFormIndex As
Integer
, ByVal
TargetIDValue As
Variant
, ByVal
DeleteClause As
String
, ByVal
Subject As
String
)
'---------------------------------------------------------------------------
' Sub : DeleteOrSaveRecord
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Double procédure permettant d'effacer un enregistrement ou de le sauvegarder
'...........................................................................
' Parameters : TargetForm : Formulaire cible
' SubFormIndex : Si <> 0, on agit sur le sous-formulaire
' TargetIDValue : Valeur de l'identifiant
' DeleteClause : Clause SQL DELETE FROM
' Subject : Sujet de l'élément à supprimer
' Return Codes : = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
oSubForm As
Form
On
Error
GoTo
L_ErrDeleteOrSaveRecord
'S'il y existe un index (SubFormIndex=0 s'il n'y a pas de sous-formulaire)
If
SubFormIndex Then
'On affecte l'objet à ce sous-formulaire
Set
oSubForm =
TargetForm.Form
(
FORM_DATA_WIZ &
SubFormIndex)
End
If
Select
Case
TargetForm.cmdDelete.Caption
'Si la légende est {Supprimer}
Case
CMD_DELETE
'Et si l'identifiant n'est pas nul
If
Not
IsNull
(
TargetIDValue) Then
'On confirme la suppression
If
MsgBox
(
"Êtes-vous certain de vouloir supprimer "
&
Subject &
" ?"
&
vbCrLf
&
vbCrLf
&
"Cette action est irréversible."
, 292
, "Supprimer un employé"
) =
6
Then
'On exécute la requête DELETE
CurrentDb.Execute
DeleteClause, dbFailOnError
'Si c'est le sous-formulaire
If
SubFormIndex Then
oSubForm.Requery
Else
TargetForm.Requery
End
If
End
If
Else
'Si l'identifiant est nul, on lève une erreur
Err
.Raise
94
, "Pas d'identifiant"
, "Il n'y a aucun enregistrement sélectionné qui puisse être supprimé !"
End
If
'On change l'intitulé des boutons
TargetForm.cmdDelete.Caption
=
CMD_DELETE
TargetForm.cmdAdd.Caption
=
CMD_SAVE
'Si la légende est {Sauvegarder}
Case
CMD_SAVE
'Si c'est le sous-formulaire
If
SubFormIndex Then
oSubForm.Requery
Else
TargetForm.Requery
End
If
'On change l'intitulé des boutons
TargetForm.cmdAdd.Caption
=
CMD_ADD
TargetForm.cmdDelete.Caption
=
CMD_DELETE
End
Select
On
Error
GoTo
0
L_ExDeleteOrSaveRecord
:
'On libère l'objet...
Set
oSubForm =
Nothing
Exit
Sub
L_ErrDeleteOrSaveRecord
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExDeleteOrSaveRecord
End
Sub
XIV-A-12. La fonction publique DataTableHasRecord()▲
Cette fonction permet de savoir si une table ou plus exactement ici, une clause SQL fondée sur une table, contient des enregistrements.
Grâce à cette fonction, un message s'affiche en tant qu'alerte pour avertir que le formulaire doit contenir au moins un enregistrement.
Private
Function
DataTableHasRecord
(
ByVal
SQLQuery As
String
) As
Boolean
'---------------------------------------------------------------------------
' Function : DataTableHasRecord
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Vérifie que la source SQLQuery possède des enregistrements
'...........................................................................
' Parameters : SQLQuery :
' Return Codes : Boolean = True if has data
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
oRS As
DAO.Recordset
'On initialise l'objet Recordset avec la chaîne SQL passée en paramètre
Set
oRS =
CurrentDb.OpenRecordset
(
SQLQuery, 2
)
With
oRS
'On renvoie la valeur correspondant à la position d'enregistrement actuelle :
'False = aucun enregistrement
DataTableHasRecord =
Not
.EOF
.Close
End
With
Set
oRS =
Nothing
End
Function
XIV-A-13. La fonction publique NullData()▲
Cette fonction est utilisée dans tous les sous-formulaires afin de calculer la nullité des champs.
Sur le principe, elle retourne 0 si le champ est Null et 1 s'il ne l'est pas, et ce, quel que soit son type.
Remarque
Le type (DataType) ici est défini à l'image des constantes dbText (10), dbLong (4) et dbDate (8) de façon générique.
Au sein de la formule qui l'exploite dans le contrôle txtCheckdata, cette fonction est additionnée à elle-même pour établir une somme d'entiers.
Ainsi, la case à cocher chkCompleted prend la valeur True si la valeur finale de ce champ correspond à la valeur attendue.
Public
Function
NullData
(
ByVal
Ctl As
Variant
, ByVal
DataType As
Integer
) As
Integer
'---------------------------------------------------------------------------
' Function : NullData
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Retourne 1 ou 0 selon la nullité du contenu
'...........................................................................
' Parameters : Ctl : contrôle de formulaire cible
' DataType : Type de donnée du contrôle
' Return Codes : Integer = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
On
Error
GoTo
L_ErrNullData
NullData =
0
If
Not
IsNull
(
Ctl) Then
NullData =
1
End
If
Select
Case
DataType
Case
10
If
Len
(
Nz
(
Ctl, ""
)) Then
NullData =
1
End
If
Case
4
If
(
Ctl >
0
) Then
NullData =
1
ElseIf
(
Ctl =
0
) And
(
Len
(
Ctl) <
2
) Then
NullData =
0
Else
NullData =
Nz
(
Ctl, 0
)
End
If
Case
8
If
IsDate
(
Ctl) Then
NullData =
1
End
If
Case
Else
End
Select
On
Error
GoTo
0
L_ExNullData
:
Exit
Function
L_ErrNullData
:
NullData =
0
Resume
L_ExNullData
End
Function
XIV-A-14. La fonction événementielle publique NotInList()▲
Cette fonction est une réplique générique associée à la rédaction typique de l'événement NotInList() où l'on force le paramètre Response à acDataErrContinue accompagné d'un message personnalisé sans pour autant permettre un ajout en cas de valeur manquante, car cela ne s'y prête pas.
Le message est construit dynamiquement avec le contenu du paramètre ItemSubject.
Vous remarquerez d'ailleurs que l'on passe ici le paramètre NewData et que la valeur Response est la valeur de retour.
Public
Function
NotInList
(
ByVal
NewData As
String
, ByVal
ItemSubject As
String
) As
Integer
'---------------------------------------------------------------------------
' Function : NotInList
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Fonction générique de substitution de l'événement NotInList d'un ComboBox
'...........................................................................
' Parameters : NewData : Valeur que l'utilisateur a entrée dans la zone de liste modifiable.
' ItemSubject : Sujet de la liste déroulante
' Return Codes : Integer = Valeur la fonction NotInList
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
MsgBox
ItemSubject &
" '"
&
NewData &
"' ne fait pas partie de la liste !"
, vbExclamation
, "Choix incorrect"
NotInList =
acDataErrContinue
End
Function
XIV-B. VII-A. Le Module basMain▲
XIV-B-1. L'en-tête de la feuille▲
L'en-tête ici ne comporte pas un grand jeu de constantes, quelques variables et une énumération.
- Les constantes de toutes catégories concernent l'affichage des contrôles masqués, de la définition des étapes et d'index de formulaire, des noms génériques des formulaires, des légendes des boutons et des couleurs des intitulés.
- L'énumération définit les valeurs de direction de la navigation pour les boutons appelant la méthode OpenTheForm avec le paramètre précédent ou suivant…
- Les variables publiques * sont commentées dans le code.
* On n'utilise habituellement pas et par préférence ce type de variable, mais pour un projet de cette envergure et qualifié de jetable dans le jargon des professions en rapport, cela n'a pas grande importance.
'**********************************************************************
' Module : basMain
' Type : Module
' DateTime : 30/07/2015
' Author : Argyronet
' Review : 23/09/2015 - Jean-Philippe AMBROSINO
' Review date : 27/11/2015
' Purpose : Tutoriel : Réalisez un assistant de présaisie des données pour alimenter la base d'un serveur central
'
'**********************************************************************
Option
Compare Database
Option
Explicit
'Affichage ou masquage des contrôles : Prod = False ; Test = True
Public
Const
SHOW_HIDDEN_CONTROLS As
Boolean
=
False
'Constantes de données
Public
Const
MAX_STEP_WIZ As
Integer
=
5
Public
Const
LAST_FORM_INDEX As
Integer
=
99
'Constantes des noms de formulaire
Public
Const
FORM_DATA_WIZ As
String
=
"frmDataWizard"
Public
Const
SUBFORM_DATA_WIZ As
String
=
"sfrmDataWizard"
Public
Const
SUB_FORM_SUFFIX As
String
=
"_sub"
Public
Const
FORM_START As
String
=
"frmStart"
Public
Const
FORM_END As
String
=
"frmEnd"
'Constantes des boutons de commandes
Public
Const
CMD_STOP As
String
=
"&Arrêter"
Public
Const
CMD_CLOSE As
String
=
"&Fermer"
Public
Const
CMD_ADD As
String
=
"Aj&outer"
Public
Const
CMD_SAVE As
String
=
"S&auvegarder"
Public
Const
CMD_VALIDATE As
String
=
"V&alider"
Public
Const
CMD_MODIFY As
String
=
"M&odifier"
Public
Const
CMD_CANCEL As
String
=
"&Annuler"
Public
Const
CMD_DELETE As
String
=
"S&upprimer"
Public
Const
CMD_CANCEL_3DOTS As
String
=
CMD_CANCEL &
"..."
Public
Const
CMD_RESTART As
String
=
"&Recommencer..."
Public
Const
CLR_REDCOLOR As
Long
=
255
Public
Const
CLR_GREENCOLOR As
Long
=
39168
'Énumération qui définit le sens d'ouverture des formulaires
Public
Enum ge_FormDirection
GotoNext =
1
GotoPrevious =
3
End
Enum
'Variables publiques :
'No du site et nom du domaine exploités par la session en cours
Public
g_strNoSiteEnCours As
String
Public
g_strDomaineSiteEnCours As
String
'Liste des étapes incomplètes
Public
g_strDataSteps As
String
'Tableau des N° d'étapes complétées ou non
Public
g_intCompletionIndex
(
1
To
MAX_STEP_WIZ) As
Integer
XIV-B-2. La procédure publique FillDataChecker▲
Cette procédure permet d'alimenter le tableau d'entiers avec une valeur True ou False à l'Index selon la valeur de Completed.
Public
Sub
FillDataChecker
(
ByVal
Index As
Integer
, ByVal
Completed As
Boolean
)
'---------------------------------------------------------------------------
' Sub : FillDataChecker
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Alimente le tableau g_intCompletionIndex selon l'index passé
'...........................................................................
' Parameters : Index : Index du tableau
' Completed : True si complété
' Return Codes : None
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
g_intCompletionIndex
(
Index) =
Completed
End
Sub
XIV-B-3. La fonction publique AllStepsAreCompleted()▲
Cette fonction permet de vérifier les étapes qui sont complétées ou non et d'en établir une liste qui est fournie à la variable g_strDataPage.
Public
Function
AllStepsAreCompleted
(
ByRef
Count As
Integer
) As
Boolean
'---------------------------------------------------------------------------
' Function : AllStepsAreCompleted
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Vérifie les étapes complétées
'...........................................................................
' Parameters : Count : Valeur représentant le nombre d'étapes
' Return Codes : Boolean = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
P As
Integer
Dim
intStepCount As
Integer
Dim
strDataPage As
String
intStepCount =
0
strDataPage =
""
'Pour chacune des étapes
For
P =
LBound
(
g_intCompletionIndex) To
UBound
(
g_intCompletionIndex)
'Si elle a été affectée à True via FillDataChecker()
If
(
g_intCompletionIndex
(
P) =
True
) Then
'On incrémente le nombre d'étapes valides
intStepCount =
intStepCount +
1
Else
'Sinon, on remplit une chaîne stipulant les étapes ignorées
strDataPage =
strDataPage &
" - étape N° "
&
P &
vbCrLf
End
If
Next
Count =
intStepCount
'La fonction est True si le nombre d'étapes complétées est égal au nombre total d'étapes
AllStepsAreCompleted =
(
Count =
MAX_STEP_WIZ)
'Définit le message final
If
Len
(
strDataPage) Then
g_strDataPage =
"Liste des étapes incomplètes :"
&
vbCrLf
&
vbCrLf
&
strDataPage
Else
g_strDataPage =
"Liste des étapes incomplètes :"
&
vbCrLf
&
vbCrLf
&
"Aucune"
End
If
End
Function
XIV-B-4. La fonction publique EraseAllDataBefore()▲
Cette fonction permet la remise à blanc des tables de données utilisateur.
Elle est appelée au début du lancement lorsque la case à cocher sur l'écran d'accueil est cochée.
Public
Function
EraseAllDataBefore
(
ByRef
ErrDescription As
String
) As
Boolean
'---------------------------------------------------------------------------
' Function : EraseAllDataBefore
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Fonction de RAZ des données occultant certaines tables
'...........................................................................
' Parameters : ErrDescription = Message d'erreur
' Return Codes : Boolean = True if success
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Const
TABLE_TO_IGNORE As
String
=
"tbl_ListeDepartements;tbl_ListeDesCommunes;tbl_ListeDesRegions;tbl_Privileges;tbl_TypesContrat"
Const
CHAR_SEP As
String
=
";"
Const
DELETE_DATA As
String
=
"DELETE * FROM #T;"
Dim
oDB As
DAO.Database
Dim
strListOfTables As
String
Dim
straTables
(
) As
String
Dim
SQLDelete As
String
Dim
T As
Integer
On
Error
GoTo
L_ErrEraseAllDataBefore
strListOfTables =
GetListOfTables
(
TABLE_TO_IGNORE, CHAR_SEP)
Set
oDB =
CurrentDb
With
oDB
Debug.Print
strListOfTables
straTables =
Split
(
strListOfTables, CHAR_SEP)
For
T =
LBound
(
straTables) To
UBound
(
straTables)
SQLDelete =
Replace
(
DELETE_DATA, "#T"
, straTables
(
T))
.Execute
SQLDelete, dbFailOnError
Next
.Close
End
With
EraseAllDataBefore =
True
On
Error
GoTo
0
L_ExEraseAllDataBefore
:
Set
oDB =
Nothing
Exit
Function
L_ErrEraseAllDataBefore
:
EraseAllDataBefore =
False
'Message d'erreur avec N°
ErrDescription =
Err
.Description
&
" - ("
&
Err
.Number
&
")"
Resume
L_ExEraseAllDataBefore
End
Function
XIV-B-5. La fonction privée GetListOfTables()▲
Cette fonction établit la liste des tables devant être remises à blanc.
Elle est appelée par la fonction EraseAllDataBefore() ci-avant.
Private
Function
GetListOfTables
(
ByVal
ExcludeTables As
String
, Optional
ByVal
CharSep As
String
=
";"
) As
String
'---------------------------------------------------------------------------
' Function : GetListOfTables
' DateTime : 27/11/2015
' Author : Jean-Philippe AMBROSINO : Argyronet sur developpez.com (Code du tutoriel 11-2015)
' Purpose : Retourne la liste des tables devant être vidées
'...........................................................................
' Parameters : ExcludeTables : Liste des tables à exclure
' Return Codes : String = Liste des tables
'...........................................................................
' Notice :
'---------------------------------------------------------------------------
Dim
oDB As
DAO.Database
Dim
oTDF As
DAO.TableDef
Dim
strDataTables As
String
Dim
straExcludeTables
(
) As
String
Dim
strExcludeTable As
String
Dim
T As
Integer
Set
oDB =
CurrentDb
straExcludeTables =
Split
(
ExcludeTables, CharSep)
'Énumère toutes les tables sauf les tables système
For
Each
oTDF In
oDB.TableDefs
With
oTDF
If
.Attributes
=
0
And
Left
$(
.Name
, 4
) <>
"MSys"
Then
'On incrémente la chaîne avec le nom des tables
strDataTables =
strDataTables &
Trim
$(
.Name
) &
CharSep
End
If
End
With
Next
'On ferme la base instanciée
oDB.Close
Set
oDB =
Nothing
'On parcourt le tableau des tables à exclure
For
T =
LBound
(
straExcludeTables) To
UBound
(
straExcludeTables)
strExcludeTable =
straExcludeTables
(
T)
'On remplace chaque table à exclure et son ; par une chaîne vide
strDataTables =
Replace
(
strDataTables, strExcludeTable &
CharSep, ""
)
Next
'On élimine le dernier caractère et on affecte le tout comme valeur de retour
If
Right
(
strDataTables, 1
) =
CharSep Then
GetListOfTables =
Left
$(
strDataTables, Len
(
strDataTables) -
1
)
End
If
End
Function
XV. Mise en exécution▲
Lorsque vous pensez que vous avez pu mettre en œuvre ce projet en l'état, il doit être prêt à tourner.
Vous avez le choix de lancer indifféremment :
- le formulaire frmStart ;
- la macro AutoExec ;
- la procédure de démarrage que vous auriez créé (non présente dans le code, ici) ;
- La fermeture d'Access et ouvrir l'application directement via un raccourci, par exemple.
Le premier formulaire s'affiche et vous pouvez commencer les tests de saisie et de comportement pour voir si vous n'avez rien omis ou bien si l'interfaçage vous satisfait ; vous pouvez alors selon vos constats, améliorer ou modifier des éléments que vous jugeriez nécessaires.
XV-A. En images, l'exécution peut se dérouler ainsi▲
L'écran d'accueil est affiché et on souhaite remettre à blanc les données puisque la case cochée…
Un message de confirmation est alors affiché :
- si vous cliquez sur Oui toutes les données sont effacées de façon irréversible et vous passez à l'étape N° 1 ;
- si vous cliquez sur Non, vous passez à l'étape N° 1 sans effacer les données ;
- si vous cliquez sur Annuler, vous restez sur cet écran.
À l'étape N° 1, on définit le nom du site.
Dans ce projet, il est considéré (comme cela l'est stipulé dans le texte en rouge) que le site est unique et qu'il reste en référence dans toutes les tables sous-jacentes.
Si toutefois vous tentez de passer à l'étape suivante alors que le formulaire n'est pas du tout rempli, le message suivant fait son apparition.
Comme je vous l'ai déjà précisé, les messages d'erreurs sont qualifiés d'optimistes.
Dans l'absolu, pour cette première étape, on aurait dû rendre le message non permissif et interdire la non-saisie du site, puisque c'est le site qui fait office de référence.
Mais il est considéré ici que c'est juste pour la démonstration et que vous pouvez modifier le comportement du message en conséquence de l'appel source.
Si toutefois vous vouliez modifier le message, il faudrait remplacer les boutons vbYesNo (Oui - Non) par le bouton OK et interdire le passage au formulaire suivant.
De là plusieurs options s'offrent à vous :
- griser le bouton suivant tant que les données ne sont pas remplies ;
- modifier le message de telle sorte qu'il affiche un bouton OK.
Une fois que vous avez rempli toutes les données de l'étape N° 1 vous passez à l'étape N° 2 pour alimenter l'ensemble du personnel du site.
Le code inscrit dans ce formulaire permet de transformer les prénoms en Nom Propre et les noms de famille en MAJUSCULES.
Par ailleurs, l'adresse e-mail est composée automatiquement sur le principe déjà expliqué dans les pages précédentes et notamment ici.
Vous ne pouvez pas remarquer ici l'effet clignotant de l'étiquette mentionnant que la ligne est complétée puisque c'est une image. Mais dans la vidéo un peu plus bas, cet effet est tout à fait visible.
L'étape suivante N° 3 va vous permettre de saisir les communes exploitées par le site.
Le principe est simple, vous choisissez le département et aussitôt la liste de droite se filtre sur les communes de ce dernier. Il suffit alors de choisir la bonne commune.
Vous pouvez remarquer qu'en cours de saisie, la mention ligne incomplète est affichée tout simplement parce que l'opérateur est en train de la remplir.
Si à ce stade il tente de passer à l'étape suivante, le message d'alerte fait son apparition en lui proposant d'ignorer ou de continuer.
Il propose alors :
- soit de finir la saisie (pas le choix, et toc !) ;
- soit d'annuler la saisie en cours…
À l'étape N° 4, le formulaire propose de saisir un ou plusieurs contrats.
Tous les champs ici sont obligatoires.
Si toutefois il existe plusieurs contrats déjà enregistrés, le bouton permettant d'en afficher la liste est disponible.
L'avant-dernière étape N° 5 est dédiée à l'alimentation des communes affectées à certains contrats.
Dans la liste de gauche figurent les contrats que vous avez déjà enregistrés, et dans la liste de droite, les communes supervisées par le site.
Attention
Il n'a pas été prévu ici de code inhérent au comportement des données s'il manque des informations (site, contrat, etc.).
Dans la mesure où vous avez complété toutes les étapes, le dernier écran vous spécifie qu'aucune étape n'a été omise…
Il décrit alors au sein de ce formulaire la marche à suivre.
Ci-dessous, par exemple, on peut constater que les étapes N° 1 et N° 2 sont incomplètes.
XVI. Mise en pratique du projet▲
Ainsi que cela déjà été élaboré au début de ce tutoriel, l'objectif de ce projet est de fournir une application prête à l'emploi dont l'objectif est de collecter l'ensemble des données que vous souhaitez centraliser dans une seule et même base de données, et ce, quel que soit son type.
Il est sous-entendu finalement qu'une autre application est censée être en place sur ces sites pour pouvoir interagir avec les données que les destinataires ou responsables de sites ont saisies.
Dans le contexte professionnel dans lequel je travaille, l'ensemble des sites possède une application itinérante qui est identique à l'application centrale où les utilisateurs, par le biais de processus d'export, déversent leurs données dans l'application centrale.
Mais pour ce faire, il est impératif que l'application itinérante soit pourvue des données en rapport avec les communes qu'ils exploitent d'une part, et les différents techniciens appartenant au site, d'autre part.
Lorsqu'ils font leur export, les données se croisent avec les informations récoltées.
J'ajoute à ce tutoriel une petite vidéo qui va vous permettre de vous rendre compte du mode de fonctionnement de cette application :
Démonstration du tutoriel en mode utilisation
Dans le jeu de tests présentés ci-dessus, j'ai expressément omis les informations pour afficher les messages d'erreur et pour arriver finalement avec le compte rendu final des étapes qualifiées d'incomplètes.
Je suis alors revenu au formulaire précédent jusqu'à l'étape incriminée et j'ai corrigé mon formulaire afin de n'avoir aucune erreur.
XVII. Conclusion▲
Bien que ce tutoriel reste axé sur un cas d'école très particulier, il reste intéressant d'en examiner le contenu, ne serait-ce que pour apprendre à éviter la redondance de code au sein des formulaires, surtout lorsque ceux-ci font la même chose.
Vous avez pu voir comment il était aisé de centraliser les procédures événementielles en un seul et même bloc et surtout comment il était plus souple de passer des paramètres pour pouvoir faire en sorte que ces procédures exécutent ce que vous souhaitez faire. Vous avez pu également apprendre à rendre optimiste une gestion d'erreurs, mais aussi à construire des classes formulaires génériques où seul le changement des valeurs de constantes suffit à faire marcher l'interface.
Pour pouvoir partager ce tutoriel et le transposer à l'image de ce que vous pourriez en attendre, j'ai dû apporter pas mal de modifications et adapter le code pour qu'il soit à la fois simplifié et compréhensible par rapport au projet original. Il n'en est pas moins que son élaboration reste assez délicate si l'on considère qu'il ne faut rien omettre, tant au sein des formulaires que de leurs propriétés.
Vous voudrez bien noter que toutes suggestions d'amélioration dans le but de parfaire ce projet restent bien évidemment les bienvenues.
XVIII. Remerciements▲
Je tiens à remercier tout particulièrement toutes celles et tous ceux qui ont participé à la relecture de ce document en y incluant leurs remarques.
- Claude Leloup pour la relecture orthographique.
- Djibril pour la partie technique de l'édition.