Gérer un troupeau de moutons avec Access

1re partie : la collecte des données

Claude Leloup

Ceci en réponse à une question posée sur le forum : Outil gestion troupeau avec enregistrement des mises-bas.

L'article peut être vu comme un exercice dirigé pour permettre à de faux débutants d'encore progresser dans :

- la construction de requêtes complexes avec l'interface graphique QBE ;

- l'expression des critères pour la mise en forme conditionnelle ;

- les formulaires pères/fils avec recherche multicritère sur les deux sources. Commentez

- Titre : Gérer un troupeau de moutons avec Access

- Auteur : Claude Leloup

- Parution : 14 septembre 2015

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2015 Claude Leloup. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Prérequis

- II. Quelques notions « métier »

- II-A. Les données qui permettent d'identifier un mouton

- II-B. Les données qui caractérisent un mouton

- II-C. La reproduction

- III. Le modèle de données

- IV. Le formulaire fMenu

- V. Le formulaire fOvins

- V-A. Présentation

- V-B. La source

- V-C. Quelques fonctionnalités

- V-C-1. La constante NumElevage

- V-D. Code du formulaire

- VI. Le formulaire tLuttes

- VI-A. Présentation

- VI-B. La source de fLuttes

- VI-C. Fonctionnalité particulière

- VI-C-1. Un carré vert indique qu'une mise bas est déclarée

- VI-D. Le code de fLuttes

- VI-E. Le sous-formulaire fils sfLuttesBrebis

- VI-E-1. La hauteur du sous-formulaire s'adapte au nombre d'enregistrements qu'il contient

- VI-E-2. Zone de liste pour le choix des brebis

- VI-E-3. Le code de sfLuttesBrebis

- VII. Le formulaire fMisesBas

- VII-A. Présentation

- VII-B. Particularités techniques

- VII-B-1. Utilisation (acrobatique) de la mise en forme conditionnelle

- VII-C. La source de fMisesBas

- VII-D. Le code du formulaire fMisesBas

- VII-E. rComptaMiseBas, la requête qui intègre les nouveau-nés dans tOvins

- VIII. Annexe : Proposition de Arkham46 pour positionner le formulaire pForm par rapport au contrôle pControl

- IX. Téléchargement

- X. Remerciements

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 :
- affichez l'objet en mode création ;
- cliquez sur la propriété, elle se met alors en surbrillance ;
- enfoncez la touche <F1>.
Pour un problème de code dans un module, placez le curseur sur le mot-clé du VBA et pressez <F1>.

L'aide Access s'ouvre alors à la bonne page.

On peut aussi :
- ouvrir l'aide <F1>, choisir l'onglet « Aide intuitive » et suivre les instructions ;
- ouvrir la fenêtre d'exécution (<Ctrl> + G), saisir un mot-clé, y placer le curseur de la souris et presser <F1>.

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 :

Option Compare Database
Option Explicit
Public Const NumElevage As String = "102030"    ' <---------À modifier

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 :²

Public Function GetNumElevage() As String
GetNumElevage = NumElevage
End Function

Là où Access proscrit les constantes, il admet généralement les fonctions.

C'est le cas ici.

V-D - Code du formulaire

1. Option Compare Database

2. Option Explicit

4. Private Sub Form_Current()

5. If Me.coFictif = False Then

6. Me.Section("Détail").BackColor = -2147483633  'gris clair

7. Else

8. Me.Section("Détail").BackColor = 33023  'orange

9. End If

10. End Sub

12. Public Sub MaJFiltre()

13. Me.Requery

14. If Me.RecordsetClone.RecordCount = 0 Then

15. MsgBox "Pas d'enregistrement avec cette combinaison"

16. End If

17. End Sub

19. Private Sub BtTout_Click()

20. Dim ctl As Control

21. For Each ctl In Me.Controls

22. If ctl.Name Like "Filtre*" Then

23. ctl = Null

24. End If

25. Next ctl

26. Me.FiltreSexe = 0

27. Me.Requery

28. End Sub

30. Private Sub FiltreNumEleveur_AfterUpdate()

31. Call MaJFiltre

32. End Sub

34. Private Sub FiltreNumTravail_AfterUpdate()

35. Call MaJFiltre

36. End Sub

38. Private Sub FiltreRace_AfterUpdate()

39. Call MaJFiltre

40. End Sub

42. Private Sub FiltreSexe_AfterUpdate()

43. Call MaJFiltre

44. End Sub

46. Private Sub FiltreFictifs_AfterUpdate()

47. If Me.FiltreFictifs = 0 Then Me.FiltreFictifs = Null

48. Call MaJFiltre

49. 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

1. Option Compare Database

2. Option Explicit

4. Private Sub Form_Current()

5. Call AmenagerTailleSF(Me.Name, "CTNRsfLuttesBrebis")

6. Me.CTNRsfLuttesBrebis.Form!cboBrebis.RowSource = Me.CTNRsfLuttesBrebis.Form!cboBrebis.RowSource

7. End Sub

9. Private Sub Form_Close()

10. If CurrentProject.AllForms("fMisesBas").IsLoaded Then DoCmd.Close acForm, "fMisesBas"

