I. Prérequis▲
Ce tutoriel s'adresse à des utilisateurs qui maitrisent déjà les bases du logiciel Access ou qui veulent faire l'effort pour progresser : l'utilisation du VBA décuple le potentiel de solutions !
Pour vérifier votre niveau, parcourez ces tutoriels : si vous les comprenez facilement, vous êtes OK et si ce n'est pas le cas, insistez : - pour commencer : Maxence Hubiche Access - Les Bases ; - pour construire des requêtes : Jean Ballat Créer des requêtes simples ; - pour construire un formulaire :Jean-Philippe Ambrosino le chapitre 2-1-2 de Mise en surbrillance d'un enregistrement dans un formulaire ; - pour le VBA : Olivier Lebeau Initiation au VBA Office. |
D'une manière générale, pour vous documenter sur les propriétés d'un formulaire ou d'un état, ou de leurs contrôles : L'aide Access s'ouvre alors à la bonne page. On peut aussi : |
II. Quelques notions « métier »▲
II-A. Les données qui permettent d'identifier un mouton▲
Le N° d'éleveur
Officiellement appelé « Indicatif de marquage ».
Six chiffres.
Le N° de travail
Cinq chiffres.
Le premier chiffre correspond à l'année de naissance (5 pour la campagne 2015).
Les quatre suivants sont un numéro d'ordre.
N.B. Les campagnes ne sont pas à l'année civile, mais du 1er juillet au 30 juin de l'année suivante.
La combinaison N° d'éleveur/N° de travail est unique : en 2025, on aura 5xxxx, avec xxxx différents de ceux qui avaient été attribués en 2015.
Cette combinaison figure sur la plaque que le mouton porte à l'oreille durant toute sa vie.
À chaque début de campagne, l'éleveur indique à l'administration - suivant ses prévisions d'agnelages - combien de boucles il veut.
II-B. Les données qui caractérisent un mouton▲
La race
Charollais, Bleu du Maine, Île-de-France, Suffolk, Romane, Texel…
La généalogie
Pour autant qu'elle soit connue. (C'est rarement le cas pour un mouton acheté.)
Comment il a été allaité
Naturel par sa mère, par une brebis adoptive, au biberon, complémenté…
Comment il est entré dans le troupeau
Naissance dans l'exploitation, achat, prise en pension.
Comment il en est sorti
Vente, consommation propre, sortie de pension, mort, vol.
II-C. La reproduction▲
Les brebis ont un rythme saisonnier de reproduction dépendant de la variation de la durée du jour au cours de l'année : l'activité sexuelle se manifeste lorsque la durée du jour diminue : du début de l'été à la fin d'automne.Certaines races comme la Romane et l'Île-de-France désaisonnent naturellement (sans hormones !!!), c'est-à-dire qu'elles sont saillies au printemps, pour mettre bas à l'automne et donc proposer des agneaux toute l'année ! Pour stimuler ce désaisonnement, on réalise un flushing avant la lutte (c'est-à-dire qu'on suralimente légèrement les brebis pendant trois semaines) puis « l'effet bélier » fait le reste (l'introduction du bélier dans le troupeau stimule le cycle des brebis).
On constitue une lutte, c'est-à-dire un groupe constitué d'un bélier et de 20 à 40 brebis.
Le bélier porte un harnais avec un bloc marqueur afin que l'arrière-train de la brebis soit marqué d'une couleur lorsqu'elle a été saillie.
La gestation dure de 140 à 150 jours.
On mémorisera les circonstances de mise bas de chaque brebis (seule, aide légère, aide forte, césarienne, embryotomie) afin de ne garder à terme, que les brebis (ou les filles de celles-ci) qui mettent bas facilement.
III. Le modèle de données▲
Les chapitres suivants concernent l'encodage des données.
IV. Le formulaire fMenu▲
C'est lui qui s'affiche à l'ouverture de l'application.
Un clic sur les boutons donne l'accès aux principaux formulaires de l'application :
OOption Compare Database
Option
Explicit
Private
Sub
btInventaire_Click
(
)
DoCmd.OpenForm
"fInventaire"
End
Sub
Private
Sub
btLuttes_Click
(
)
DoCmd.OpenForm
"fLuttes"
End
Sub
Private
Sub
btOvins_Click
(
)
DoCmd.OpenForm
"fOvins"
End
Sub
Private
Sub
BtRepro_Click
(
)
DoCmd.OpenForm
"fRepro"
End
Sub
V. Le formulaire fOvins▲
V-A. Présentation▲
Comme dans tout formulaire Access,
Il s'agit d'un formulaire « tout-en-un » : non seulement il permet de gérer la table tOvins (c'est-à-dire ajouter, supprimer ou modifier des enregistrements), mais il offre la possibilité d'opérer des recherches multicritères. En l'occurrence, suivant les filtres mentionnés dans le pied (le N° d'éleveur, le N° de travail, le sexe, la race, le caractère « fictif »(1)).
Selon les filtres choisis, la source du formulaire est modifiée par exemple :
N.B. Si aucun ovin ne correspond à la combinaison de filtres, vient ce message :
La technique de cette méthode est décrite en détail dans ce tutoriel :Formulaire de recherche polyvalent sur la base d'une requête enregistrée.
V-B. La source▲
Même principe que .
La comparaison se fait par rapport à la valeur du groupe d'option :
- si le groupe d'option a une valeur supérieure à zéro (donc si l'utilisateur a choisi Femelles ou Mâles), la requête ramènera les tSexeFK égaux soit à 1 (si « Femelles » est cochée), soit égaux à 2 (si « Mâles » est cochée) ;
- si le groupe vaut zéro, la requête ramènera les cas où tSexeFK est égal à lui-même, c'est-à-dire tous.
À l'ouverture du formulaire, le groupe vaut 0, donc « Sans distinction » est cochée. Il passe à 1 lorsque l'utilisateur coche « Femelles ». Il passe à 2 lorsque l'utilisateur coche «Mâles ». Il passe à 0 lorsque l'utilisateur coche « Sans distinction ». |
C'est comme et . Rappelez-vous que FiltreRace est une zone de liste
et que, même si elle affiche une race en clair, ce qu'elle contient effectivement, c'est la colonne liée, en l'occurrence tRacePK.
Si la case est grisée (valeur Null), tous les enregistrements seront ramenés,
si la case est cochée (valeur Vrai), seuls les ovins fictifs seront ramenés.
V-C. Quelques fonctionnalités▲
On utilise la mise en forme conditionnelle :
Pour la cause de sortie :
Pour le N° d'éleveur :
V-C-1. La constante NumElevage▲
Nous avons défini une constante NumElevage : Sélectionnez
Ici fixée à 102030. L'utilisateur modifiera une fois pour toutes pour y mentionner son propre numéro. Cette constante a une portée universelle. C'est-à-dire que l'on peut l'utiliser partout dans l'application (on dit qu'elle est « visible » partout). Cependant, on ne peut pas utiliser des constantes partout dans Access. Par exemple, dans l'expression d'une mise en forme conditionnelle. Qu'à cela ne tienne, on contourne en créant une fonction qui renvoie la valeur de la constante :² Sélectionnez
Là où Access proscrit les constantes, il admet généralement les fonctions. C'est le cas ici. |
V-D. Code du formulaire▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
Option
Compare Database
Option
Explicit
Private
Sub
Form_Current
(
)
If
Me.coFictif
=
False
Then
Me.Section
(
"Détail"
).BackColor
=
-
2147483633
'gris clair
Else
Me.Section
(
"Détail"
).BackColor
=
33023
'orange
End
If
End
Sub
Public
Sub
MaJFiltre
(
)
Me.Requery
If
Me.RecordsetClone.RecordCount
=
0
Then
MsgBox
"Pas d'enregistrement avec cette combinaison"
End
If
End
Sub
Private
Sub
BtTout_Click
(
)
Dim
ctl As
Control
For
Each
ctl In
Me.Controls
If
ctl.Name
Like "Filtre*"
Then
ctl =
Null
End
If
Next
ctl
Me.FiltreSexe
=
0
Me.Requery
End
Sub
Private
Sub
FiltreNumEleveur_AfterUpdate
(
)
Call
MaJFiltre
End
Sub
Private
Sub
FiltreNumTravail_AfterUpdate
(
)
Call
MaJFiltre
End
Sub
Private
Sub
FiltreRace_AfterUpdate
(
)
Call
MaJFiltre
End
Sub
Private
Sub
FiltreSexe_AfterUpdate
(
)
Call
MaJFiltre
End
Sub
Private
Sub
FiltreFictifs_AfterUpdate
(
)
If
Me.FiltreFictifs
=
0
Then
Me.FiltreFictifs
=
Null
Call
MaJFiltre
End
Sub
4-9 : on veut afficher la section détail en orange pour attirer l'attention de l'utilisateur sur le fait qu'il s'agit d'un ovin « fictif » (le mâle d'une brebis achetée pleine, ou le mâle d'une brebis inséminée artificiellement). Access n'offre pas la possibilité de mise en forme conditionnelle pour la section « Détail ». Pour pallier ce manque, on recourt à du code : à chaque lecture d'un enregistrement (événement « Sur activation » On
current), on modifie la propriété « Couleur de fond » BackColorde la section.
12-49 : ne concerne que la partie « recherche multicritère » décrite dans Formulaire de recherche polyvalent sur la base d'une requête enregistrée.
VI. Le formulaire tLuttes▲
VI-A. Présentation▲
Il s'agit d'un formulaire père/fils :
- fLuttes, le père avec comme source la table tLuttes ;
- sfLuttesBrebis, le fils avec comme source la table tLutteBrebis.
Si le concept de formulaire « père/fils » ne vous est pas familier, voyez ce tutoriel : Comment classer les données dans des tables liées et construire un formulaire père/fils.
Lorsque fLuttes affiche un enregistrement de tLuttes, sfLuttesBrebis affiche les enregistrements de tLutteBrebis correspondants.
La clé primaire de tLuttes (tLuttesPK) et la clé étrangère de tLutteBrebis (tLuttesFK) assurent la synchronisation entre les deux composantes :
VI-B. La source de fLuttes▲
Tout comme fOvins, ce formulaire est polyvalent : on peut ajouter, modifier ou supprimer les enregistrements de sa source, mais il peut aussi servir de formulaire de recherche multicritère :
Avec ceci de particulier, que les critères portent sur deux tables :
- la source du formulaire fLuttes (tLuttes) ;
- la source du sous-formulaire sfLuttesBrebis (tLutteBrebis).
Si nous suivons la même logique que pour fOvins, nous créons une requête qui se réfère aux filtres :
MAIS
voici ce que ramènerait une telle requête :
c'est-à-dire, pour une lutte, autant de lignes qu'il y a de brebis qui participent à la lutte.
La source de notre formulaire ne doit contenir qu'une seule ligne par lutte !
Qu'à cela ne tienne, transformons la requête de sélection en une requête de regroupement :
qui, cette fois, ramène une seule ligne par lutte :
OUI MAIS
une telle requête n'est plus modifiable : vous n'avez plus la possibilité de modifier le contenu d'une colonne, ni supprimer une ligne et encore moins d'en ajouter une !
Donc, ça ne va pas ! Il va falloir ruser !
En fait, il faut dire à Access : « Dans la source, ramenez tous les enregistrements de tLuttes dont le bélier est mentionné dans la requête rfLuttes ! »
Voici les mots qu'il faut pour le dire :
Dans la foulée, on trie dans l'ordre décroissant de DateDebut. Ainsi, si on fait une recherche selon un bélier ou une brebis, on affichera en premier la dernière lutte à laquelle ils ont participé.
Ce n'est pas beau ça ?
VI-C. Fonctionnalité particulière▲
VI-C-1. Un carré vert indique qu'une mise bas est déclarée▲
Nous verrons dans un chapitre suivant, qu'une mise bas se concrétise par un enregistrement dans la table tLutteBrebis.
Pour faire apparaître un carré vert, nous avons ajouté une zone de texte qui enregistre le nombre (0 ou 1) de mise bas déclarée pour cette femelle dans cette lutte :
et une mise en forme conditionnelle fait le reste :
Remarquez que le 0 ou le 1 n'apparaîtront pas : ils sont de la même couleur que le fond de la zone de texte. |
VI-D. Le code de fLuttes▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
Option
Compare Database
Option
Explicit
Private
Sub
Form_Current
(
)
Call
AmenagerTailleSF
(
Me.Name
, "CTNRsfLuttesBrebis"
)
Me.CTNRsfLuttesBrebis.Form
!cboBrebis.RowSource
=
Me.CTNRsfLuttesBrebis.Form
!cboBrebis.RowSource
End
Sub
Private
Sub
Form_Close
(
)
If
CurrentProject.AllForms
(
"fMisesBas"
).IsLoaded
Then
DoCmd.Close
acForm, "fMisesBas"
End
Sub
Public
Sub
MaJFiltre
(
)
Me.Requery
If
Me.RecordsetClone.RecordCount
=
0
Then
MsgBox
"Pas d'enregistrement avec cette combinaison"
End
If
End
Sub
Private
Sub
BtTout_Click
(
)
Dim
ctl As
Control
For
Each
ctl In
Me.Controls
If
ctl.Name
Like "Filtre*"
Then
ctl =
Null
End
If
Next
ctl
Me.Requery
End
Sub
Private
Sub
FiltreBelier_AfterUpdate
(
)
Call
MaJFiltre
End
Sub
Private
Sub
FiltreBrebis_AfterUpdate
(
)
Call
MaJFiltre
End
Sub
Private
Sub
txtDateFin_AfterUpdate
(
)
Me.Refresh
End
Sub
Commentaires du code
3-7 : concerne l'ajustement de la hauteur du sous-formulaire (voir § suivant).
9-11 : nous présenterons tout à l'heure le formulaire fMisesBas. Il fonctionne de pair avec fLuttes et cela n'a pas de sens de laisser fMisesBas ouvert si fLuttes est fermé.
13-36 : rien de particulier. Ne concerne que la partie « recherche multicritère » décrite dans Formulaire de recherche polyvalent sur la base d'une requête enregistrée.
VI-E. Le sous-formulaire fils sfLuttesBrebis▲
VI-E-1. La hauteur du sous-formulaire s'adapte au nombre d'enregistrements qu'il contient▲
de manière à ce que la section « Pied » qui renseigne le nombre de femelles de la lutte soit « collée » à la fin de la section Détail.
Pour une description détaillée du processus, voir Comment ajuster la taille d'un sous-formulaire en fonction du nombre de ses enregistrements.
VI-E-2. Zone de liste pour le choix des brebis▲
Pour être candidate dans une lutte, il faut :
qu'il s'agisse d'une femelle ;
qui est présente dans le troupeau au début de la mise en lutte. En d'autres mots, elle doit avoir une date d'entrée antérieure à celle du début de lutte et sa date de sortie doit être soit nulle, soit postérieure à celle du début de lutte ;
elle doit avoir au moins 300 jours d'âge à la date de début de lutte ;
si elle a déjà mis bas, il faut que la dernière fois remonte à au moins septante-cinq jours (ma belgitude ne résiste pas au plaisir d'écrire 75 en lettres ! ) ;
elle ne doit pas déjà faire partie d'une autre lutte encore en cours.
La requête qui ramène les ovins qui satisfont aux cinq critères :
VI-E-3. Le code de sfLuttesBrebis▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
Option
Compare Database
Option
Explicit
Private
Sub
Form_Current
(
)
If
CurrentProject.AllForms
(
"fMisesBas"
).IsLoaded
Then
DoCmd.Close
acForm, "fMisesBas"
Me.cboBrebis.RowSource
=
Me.cboBrebis.RowSource
End
Sub
Private
Sub
Form_AfterDelConfirm
(
Status As
Integer
)
Call
AmenagerTailleSF
(
Me.Parent.Name
, "ctnr"
&
Me.Name
)
End
Sub
Private
Sub
Form_AfterInsert
(
)
Call
AmenagerTailleSF
(
Me.Parent.Name
, "ctnr"
&
Me.Name
)
End
Sub
Private
Sub
btMB_Click
(
)
If
Me.cboBrebis
=
0
Then
Exit
Sub
'clic sur enregistrement encore vierge
DoCmd.OpenForm
"fMisesBas"
, , , , , acHidden
PositionForm Forms
(
"fMisesBas"
), Me.btMB
End
Sub
Private
Sub
cboBrebis_AfterUpdate
(
)
On
Error
GoTo
GestionErreurs
Me.Refresh
GestionErreurs
:
Select
Case
Err
.Number
Case
0
Exit
Sub
Case
3022
'doublon
MsgBox
"Cette brebis N° "
&
Me.cboBrebis.Text
&
" fait déjà partie de la lutte."
Me.Undo
End
Select
End
Sub
Commentaires du code
4-7 : à chaque changement d'enregistrement :
- (5) on ferme le formulaire fMiseBas, car s'il est encore ouvert, il se rapporte à l'enregistrement qui était actif juste avant ;
- (6) on réactualise la propriété « Contenu » de la zone de liste.
9-15 : ces instructions concernent l'adaptation de la hauteur du sous-formulaire.
17-21 : le clic sur le bouton « Mise bas » sur une ligne d'enregistrement :
- (18) sera sans effet, s'il s'agit du bouton situé sur la ligne qui propose d'ajouter un enregistrement ;
- (19-20) va provoquer l'ouverture du formulaire fMisesBas juste en dessous du bouton qui a été cliqué (ou à proximité selon la place disponible à l'écran).
Cette technique a été présentée par Arkham46 dans cette contribution.
Il n'y a pas besoin de comprendre tout ce qu'il y a sous le capot pour savoir conduire une voiture. Pour utiliser la proposition d'Arkham46 : - vous copiez dans un module le code donné à la fin de cet article ; - pour commander l'ouverture du formulaire, ces deux lignes de code : Sélectionnez
- le formulaire à ouvrir doit être une fenêtre indépendante : |
23-33 : on vérifie ici que la brebis qui vient d'être désignée ne fait pas déjà partie de la lutte que nous sommes en train de déclarer.
On provoque la sauvegarde de l'enregistrement… et Access fait le reste, car dans la définition de la table tLutteBrebis, nous avons placé un index unique sur la combinaison lutte/brebis :
Dès lors, en cas de tentative de doublon, Access lève une erreur 3022 que nous récupérons pour afficher ce message :
VII. Le formulaire fMisesBas▲
VII-A. Présentation▲
Lorsqu'une brebis met bas, il faut enregistrer la (les) naissance(s), voici la suite des opérations :
Un clic dans le menu.
Dans le formulaire fLuttes, filtrer pour afficher la dernière lutte de la brebis.
Un clic sur le bouton « MiseBas ».
Le formulaire fMisesBas s'affiche :
L'utilisateur complète (ici des jumeaux pour la Saint-Nicolas !) et comptabilise :
Les deux agneaux ont été automatiquement enregistrés dans la table tOvins.
Remarquez que le bouton « À comptabiliser » a été remplacé par « Déjà enregistré » et les données ne sont plus modifiables (ni ajout, ni suppression) pour cette mise bas.
VII-B. Particularités techniques▲
Les contrôles en rouge sont utiles au fonctionnement, mais sans intérêt pour l'utilisateur. Ils ont leur propriété Visible positionnée à Non.
Tout comme fOvins et fLuttes, fMisesBas est du type père/fils.
Le contrôle TXTtLuttesBrebisFK prend comme valeur par défaut le contenu de TXTtLuttesBrebisPK de la brebis courante dans fLuttes :
Donc, à la création de l'enregistrement - lors de la première ouverture du formulaire fMiseBas pour cette brebis dans cette lutte -, le champ tLutteBrebisFK (la clé étrangère) sera automatiquement mis à jour.
Seulement un des deux boutons aura sa propriété Visible positionnée à Oui, selon le stade de comptabilisation de la mise bas.
VII-B-1. Utilisation (acrobatique) de la mise en forme conditionnelle ▲
Pour le N° de travail
situation normale
cas de la ligne qui propose d'ajouter un enregistrement
si l'agneau est viable, il doit avoir un N°, par contre il ne peut avoir de N° s'il n'est pas viable
si l'agneau n'est pas viable et pas de N°, le champ s'affiche en gris
Pour l'allaitement
situation normale
agneau non viable
cas de la ligne de l'enregistrement à ajouter
VII-C. La source de fMisesBas▲
En d'autres mots, les enregistrements de tMisesBas qui concernent la brebis dont il est actuellement question dans le formulaire fLuttes.
VII-D. Le code du formulaire fMisesBas▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
Option
Compare Database
Option
Explicit
Private
Sub
Form_Current
(
)
With
Me
If
Me.txtEnregistreeMB
=
True
Then
'Afficher le bouton qui convient
.btComptabiliser.Visible
=
False
.btEnregistree.Visible
=
True
'Interdire les modif
.AllowEdits
=
False
.AllowDeletions
=
False
'Interdire les modif dans le sfLuttesBrebis
.CTNRsfMisesBasAgneaux.Form.AllowAdditions
=
False
.CTNRsfMisesBasAgneaux.Form.AllowDeletions
=
False
.CTNRsfMisesBasAgneaux.Form.AllowEdits
=
False
Else
'Afficher le bouton qui convient
.btComptabiliser.Visible
=
True
.btEnregistree.Visible
=
False
'Autoriser les modif
.AllowEdits
=
True
.RecordSelectors
=
True
'Autoriser les modif dans le sfMisesBasAgneaux
.CTNRsfMisesBasAgneaux.Form.AllowAdditions
=
True
.CTNRsfMisesBasAgneaux.Form.AllowDeletions
=
True
.CTNRsfMisesBasAgneaux.Form.AllowEdits
=
True
End
If
End
With
End
Sub
Private
Sub
btComptabiliser_Click
(
)
Dim
iReponse As
Integer
'Demande de confirmation
iReponse =
MsgBox
(
"Confirmez que vous voulez enregistrer cette mise bas"
, vbYesNo
+
vbQuestion
+
vbDefaultButton2
)
If
iReponse =
vbNo
Then
Exit
Sub
With
Me
'MàJ de EnregistreeMB
.txtEnregistreeMB
=
True
'Rendre le formulaire non modifiable
.AllowEdits
=
False
.AllowDeletions
=
False
'Rendre le sous-formulaire non modifiable
.CTNRsfMisesBasAgneaux.Form.AllowAdditions
=
False
.CTNRsfMisesBasAgneaux.Form.AllowDeletions
=
False
.CTNRsfMisesBasAgneaux.Form.AllowEdits
=
False
'Changer de bouton
.txtEnregistreeMB
=
True
.txtDateMB.SetFocus
.btComptabiliser.Visible
=
False
.btEnregistree.Visible
=
True
'Enregistrer tMisesBas
.Refresh
End
With
'Enregistrer les naissances dans tOvins
DoCmd.SetWarnings
False
DoCmd.OpenQuery
"rComptaMiseBas"
DoCmd.SetWarnings
True
End
Sub
Commentaires du code
Pas de difficulté : les explications incluses dans les instructions devraient suffire.
Ligne 57 : la requête rComptaMiseBas est décrite au paragraphe suivant.
VII-E. rComptaMiseBas, la requête qui intègre les nouveau-nés dans tOvins▲
Il s'agit d'une requête qui va ajouter un enregistrement dans tOvins pour chaque nouveau-né.
Cet enchevêtrement de tables permet d'accéder à toutes les données nécessaires pour alimenter les colonnes de tOvins. Remarquez que tOvins est assignée deux fois (une première pour se connecter aux données de la brebis et une seconde fois pour se connecter à celles du bélier).
Les enregistrements ramenés par cette requête seront limités à ceux dont le tLutteBrebisPK est celui de la brebis dont on déclare la mise bas…
… pour autant que l'agneau soit viable.
Deux colonnes méritent un mot d'explication.
- NumEleveur
Ici par exemple, pour compléter le N° d'éleveur de l'agneau, on indique le N° de l'élevage.
Pour rappel, on utilise une fonction, car une constante n'est pas admise dans une requête.
L'explication a été donnée plus haut ici.
- tRaceFK
En d'autres mots : si les deux parents sont de même race, ce sera la race du nouveau-né, sinon ce dernier sera de race « Indéterminée ».
Des « zinnekes » comme on dit à Bruxelles .
Nous clôturons ici cette première partie de l'article.
Dans une prochaine publication, nous aborderons l'utilisation des données essentiellement à l'aide de deux formulaires :
VIII. Annexe : Proposition de Arkham46 pour positionner le formulaire pForm par rapport au contrôle pControl▲
Voici le code de Arkham46 dont il est question au paragraphe Le code du sous-formulaire fils sfLuttesBrebis.
Option
Compare Database
Option
Explicit
'***************************************************************************************
'* API *
'***************************************************************************************
Private
Declare
Function
SetWindowPos Lib
"User32"
(
ByVal
hwnd As
Long
, ByVal
hWndInsertAfter As
Long
, ByVal
x As
Long
, ByVal
y As
Long
, ByVal
cx As
Long
, ByVal
cy As
Long
, ByVal
wFlags As
Long
) As
Long
Private
Declare
Function
GetWindowRect Lib
"User32"
(
ByVal
hwnd As
Long
, lpRect As
RectAPI) As
Long
Private
Declare
Function
GetDC Lib
"User32"
(
ByVal
hwnd As
Long
) As
Long
Private
Declare
Function
ReleaseDC Lib
"User32"
(
ByVal
hwnd As
Long
, ByVal
Hdc As
Long
) As
Long
Private
Declare
Function
GetDeviceCaps Lib
"gdi32"
(
ByVal
Hdc As
Long
, ByVal
nIndex As
Long
) As
Long
Private
Declare
Function
ClientToScreen Lib
"User32"
(
ByVal
hwnd As
Long
, lpPoint As
PointAPI) As
Long
Private
Declare
Function
SystemParametersInfo Lib
"User32"
_
Alias "SystemParametersInfoA"
(
ByVal
uAction As
Long
, _
ByVal
uParam As
Long
, ByRef
lpvParam As
RectAPI, _
ByVal
fuWinIni As
Long
) As
Long
'***************************************************************************************
'* Types *
'***************************************************************************************
' Type Point pour API
Public
Type
PointAPI
x As
Long
y As
Long
End
Type
Public
Type
RectAPI
Left
As
Long
Top As
Long
Right
As
Long
Bottom As
Long
End
Type
'***************************************************************************************
'* Constantes *
'***************************************************************************************
Private
Const
SWP_NOSIZE =
&
H1
Private
Const
SWP_NOMOVE As
Long
=
&
H2
Private
Const
SWP_NOZORDER =
&
H4
Private
Const
SWP_SHOWWINDOW =
&
H40
Private
Const
LOGPIXELSY =
90
Private
Const
LOGPIXELSX =
88
Private
Const
SPI_GETWORKAREA =
48
'---------------------------------------------------------------------------------------
' Convertit les Twips en Pixels sur l'axe horizontal
'---------------------------------------------------------------------------------------
' pTwipsX : Valeur à convertir en Twips
' Renvoie la valeur convertie en Pixels
'---------------------------------------------------------------------------------------
Public
Function
TwipsToPixelX
(
pTwipsX As
Long
) As
Long
Static
Mult As
Long
Dim
Hdc As
Long
If
Mult =
0
Then
Hdc =
GetDC
(
0
)
Mult =
1440
/
GetDeviceCaps
(
Hdc, LOGPIXELSX)
ReleaseDC 0
, Hdc
End
If
TwipsToPixelX =
CLng
(
pTwipsX /
Mult)
End
Function
'---------------------------------------------------------------------------------------
' Convertit les Twips en Pixels sur l'axe vertical
'---------------------------------------------------------------------------------------
' pTwipsY : Valeur à convertir en Twips
' Renvoie la valeur convertie en Pixels
'---------------------------------------------------------------------------------------
Public
Function
TwipsToPixelY
(
pTwipsY As
Long
) As
Long
Static
Mult As
Long
Dim
Hdc As
Long
If
Mult =
0
Then
Hdc =
GetDC
(
0
)
Mult =
1440
/
GetDeviceCaps
(
Hdc, LOGPIXELSY)
ReleaseDC 0
, Hdc
End
If
TwipsToPixelY =
CLng
(
pTwipsY /
Mult)
End
Function
'---------------------------------------------------------------------------------------
' Positionne le formulaire pForm par rapport au contrôle pControl
'---------------------------------------------------------------------------------------
Public
Sub
PositionForm
(
pForm As
Access.Form
, pControl As
Access.Control
)
Dim
lParentForm As
Access.Form
Dim
lPt As
PointAPI
Dim
lRect As
RectAPI
Dim
lScreenRect As
RectAPI
Dim
lScrWitdh As
Single
, lScrHeight As
Single
On
Error
GoTo
Gestion_Erreurs
' Vérifie que le formulaire est en fenêtre indépendante
If
Not
pForm.PopUp
Then
MsgBox
"Le formulaire à positionner doit être en fenêtre indépendante"
&
_
vbCrLf
&
"(onglet Autre dans les propriétés du formulaire)"
, vbInformation
SetWindowPos pForm.hwnd
, 0
, 0
, 0
, 0
, 0
, SWP_NOZORDER Or
SWP_NOMOVE Or
SWP_NOSIZE Or
SWP_SHOWWINDOW
Exit
Sub
End
If
' Formulaire parent
Set
lParentForm =
pControl.Parent
' Remonte jusqu'au formulaire si contrôle dans onglets
If
TypeOf lParentForm Is
Page Then
Do
Err
.Clear
Set
lParentForm =
lParentForm.Parent
If
Err
.Number
<>
0
Then
Err
.Clear
: Exit
Do
Loop
End
If
' Lit la taille du formulaire à positionner
Call
GetWindowRect
(
pForm.hwnd
, lRect)
lRect.Right
=
lRect.Right
-
lRect.Left
+
1
lRect.Bottom
=
lRect.Bottom
-
lRect.Top
+
1
' Lit la taille de l'écran
SystemParametersInfo SPI_GETWORKAREA, 0
, lScreenRect, 0
lScrWitdh =
lScreenRect.Right
-
lScreenRect.Left
+
1
lScrHeight =
lScreenRect.Bottom
-
lScreenRect.Top
+
1
' Position du contrôle de positionnement
lPt.x
=
TwipsToPixelX
(
pControl.Left
+
lParentForm.CurrentSectionLeft
)
lPt.y
=
TwipsToPixelY
(
pControl.Top
+
pControl.Height
+
lParentForm.CurrentSectionTop
)
ClientToScreen lParentForm.hwnd
, lPt
Set
lParentForm =
Nothing
lRect.Left
=
lPt.x
lRect.Top
=
lPt.y
' Doit tenir dans l'écran
' Si déborde à droite => décale le formulaire pour qu'il s'affiche entièrement
If
lRect.Left
+
lRect.Right
>
lScrWitdh Then
lRect.Left
=
lScrWitdh -
lRect.Right
End
If
' Si déborde en bas => affiche le formulaire au-dessus du contrôle
If
lRect.Top
+
lRect.Bottom
>
lScrHeight Then
lRect.Top
=
lRect.Top
-
TwipsToPixelY
(
pControl.Height
) -
lRect.Bottom
End
If
' Repositionne le formulaire
Call
SetWindowPos
(
pForm.hwnd
, 0
, lRect.Left
, lRect.Top
, lRect.Right
, lRect.Bottom
, SWP_NOZORDER Or
SWP_NOSIZE Or
SWP_SHOWWINDOW)
On
Error
GoTo
0
Exit
Sub
Gestion_Erreurs
:
MsgBox
"Error "
&
Err
.Number
&
" ("
&
Err
.Description
&
") dans la procédure PositionForm"
End
Sub
IX. Téléchargement▲
La base de données au format Access 2000 se trouve ici.
X. Remerciements▲
Merci à foster53 qui m'a expliqué une partie de l'histoire qui précède l'achat des côtes d'agneau au supermarché.
Merci à Jean-Damien Gayot qui a amélioré la qualité du code.
Merci à Malick Seck (milkoseck) pour la correction orthographique.