Un formulaire de recherche basé sur la technique du père/fils

| Claude Leloup | Mandresy Rabenja |

Dans ce tutoriel, vous apprendrez à transformer, en quelques clics et copiés/collés, votre formulaire original en un outil de recherche multicritère.

Vous y trouverez aussi une manière inhabituelle d'utiliser la technique des formulaires « père et fils » pour réaliser votre sélection.

L'idée consiste à construire un nouveau formulaire « père » contenant un contrôle par critère de choix et votre formulaire original en tant que « fils ». Commentez

- Titre : Un formulaire de recherche basé sur la technique du père/fils

- Auteurs : Claude Leloup, Mandresy Rabenja

- Parution : 4 février 2014

- Mise à jour : 6 octobre 2017

- Licence : Copyright ® 2014 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Avant-propos

- II. Prérequis

- III. Comment s'y prendre

- III-A. Le point de départ

- III-B. Construire le « père »

- III-C. Incorporer le « fils »

- III-D. Établir la filiation

- III-E. Encore quelques bricoles et c'est fini !

- IV. Autres tutoriels traitant du sujet sur DVP

- V. Téléchargement

- VI. Remerciements

I - Avant-propos

Le principe des formulaires « père/fils » :

- le fils est un sous-formulaire du « père » ;

- la source du « père » et celle du « fils » ont des colonnes dont les valeurs sont communes ;

- lorsque le « père » affiche un enregistrement, le « fils » affiche uniquement les enregistrements qui correspondent aux valeurs communes.

Un exemple :

- le « père » décrit la recette ;

- le « fils » liste les ingrédients pour réaliser cette recette.

Dans le cas qui nous occupe, nous allons un peu ruser.

Au lieu de coordonner l'affichage du « père » et du « fils » d'après leur source, nous allons coordonner le « fils » sur la base de champs indépendants logés dans le formulaire « père ». (Ce dernier n'aura d'ailleurs pas de source !)

II - Prérequis

Avoir bien compris le mécanisme des formulaires « père/fils ». À ce sujet, vous pouvez consulter ce tutoriel Comment classer les données dans des tables liées et construire un formulaire père/fils et singulièrement son chapitre VII.

III - Comment s'y prendre

III-A - Le point de départ

Imaginez que vous disposez de ce formulaire :

Voici comment procéder pour l'utiliser comme formulaire de recherche multicritère en réutilisant, quasi telles quelles, les quelques lignes de code que nous détaillerons plus loin.

III-B - Construire le « père »