11. End Sub

13. Public Sub MaJFiltre()

14. Me.Requery

15. If Me.RecordsetClone.RecordCount = 0 Then

16. MsgBox "Pas d'enregistrement avec cette combinaison"

17. End If

18. End Sub

20. Private Sub BtTout_Click()

21. Dim ctl As Control

22. For Each ctl In Me.Controls

23. If ctl.Name Like "Filtre*" Then

24. ctl = Null

25. End If

26. Next ctl

27. Me.Requery

28. End Sub

30. Private Sub FiltreBelier_AfterUpdate()

31. Call MaJFiltre

32. End Sub

34. Private Sub FiltreBrebis_AfterUpdate()

35. Call MaJFiltre

36. End Sub

38. Private Sub txtDateFin_AfterUpdate()

39. Me.Refresh

40. 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

1. Option Compare Database

2. Option Explicit

4. Private Sub Form_Current()

5. If CurrentProject.AllForms("fMisesBas").IsLoaded Then DoCmd.Close acForm, "fMisesBas"

6. Me.cboBrebis.RowSource = Me.cboBrebis.RowSource

7. End Sub

9. Private Sub Form_AfterDelConfirm(Status As Integer)

10. Call AmenagerTailleSF(Me.Parent.Name, "ctnr" & Me.Name)

11. End Sub

13. Private Sub Form_AfterInsert()

14. Call AmenagerTailleSF(Me.Parent.Name, "ctnr" & Me.Name)

15. End Sub

17. Private Sub btMB_Click()

18. If Me.cboBrebis = 0 Then Exit Sub 'clic sur enregistrement encore vierge

19. DoCmd.OpenForm "fMisesBas", , , , , acHidden

20. PositionForm Forms("fMisesBas"), Me.btMB

21. End Sub

23. Private Sub cboBrebis_AfterUpdate()

24. On Error GoTo GestionErreurs

25. Me.Refresh

26. GestionErreurs:

27. Select Case Err.Number

28. Case 0

29. Exit Sub

30. Case 3022  'doublon

31. MsgBox "Cette brebis N° " & Me.cboBrebis.Text & " fait déjà partie de la lutte."

32. Me.Undo

33. End Select

34. 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 :

DoCmd.OpenForm "LeNomDuFormulaire", , , , , acHidden
PositionForm Forms("LeNomDuFormulaire "), Me.LeNomDuControleRepere

- 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

1. Option Compare Database

2. Option Explicit

4. Private Sub Form_Current()

5. With Me

6. If Me.txtEnregistreeMB = True Then

7. 'Afficher le bouton qui convient

8. .btComptabiliser.Visible = False

9. .btEnregistree.Visible = True

10. 'Interdire les modif

11. .AllowEdits = False

12. .AllowDeletions = False

13. 'Interdire les modif dans le sfLuttesBrebis

14. .CTNRsfMisesBasAgneaux.Form.AllowAdditions = False

15. .CTNRsfMisesBasAgneaux.Form.AllowDeletions = False

16. .CTNRsfMisesBasAgneaux.Form.AllowEdits = False

17. Else

18. 'Afficher le bouton qui convient

19. .btComptabiliser.Visible = True

20. .btEnregistree.Visible = False

21. 'Autoriser les modif

22. .AllowEdits = True

23. .RecordSelectors = True

24. 'Autoriser les modif dans le sfMisesBasAgneaux

25. .CTNRsfMisesBasAgneaux.Form.AllowAdditions = True

26. .CTNRsfMisesBasAgneaux.Form.AllowDeletions = True

27. .CTNRsfMisesBasAgneaux.Form.AllowEdits = True

28. End If

29. End With

30. End Sub

32. Private Sub btComptabiliser_Click()

33. Dim iReponse As Integer

34. 'Demande de confirmation

35. iReponse = MsgBox("Confirmez que vous voulez enregistrer cette mise bas", vbYesNo + vbQuestion + vbDefaultButton2)

36. If iReponse = vbNo Then Exit Sub

37. With Me

38. 'MàJ de EnregistreeMB

39. .txtEnregistreeMB = True

40. 'Rendre le formulaire non modifiable

41. .AllowEdits = False

42. .AllowDeletions = False

43. 'Rendre le sous-formulaire non modifiable

44. .CTNRsfMisesBasAgneaux.Form.AllowAdditions = False

45. .CTNRsfMisesBasAgneaux.Form.AllowDeletions = False

46. .CTNRsfMisesBasAgneaux.Form.AllowEdits = False

47. 'Changer de bouton

48. .txtEnregistreeMB = True

49. .txtDateMB.SetFocus

50. .btComptabiliser.Visible = False

51. .btEnregistree.Visible = True

52. 'Enregistrer tMisesBas

53. .Refresh

54. End With

55. 'Enregistrer les naissances dans tOvins

56. DoCmd.SetWarnings False

57. DoCmd.OpenQuery "rComptaMiseBas"

58. DoCmd.SetWarnings True

59. 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.

(1) Un mâle « fictif » en cas d'insémination artificielle ou lors de l'achat d'une brebis déjà pleine.