Se positionner dans un formulaire ou un sous-formulaire

Une question revient souvent sur les forums du site : comment se positionner sur un enregistrement précis, dans un sous-formulaire ? Il a plusieurs méthodes pour résoudre ce problème, en voici une facile à réutiliser…

En fait, on va en profiter pour utiliser une méthode qui s’applique aux formulaires comme aux sous-formulaires.

flux_rss_sousform_demo.jpg

Le scénario

  • Je dispose d’un formulaire, sur lequel est « posé » un sous-formulaire qui donne la liste des articles, pour le flux concerné.
  • Peu importent les noms du formulaire et du sous-formulaire, il ne servent pas dans la suite.
  • Par contre, le container de sous-formulaire s’appelle sfmArticles.
  • Le formulaire est lié à une table tbl Flux dont la clef primaire est numérique.
  • Le sous-formulaire est lié à une table tbl Flux Articles dont la clef primaire est numérique également.

flux_rss_sousform.jpg

Je souhaite maintenant ajouter 2 boutons : l’un pour se positionner sur un flux précis, l’autre pour se positionner sur un article précis. Le positionnement se fera à partir du numéro de flux ou d’article :

  1. Je tape un numéro dans la zone de texte en haut à droite (txtNumero).
  2. Je clique sur l’un des 2 boutons.
  3. Access me positionne là où il faut… ou me signale une erreur si le numéro n’est pas trouvé.
Remarque
Il y a d’autres manières pour se positionner sur un enregistrement, utiliser des listes déroulantes par exemple. Vous adapterez en fonction de l’ergonomie souhaitée !

Une petite fonction pratique

Comme c’est le genre de besoin qu’on a très régulièrement dans une base Access, autant en faire une « boîte noire » réutilisable. Recopiez la fonction suivante dans un module standard de votre base de données :

La fonction reçoit 2 paramètres :

  • L’objet Formulaire (ou Sous-formulaire) dans lequel on souhaite se positionner.
  • Le critère permettant de trouver l’enregistrement.

Elle renvoie True si le positionnement a pu se faire, et False si on n’a pas trouvé l’enregistrement.

Pour info, le principe consiste à récupérer le jeu d’enregistrements (Recordset) qui alimente le formulaire, et à y déclencher une recherche (FindFirst). Si on trouve un enregistrement, on fait en sorte que le signet (Bookmark) de l’enregistrement trouvé soit appliqué au formulaire. Ce qui équivaut à « déplacer » le formulaire sur le signet en question…

Se positionner dans le formulaire

En guise d’application, on va s’occuper du bouton Atteindre le flux.

  1. Faites apparaître les propriétés de ce bouton.
  2. Donnez-lui un nom (dans mon cas : btnAfficherFlux).
  3. Activez l’onglet Evénement de la fenêtre Propriétés.
  4. Définissez l’événement Sur clic comme ceci :

Le code fait ceci :

  1. On vérifie que la zone de saisie contient bien un nombre (rappelez-vous que les numéros de flux et d’articles sont… des nombres dans ce scénario).
  2. On constitue ensuite le critère de recherche.
  3. Enfin et surtout, on appelle la fonction ChercherEnregistrement() écrite plus haut en lui passant : le formulaire en cours (Me), et le critère.
  4. Si la fonction renvoie False, on affiche un message d’erreur.

Se positionner dans le sous-formulaire

La bonne nouvelle, c’est que la technique s’applique aussi aux sous-formulaires. Seul l’objet Formulaire change. Voici donc le code du bouton Atteindre l’article :

L’objet Sous-formulaire est obtenu par Me.sfmArticles.Form. Et c’est tout !
Pour plus de détails sur cette syntaxe, consultez l’article Sous-formulaires : une mise au point.

Vous aimerez aussi...

