IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

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

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 ».20 commentaires Donner une note à l´article (5)  

Article lu   fois.

Les deux auteurs

Profil ProSite personnel

Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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.
Image non disponible

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 :

Image non disponible

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 »

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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 :

Image non disponible

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 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
Public Sub Actu()
  On Error GoTo GestionErreurs
  Dim ctl As Control
  Me(sConteneur).LinkMasterFields = ""
  Me(sConteneur).LinkChildFields = ""
  For Each ctl In Me.Controls
     If Left(ctl.Name, 6) = "filtre" And Not IsNull(Me(ctl.Name)) Then
         Me(sConteneur).LinkChildFields = Me(sConteneur).LinkChildFields _
             & "[" & Right(ctl.Name, Len(ctl.Name) - 6) & "];"
         Me(sConteneur).LinkMasterFields = Me(sConteneur).LinkMasterFields _
             & "[" & ctl.Name & "];"
     End If
  Next ctl
  Exit Sub
GestionErreurs:
  Select Case Err.Number
    Case 2335  'survient à partir de la 2e affectation d'un champ fils (sans conséquence)
      Resume Next
    Case Else
      MsgBox "Erreur dans Sub Actu : " & Err.Number & " " & Err.Description
  End Select
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:\MesDocuments\PrintScreen\i737.jpg

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)

Image non disponible

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

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
Option Compare Database
Option Explicit
               
Dim sConteneur As String
Private Sub Form_Open(Cancel As Integer)
  Dim ctl As Control
  'Recherche du nom du conteneur
  For Each ctl In Me.Controls
    If ctl.ControlType = acSubform Then
        sConteneur = ctl.Name
        Exit Sub
    End If
  Next ctl
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 :

 
Sélectionnez
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 :

Image non disponible
 
Sélectionnez
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

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.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Copyright © 2014 Claude Leloup Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.