On incorpore autant de contrôles indépendants (des contrôles qui n'ont pas de propriété Source contrôle) que de critères de sélection souhaités.

Peu importe le type de ces contrôles : une zone de texte, une zone de liste (modifiable ou non), une case à cocher…

La seule contrainte, pour pouvoir utiliser telle quelle la proposition, c'est que le nom de ces contrôles soit composé du mot « Filtre » accolé au nom correspondant du Source contrôle du « fils » :

III-C - Incorporer le « fils »

Il suffit de glisser/déposer l'objet « fils » (le formulaire fVins) dans le « père » en mode construction (le formulaire fRecherche) :

À ce stade, parler de « père » et « fils » est un abus de langage, d'ailleurs si on regarde les propriétés du conteneur de fVins, on constate qu'Access n'a pas « spontanément » reconnu la filiation, comme il l'aurait fait si les sources avaient été deux tables liées.

III-D - Établir la filiation

Instinctivement, on se dit qu'il suffit de compléter soi-même les propriétés Champs fils et Champs pères comme ceci :

Pas si simple !

Si on procédait de la sorte, les deux formulaires seraient effectivement coordonnés et le « fils » afficherait ses enregistrements lorsque nous aurions simultanément :

[FiltreAppellation] = [Appellation]

[FiltreCategorie] = [Categorie]

[FiltreMillesime] = [Millesime]

[FiltreRegion] = [Region]

C'est le dur moment, où il faut se rappeler que si on compare Null à quoi que ce soit, la réponse est toujours « Null ». Dès lors, si un des filtres a la valeur Null, le « fils » n'affichera rien !

En fait, nous ce que nous voulons c'est :

- si un filtre est complété, il faut comparer sa valeur à celle de la source du « fils » ;

- si le filtre n'est pas complété, il faut ignorer la comparaison.

Pas moyen de communiquer cette règle lors de la création du formulaire.

Qu'à cela ne tienne, nous allons construire, à la volée, le comportement ad hoc.

L'algorithme est simple :

- au départ, les propriétés Champs fils et Champs pères sont vierges ;

- chaque fois que l'utilisateur modifiera la valeur d'un FiltreXxxx, on repèrera tous les contrôles FiltreXxxx non Null et on garnira les propriétés Champs fils et Champs pères en conséquence.

Voici le code qui se déclenchera après la mise à jour d'un de ces contrôles :

1. Public Sub Actu()

2. On Error GoTo GestionErreurs

3. Dim ctl As Control

4. Me(sConteneur).LinkMasterFields = ""

5. Me(sConteneur).LinkChildFields = ""

6. For Each ctl In Me.Controls

7. If Left(ctl.Name, 6) = "filtre" And Not IsNull(Me(ctl.Name)) Then

8. Me(sConteneur).LinkChildFields = Me(sConteneur).LinkChildFields _

9. & "[" & Right(ctl.Name, Len(ctl.Name) - 6) & "];"

10. Me(sConteneur).LinkMasterFields = Me(sConteneur).LinkMasterFields _

11. & "[" & ctl.Name & "];"

12. End If

13. Next ctl

14. Exit Sub

15. GestionErreurs:

16. Select Case Err.Number

17. Case 2335  'survient à partir de la 2e affectation d'un champ fils (sans conséquence)

18. Resume Next

19. Case Else

20. MsgBox "Erreur dans Sub Actu : " & Err.Number & " " & Err.Description

21. End Select

22. End Sub

Explication du code :

4-5 : on vide les propriétés Champs fils (LinkChildFields) et Champs pères (LinkMasterFields) de leur contenu précédent éventuel.

6 : on lance une boucle pour rechercher tous les contrôles du « père ».

7 -11 : pour ceux dont le nom commence par « Filtre » et qui n'ont pas la valeur Null, on complète les propriétés Champs fils et Champs pères.

Lorsque Champs pèresest encore vide, c'est-à-dire lors du 1er remplissage de Champs fils Access effectue, sans problème, le remplissage des deux propriétés.

Par contre lors de l'itération suivante, lorsqu'on veut par exemple ajouter [Categorie]; a Champs fils alors que Champs pères contient déjà [FiltreAppellation]; Access génère cette erreur :

C'est cette « fausse » erreur que l'on neutralise en 17-18.

Si vous êtes attentif, vous avez remarqué dans le code ci-dessus, que nous faisons référence au conteneur du sous-formulaire avec la syntaxe : Me(sConteneur).

Ceci est une astuce pour rendre le code plus générique : le code proposé fonctionnera quel que soit le nom que vous avez donné au conteneur (dans l'exemple, il s'appelle cntrVins)

Dans l'événement Sur ouverture du formulaire, nous avons ce code qui recherche le nom du conteneur :

1. Option Compare Database

2. Option Explicit

4. Dim sConteneur As String

5. Private Sub Form_Open(Cancel As Integer)

6. Dim ctl As Control

7. 'Recherche du nom du conteneur

8. For Each ctl In Me.Controls

9. If ctl.ControlType = acSubform Then

10. sConteneur = ctl.Name

11. Exit Sub

12. End If

13. Next ctl

14. End Sub

On déclenche une boucle sur la collection des contrôles du formulaire jusqu'à trouver celui qui est un conteneur (code type = acSubform), on mémorise alors son nom dans la variable sConteneur définie en tête du module de classe, donc visible tant que le formulaire reste ouvert.

III-E - Encore quelques bricoles et c'est fini !

À l'événement Après mise à jour de chaque contrôle FiltreXxxx, nous aurons ce code qui va déclencher la Sub Actu() présentée au paragraphe précédent :

Private Sub FiltreAppellation_AfterUpdate()
Call Actu
End Sub

Private Sub FiltreCategorie_AfterUpdate()
Call Actu
End Sub

Private Sub FiltreMillesime_AfterUpdate()
Call Actu
End Sub

Private Sub FiltreRegion_AfterUpdate()
Call Actu
End Sub

C'est le seul bout de code que vous devez adapter vous-même après avoir copié/collé le code fourni dans ce tutoriel.

Et, pour le confort, on ajoute un bouton dont le clic provoque la réinitialisation des contrôles FiltreXxxx :

Private Sub btTout_Click()
Dim ctl As Control
For Each ctl In Me.Controls
If Left(ctl.Name, 6) = "filtre" Then
Me(ctl.Name) = Null
End If
Next ctl
Call Actu
End Sub

IV - Autres tutoriels traitant du sujet sur DVP

RECHERCHE MULTI-CRITERE de cafeine ;

Création d'un formulaire de recherche multicritère de jeannot45 ;

Formulaire de recherche prêt à l'emploi de loufab ;

Formulaire de recherche sur la base d'une requête de votre serviteur.

V - Téléchargement

La base de données (Access2000) qui a servi à la mise au point de ce tutoriel est ici.

VI - Remerciements

À Christophe Warin (Tofalu) et à Philippe JOCHMANS qui ont corrigé et amélioré mon code.

À Arkham46 pour l'outil qui a facilité la rédaction et la mise en ligne de cet article.

À bipbip56 pour m'avoir signalé une erreur et à tee_grandbois pour l'avoir localisée.

À Philippe Duval (Phanloga) pour la correction orthographique.