25 réponses

  1. Leroy Eric dit :

    Merci pour ce didacticiel !!… Quelle joie de voir son application fonctionner !

  2. vincent kersten dit :

    Bonjour,

    J’espérais avoir trouvé une solution à mon problème (décrit ci dessous), mais il me renvoi une erreur dans la fonction :

    run-time error ‘3070’

    le moteur Jet ne reconnait pas ‘EE000004’ (ceci est bien la valeur à trouver) comme nom de champ valide ou expression !!!

    et il bloque sur la ligne rst.FindFirst srtCritere

    toute aide qui me permettrait de pouvoir me positionner sur l’enregistrement souhaité serait la bien venue.

    Merci

    Dans un application, j’ai un formulaire continu qui contient pas mal de ligne, les utilisateurs ne peuvent pas modifier directement dans ce formulaire, il passent par un petit form popup qui s’ouvre avec un double click sur le champ a modifier.
    Sur clic d’un bouton dans le popup le champ à modifier dans mon formulaire (d’origine) se met à jour sans problème grâce au ‘requery’ le problème est que requery ‘rafraichi’ tout le formulaire et renvoi le focus sur le premier champ de la première ligne; c’est gênant pour l’utilisateur qui modifie la 1418 éme ligne et qui après modif est bon pour retrouver sa ligne si il a d’autre chose à y modifier.

    Bref je cherche un moyen pour remettre le focus idéalement sur le champ sur lequel il a fait un double clic ou au pire sur la ligne concernée.

    Je pensais à un truc du genre gotorecord … mais je vois pas trop.

  3. Hervé Inisan dit :

    lune212 > Ta méthode pour alimenter la variable strCritere (ou ta variable param) est incorrecte : tu passes la valeur de formulaire uniquement, alors qu’il faudrait passes un filtre SQL valide.

    Tu peux t’inspirer de mon exemple, en regardant comment est construite strCritere dans le bloc btnAfficherArticle_Click.

  4. lune212 dit :

    Bonjour j ai utlisé ton code mais j’ai une erreur (argument non valide) et le débugger s’arrete à rst.FindFirst strCriter…je ne comprends pas … à l’aide svp
    Function ChercherEnregistrement(frm As Access.Form, strCritere As String) As Boolean

    ‘——————————————————–
    ‘ Variables
    Dim rst As dao.Recordset
    Dim blnResultat As Boolean

    ‘Le Recordset
    Set rst = frm.Recordset

    ‘Chercher l ‘enregistrement
    blnResultat = False
    MsgBox strCritere
    rst.FindFirst strCritere
    ‘Si recherche réussie la valeur de NoMatch est à False
    If Not rst.NoMatch Then
    frm.Bookmark = rst.Bookmark
    blnResultat = True
    End If

    ‘Libérer les objets
    Set rst = Nothing
    ChercherEnregistrement = blnResultat
    End Function

    Private Sub recherche_affaire_Click()
    Dim param As String

    ‘ Vérifier si la valeur est numérique
    If Not IsNumeric(Me.rechercher_affaire) Then
    MsgBox « La valeur cherchée doit être numérique ! », vbExclamation
    Exit Sub
    End If

    param = Form![rechercher_affaire]

    If Not ChercherEnregistrement(Me, param) Then
    MsgBox « Numéro d’affaire introuvable ! », vbExclamation
    End If

    End Sub

  5. Hervé Inisan dit :

    sara > L’article est en ligne, c’est à cette adresse. Ouala !

  6. sara dit :

    OK Merci énormément HERVE Inisan 🙂

  7. Hervé Inisan dit :

    sara > J’ai prévu un article d’ici quelques jours. A suivre… 🙂

  8. sara dit :

    Oui pourquoi par le changement de couleur de la ligne rechercher pour d’être plus visible, donc comment je peut le faire ?

    Merci Hervé 🙂

  9. Hervé Inisan dit :

    sara > Le clignotement n’est peut-être pas une bonne idée (vite fatiguant). Mais un changement de couleur de la ligne, par exemple (par mise en forme conditionnelle).

  10. sara dit :

    Bonjour Hervé,

    Merci beaucoup, effectivement, c’est une solution interessante…

    Mais je veux savoir est ce que possible quand il positionne sur un enregistrement précis la ligne de l’enregistrement commance à clignoter d’une couleur précis pour d’être visible. Je voudrais savoir s’il est possible de leur réaliser?

  11. Hervé Inisan dit :

    Soso > Faire un formulaire de recherche très générique n’est pas forcément facile, parce que la recherche dépend des noms de tables, des noms de champs, des types de données, etc. S’il s’agit de retrouver un enregistrement précis, peut-être qu’une liste déroulante de recherche peut convenir ?

  12. Soso dit :

    Bonjour,

    Bravo pour ce site, il est vraiment très clair!!

    Voilà, j’ai plusieurs formulaires et je veux faire un formulaire de recherche avec deux champs : Nom du formulaire et N° de la page qui est AutoNumérique. L’objectif de ce formulaire de recherche est de pouvoir donner la possibilité de remplir les champs manquants qui n’ont pas pu être compléter lors d’une précédente saisie.
    Je m’explique : J’ouvre mon formulaire puis je remplis les champs et je valide. Cette opération je la renouvèle régulièrement, ce qui fait que j’aurai plusieurs enregistrements. Par contre, il peut arriver un jour où je ne remplis pas la totalité des champs pour que je les remplisse une prochaine fois. Après quelques enregistrements, je décide de retourner à l’enregistrement incomplet. Donc, grâce à mon formulaire de recherche, je peux retrouver l’enregistrement très facilement et pouvoir le compléter. C’est valable pour tous les formulaires que j’ai. J’espère avoir été clair. Je voudrais savoir s’il est possible de leur réaliser?
    Je vous remercie pour votre réponse.

    Soso

  13. Hervé Inisan dit :

    saved68 > Pour la 2ème question : il est possible de masquer certains champs dans la partie « Liste » (ou « Feuille de données ») du formulaire double-affichage. Il suffit de faire un clic droit sur le champ, et de choisir Masquer. Ça permet de limiter le nombre d’informations dans cette liste.

    Pour la 1ère question, concernant les classes : pour n’avoir que les élèves d’une classe, il faut filtrer le formulaire sur la classe en question. Ça peut se faire soit de façon interactive (sélection de la classe sur le formulaire normal, clic droit, filtre), ou avec un peu de VBA (filtrage par liste déroulante).

    Ouala !

  14. saved68 dit :

    Merci beaucoup, effectivement, c’est une solution interessante… mais…
    Mais, j’aurai aimé que sur ce formulaire n’apparaisse que les élèves de la classe dans laquelle l’élève sur le formulaire apparait… cela ne semble possible qu’en triant la table…
    De plus, dans ce formulaire, j’ai aussi le nom des parents dans un autre onglet, et dans un troisième onglet, les éventuels suivis. Dès que je clique sur un des onglets, la table se déplace, pour afficher les informations, alors que je ne voudrais que n’apparaisse que le nom des élèves…. suis je trop gourmande?

    merci pour tes infos en tous les cas!

    savec

  15. Hervé Inisan dit :

    saved68 > Oui. Il suffit :

    1. De créer un formulaire simple (sans sous-formulaire, ce n’est plus la peine).
    2. De faire apparaître ses propriétés.
    3. Sous l’onglet Format, régler Affichage par défaut = Formulaire double affichage.

    C’est tout !

    On peut si nécessaire régler le double affichage par les autres options qui parlent de « double affichage », dans le même onglet de propriétés. Pratique, non ? 🙂

  16. saved68 dit :

    je possède access 2010… et c’est possible de le faire automatiquement??……

  17. Hervé Inisan dit :

    saved68 > Tu as quelle version d’Access ? A partir d’Access 2007, il y a une fonctionnalité qui fait ça automatiquement… 🙂

  18. saved68 dit :

    Bonjour,
    Bravo pour ce site, il est vraiment très clair!!

    Mais…. je pense avoir trouver une partie de la réponse, mais je n’en suis pas sure!
    Voilà, j’ai un formulaire avec les fiches de mes élèves. dans ce formulaire, j’ai mis un sous formulaire qui affiche tous les élèves de la classe, d’un élève afficher dans le formulaire.
    Je voudrais savoir s’il est possible, quand je selectionne un autre élève de la classe (qui se trouve dans le sous formulaire) de voir sa fiche s’afficher? (j’espère etre assez claire….)

    Je vous remercie pour votre réponse

    saved

  19. Lucas dit :

    C’est tout à fait ça! Je n’étais en effet pas sur la bonne piste. Il s’agissait bien de filtrer mon sous-formulaire et non pas d’atteindre un enregistrement spécifique de mon sous-formulaire.
    J’ai donc trouvé la solution à mon problème sur le site web suivant: http://www.pcastuces.com/pratique/w

    Voici les lignes de codes qui m’ont permit de mettre en place le filtre:

    strFiltre = « [dligne_date] BETWEEN  » & dtmPremierJourDuMois &  » AND  » & dtmDernierJourDuMois
    Me.Filter = strFiltre
    Me.FilterOn = True

    Merci d’avoir pris en compte ma demande

  20. Hervé Inisan dit :

    Lucas > A priori, dans ton cas, il ne s’agit pas d’atteindre une ligne du sous-formulaire, mais plutôt de filtrer le sous-formulaire sur un critère. Est-ce que c’est bien ça ?

    Sinon, en passant : j’éviterais les enchaînements de conversion sur la date : date => chaîne => numérique. On peut extraire directement le mois (numérique) d’une date, sans passer par la chaîne. La fonction Month() est ton amie. 🙂

  21. Lucas dit :

    Bonjour Hervé,
    Ce scénario de positionnement dans un sous-formulaire se rapproche beaucoup de ce que je souhaite réaliser dans mon propre projet, seulement voilà mon projet comporte une différence de taille qui ne me permet pas de mettre en œuvre ce positionnement. Je m’explique:
    •Je dispose d’un formulaire «frmSaisieJournaliereDetaillee», sur lequel est « posé » un sous-formulaire «sfrmSaisieJournaliereDetaillee_InsertionDate» qui donne la liste des jours travaillées (sous forme de date jj/mm/aaaa), pour un employé concerné.
    •Le formulaire est lié à une table «dentete» qui contient uniquement le nom des employés (ce sont les clefs primaires).
    •Le sous-formulaire est lié à une table «dligne» qui contient également le nom des employés et les dates travaillées pour chaque employés (ce sont tous 2 des clefs primaires).

    -A l’aide des flèches de navigation, je peux sélectionner un à un les différents employés dont le nom s’affiche dans une zone de texte de mon formulaire. En fonction de l’employé sélectionné, ses dates travaillées s’affichent alors dans le sous-formulaire en colonne les unes à la suite des autres avec la possibilité pour l’employé de saisir de nouvelles dates à la suite de la dernière date affichée.

    C’est là que se trouve la faille de mon projet. Pour l’instant les employés n’ont rentrés que les jours travaillés du mois de Juillet, mais arrivé au mois de Décembre il y aura déjà 184 jours (moins les weekends et jours fériés) d’affiché, et je vous laisse imaginer le nombre de jours qui s’afficheront dans 5 ans…

    Mon idée aurait donc été de rajouter une zone de texte ou une liste déroulante dans le sous-formulaire (ou le formulaire à voir…) qui contiendrait tous les mois de l’année. Ainsi, j’aurai la possibilité de n’afficher que les dates travaillées correspondant au mois sélectionné (suivra ensuite une liste déroulante des différentes années pour sélectionner la bonne année =] ).

    Seulement voilà, comme je le disais, à la différence de ce qui est présenté dans l’article, mes tables sont bien liés entre elles par le nom des employés ce qui me permet de rechercher les dates travaillées pour un employés donné mais je n’ai pas la possibilité de rechercher les dates correspondant à un mois donné… 🙁

    La question est donc de savoir s’il existe un moyen (autre que de modifier toute la structure de ma base de donnée et de mes relations entre chaque table) pour effectuer cette recherche et s’il est possible d’extraire uniquement les dates de ma table «dligne» correspondant au mois sélectionné?

    Dites oui! Dites oui!!! 🙂 🙂 🙂

    PS: Le fait de récupérer le mois sous forme de string puis de le transformer en numérique [ex: « Juillet » -> 04] puis de rechercher dans le Recordset toutes les dates qui sont de la forme jj/04/aaaa et enfin de les afficher est une des solutions à laquelle j’ai pensé mais je ne sais pas du tout si cela pourrait marcher et comment la mettre en place n’étant pas du tout à l’aise avec les Recordset… =]

    Merci du fond du coeur pour avoir eu le courage de lire mon « commentaire/roman » et pour peut-être réussir à trouver une solution à mon problème.

    Lucas

  22. Hervé Inisan dit :

    vanillie > La plupart des articles est déjà applicable à Access 2010. En fait, pour chaque article, les tags (en haut d’article) donnent les versions concernées. En général de 97 à 2010.

    Les captures d’écran de cet article sont d’ailleurs faites sous Access 2010.

  23. vanillie dit :

    Bonjour
    Allez-vous adapter ce site pour access 2010?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *