Sélecteur par listes : version 2

Dans un précédent article intitulé Sélecteur par listes : version 1, nous avions mis en place un formulaire de sélection de valeurs. Aujourd’hui, nous allons adapter le principe pour que les valeurs proviennent d’une table, au lieu d’être statiques.

selecteur_clients.png

Avant de démarrer…

  • Les principes de construction sont proches de ceux traités dans l’article Sélecteur par listes : version 1. Consultez cet article pour démarrer, de nombreux points seront repris ici.
  • Pour que le mode de sélection soit le plus adaptable possible, nous allons également reprendre les principes vus dans l’article Une méthode élégante de sélection. Même si ça demande un peu plus d’efforts, nous obtiendrons un système plus évolutif.
  • Je suppose que votre base de données contient une table de clients (tbl Clients). Le reste va être monté dans ce qui suit…

Étape 1 : la table de sélection

Comme expliqué dans l’article Une méthode élégante de sélection, on va essayer d’avoir le moins d’impact possible sur la table Clients (pas de champ à ajouter dans cette table). Du coup, il vous faut une table spécifique pour gérer les sélections. La structure de cette table est donnée dans l’article cité.

Sélection Table

Étape 2 : la requête de sélection

Vous devez lier votre table Clients à la table de sélection construite précédemment. Une fois encore, reportez-vous à l’article Une méthode élégante de sélection. La requête y est détaillée aussi… La mienne s’appelle rqt Sélection Clients dans la suite.

selecteur_clients_requete.jpg

Étape 3 : le code VBA pour gérer les sélections

Pour gérer les sélections de façon transparente dans l’application, voici un certain nombre de procédures ou fonctions, que vous devez recopier dans un module standard de votre base :

En pratique, j’ai repris l’ensemble du module déjà donné dans l’article précédent, en ajoutant deux méthodes qui nous seront utiles ici :

  • La procédure InverserSelection inverse l’état d’une ligne (sélectionnée ou pas). Il s’agit simplement d’inverser la valeur du champ Oui/Non Sélectionné, dans la table tbl Sélections.
  • La fonction NombreSelections() renvoie le nombre d’enregistrements sélectionnés (on compte le nombre de champs Sélectionné cochés, dans la table tbl Sélections).

Étape 4 : le formulaire

Construisez un formulaire en mode Création, donc vide. Placez-y les éléments accessoires (le titre par exemple), et surtout les éléments suivants :

  • Une liste des clients (objet ListBox nommé lstClients).
  • Une deuxième liste, copiée de la précédente (objet ListBox nommé lstClientsSelectionnes).
  • 4 boutons pour la sélection d’un seul client (btnSelectionnerUn), la désélection d’un seul client (btnDeselectionnerUn), la sélection de tous les clients (btnSelectionnerTout), et la désélection de tous les clients (btnDeselectionnerTout). On considère qu’une sélection consiste à faire passer un ou plusieurs clients de gauche à droite, et qu’une dé-sélection… fait l’inverse !
  • 2 boutons pour l’interface générale : btnOK et btnAnnuler.

Les listes de clients

  1. Lors de la création des listes déroulantes, un Assistant devrait s’afficher. Choisissez l’option « Je veux que la zone de liste extraie les valeurs d’une table ou d’une requête« .
  2. Sélectionnez la requête rqt Sélection Clients créée plus haut.
  3. Choisissez les champs qui vous intéressent, en n’oubliant par la clef primaire de la table Clients (dans mon cas : Numéro Client). Ce champ sera placé en première colonne des listes (il peut être masqué s’il n’intéresse pas l’utilisateur). C’est lui qui donnera les numéros de client à manipuler.
  4. Une fois les deux listes construites, faites en sorte que la première affiche les clients non sélectionnés, et la seconde les clients sélectionnés. Pour cela :
    • Faites apparaître les propriétés de la première liste, onglet Données.
    • La propriété Contenu doit lister l’instruction SQL SELECT qui extrait les données. Cliquez sur les points de suspension à sa droite.
    • Vous obtenez un écran de requête. Appliquez le critère Oui au champ Sélectionné, sur la grille de requête.
    • Fermez cette requête en enregistrant les changements.
    • De retour au formulaire, refaites la même opération avec la seconde liste, cette fois Sélectionné = Non.

Étape 5 : initialisation du formulaire

A son ouverture, le formulaire doit réinitialiser la table des sélections, et mettre à jour les listes de clients. Voici le code VBA qui va s’en charger, à recopier dans le module du formulaire, pr
écisément :

Étape 6 : gérer les transferts d’une liste à l’autre

4 boutons ont été prévus pour permettre les sélections. On va aussi faire en sorte qu’un double-clic sur une liste sélectionne (ou dé-sélectionne) le client concerné. Avec ce qui a été mis en place plus haut (au point 3), la gestion des boutons et des listes reste plutôt courte… 🙂

  • Sélectionner / dé-sélectionner un client équivaut à inverser son état de sélection (rappelez-vous de la méthode InverserSelection plus haut).
  • Sélectionner ou dé-sélectionner tous les clients équivaut aussi à des appels de méthodes écrites précédemment.

Étape 7 : exploiter la sélection

On n’a plus qu’à gérer les boutons OK et Annuler. Commençons par le deuxième, facile, qui ferme le formulaire :

Pour le bouton OK, tout dépend de ce que vous voulez en faire (reportez-vous à la fin de l’article Une méthode élégante de sélection pour quelques compléments). Dans mon cas, je vais ouvrir un état filtré sur les clients sélectionnés (l’état est basé sur la requête rqt Sélection Clients). Ce qui donne :

selecteur_clients_etat.jpg

Ouf ! Si vous avez passé tous les obstacles…

  • vous obtenez un formulaire ergonomique pour sélectionner les clients ;
  • vous avez une méthode qui peut être adaptée à d’autres tables ;
  • le tout sans impact sur la structure des tables existantes ;
  • fonctionne en réseau ;
  • garanti sans phosphates 🙂

Finalement, ça valait peut-être le coup d’arriver jusque là ?! 🙂

Vous aimerez aussi...

33 réponses

  1. aldo dit :

    Bonjour,

    La macro blogue à « inverser Selection »
    ‘ —
    ‘ SELECTION D’UN ELEMENT
    ‘ —
    Private Sub btnSelectionnerUn_Click()
    InverserSelection Me.lstCDM.Value
    MiseAJourListes
    End Sub

    J’obtiens un message d’erreur
    « Erreur d’exécution ’94’:
    Utilisation incorrecte de Null »

    Quelqu’un peut m’aider, j’ai pourtant suivi la procédure à la lettre.
    Dans ce formulaire je souhaiterai sélectionner des élèves

  2. Hervé Inisan dit :

    Moha > A vue de nez, il faudrait aussi que lngNumero soit de type String et non plus Long (du coup, pour être cohérent, la variable devrait s’appeler strNumero).

  3. Moha dit :

    Bonsoir Mr Hervé
    Merci d’abord pour votre réponse, que j’ai essayé mais ça marche pas toujours:Erreur d’exécution ’13’ incompatibilité du type. N°QuittanceSelect : est de type texte sous forme alpha numérique : « 0040ZP »

    ‘ —
    ‘ INVERSER LA SELECTION D’UNE LIGNE
    ‘ —
    Sub InverserSelection( _
    ByVal lngNumero As Long, _
    Optional ByVal strTableSelection As String = « QuittancesSéléctionnées »)

    Dim strSQL As String
    strSQL = « UPDATE [ » & strTableSelection & « ] SET [Séléctionnées] = Not [Séléctionnées] » _
    &  » WHERE [N°QuittanceSelect] = ‘ » & lngNumero & « ‘ »
    CurrentDb.Execute strSQL
    End Sub

  4. Hervé Inisan dit :

    Moha > Est-ce que ma réponse a la 1ère question résout aussi la deuxième ?

  5. Moha dit :

    Pour exploiter la selection j’ai associé la requete sql ci-apès au boutton valider mais ça marche pas. pouvez vous m’aidé pour la corrigé :

    Private Sub ValidSitQuittance_Click()
    Dim strSQL As String
    strSQL = « UPDATE ReqQuittancesSelect SET ReqQuittancesSelect.SitQuit = [Formulaires]![TraitementsQuittances]![SitQuitTraitement], ReqQuittancesSelect.DateSituation = [Formulaires]![TraitementsQuittances]![DateTraitement] WHERE (((ReqQuittancesSelect.Séléctionnées)=Yes)); »
    CurrentDb.Execute strSQL
    End Sub

  6. Moha dit :

    Bonjour
    Comment adapter le code de la procédure InversionSelection dans le cas où la valeur n’est pas (long) mais un texte (Alpha numérique)
    Cordialement

  7. Hervé Inisan dit :

    Moha > A priori, il suffit d’adapter la requête SQL (variable strSQL) en délimitant le champ Numéro (s’il s’appelle comme ça) par des apostrophes. Du genre :

  8. Hervé Inisan dit :

    dany tall > Le type incompatible signifie que la valeur passée à la procédure InversionSelection n’est pas conforme. Dans mon exemple, cette valeur est supposée être un entier long (Long). Si la valeur fournie par la liste est d’un type différent, il faudra adapter le code.

  9. dany tall dit :

    Bonjour,

    je reviens sur mon problème concernant le message d’erreur  » utilisation incorrecte de NULL » lorsque j’exécute le « btnSelectionnerUn » (mais je pense que j’ai pu résoudre le problème) par contre pour faire la bascule inverse donc de la liste « lstfrsselectionnes » vers « lsfrs » j’ai ce message d’erreur « Incompatibilité de type » sur la ligne « InverserSelection Me… »

    Voici le code

    ‘ —————————-
    ‘ DESELECTION D’UN FOURNISSEUR
    ‘ —————————-
    Private Sub btndeselectionun_Click()

    InverserSelection Me.lstfrsselectionnes.Value
    ‘TransfererUn Me.lstfrsselectionnes, Me.lstfrs
    MiseAJourListes
    End Sub

    Quelqu’un pourrait-il m’aider svp je peine sur ce sujet depuis deux semaines déjà.

    Merci à tous.

    Dany

  10. Hervé Inisan dit :

    dany tall > Le débogage s’arrête sur quelle ligne exactement ?

  11. dany tall dit :

    Voici le message d’erreur que j’ai lorsque j’essaie de transférer ou non un élément de ma liste de sélection vers ma liste cible en cliquant sur le bouton « btnSelectionnerUn »: « Utilisation incorrecte de NULL »

  12. dany tall dit :

    OK c’est exactement ce que j’ai fait maintenant j’ai un problème avec la procédure « InverserSelection » j’ai suivi le conseil de Jean – Guy car j’ai lu qu’il a eu le même problème il y a bien longtemps mais je ne parviens pas à bien le résoudre.

  13. Hervé Inisan dit :

    dany tall > C’est ça. Le module standard est un module qui doit être créé manuellement.

    Par contre, le module du formulaire est accessible automatiquement (tout formulaire a un module unique associé). L’icône Code (ou Visualiser le code) donne accès à ce module, lorsqu’on est en mode Création de formulaire. Il suffit aussi, dans VBE, de double-cliquer sur le nom du formulaire (en fait, dans VBE : le nom du formulaire doit plutôt être vu comme « le nom du module de formulaire »).

    Toutes les étapes à partir de la 5 sont à reprendre dans le module du formulaire. C’est ça qui va associer du code VBA (des gestionnaires d’événements) aux boutons. Il faut que les noms des boutons soient identiques aux noms des blocs, sinon ça ne marchera pas. Si un bouton s’appelle btnTest, son gestionnaire d’événement Clic doit démarrer par :

  14. dany tall dit :

    Tapé dans le formulaire concerné? c’est-à-dire que je fais deux modules dont un standard et l’autre module dédié au formulaire? Dans le module du formulaire j’insère le code de l’étape 4 si j’ai bien compris?

  15. Hervé Inisan dit :

    dany tall > A priori, le code donné à l’étape 3 devrait être recopié dans un module standard, comme indiqué. Ça permet de le réutiliser sur d’autres formulaires si nécessaire. Par contre, ce qui suit est tapé dans le module du formulaire concerné, puisqu’il y a des gestionnaires d’événements associés aux boutons.

  16. dany tall dit :

    Bonjour Hervé,

    je pense pas qu’il y ait une erreur sur le nom d’un objet par contre j’ai mis tout le code dans un même module est ce que le problème ne viendrait pas de là?

  17. Hervé Inisan dit :

    dany tall > Est-ce qu’il pourrait y avoir une erreur sur le nom d’un objet (table, objet graphique…) ?

  18. dany tall dit :

    Bonjour,

    votre tuto sur le sélecteur de liste version 2 est vraiment très intéressante et m’aide beaucoup à traiter le même type de problème sur ma base de données. Par contre j’ai un petit soucis, en fait lorsque je clique sur le bouton ajouter un « élément », la sélection ne s’ajoute pas dans l’autre liste. Mais si je dé-sélectionne un élément de ma table « Tbl sélection », cette élément est bien supprimé de la liste « lst frs » mais il s’ajoute à la liste « lst frs sélectionnés », ce qui n’est pas normal.

    Comment faire pour que mon formulaire « sélecteur de frs » fonctionne correctement de telle sorte que lorsque je sélectionne un élément dans la liste « lst frs » et que je clique sur mon bouton « ajouter », que cet élément s’ajoute bien dans la liste « lst frs sélectionnés » ?

    En vous remerciant.

  19. Jean-Guy dit :

    Bonjour.

    Je vous fais part de ma solution au souci que j’avais avec la procedure inverserSelection dont je vous parlais hier.

    Je me suis rapproché des procedures selectionner et deselectionner toutes les lignes pour les comparer avec la procedure inverser la selection d’une ligne.

    J’ai ensuite copier la procedure inverser la selection d’une ligne.

    Je l’ai renommé Ajouter la selection d’une ligne soit AjouterSelection( _

    J’ai modifié le ligne de code:

    strSQL = « UPDATE [ » & strTableSelection & « ] SET [Sélectionné] = Not [Sélectionné] » _
    &  » WHERE [Numéro] =  » & lngNumero
    Par

    strSQL = « UPDATE [ » & strTableSelection & « ] SET [Sélectionné] = true » _
    &  » WHERE [Numéro] =  » & lngNumero

    J’ai donc remplacé NOT [Sélectionné] par True.

    Cela fonctionne.

    Puis pour le bouton enveler la sélection d’une ligne j’ai fais la même chose mais cette fois-ci en remplacant
    NOT[sélectionné] par False.

  20. Hervé Inisan dit :

    massi15 > Il n’y a rien de « natif » sur Access pour se déplacer de cette manière. Un petit bout de VBA pourrait faire l’affaire (à vérifier ceci dit, je n’ai pas eu le temps de tester).

  21. Jean-Guy dit :

    Je vous remercie de votre réponse rapide.

    Pour l’instant, le bouton ajouter pointe sur le code btnSelectionnerUn_Click() du formulaire qui lui appelle le code InverserSelection du module 1.

    Je précise que j’ai le même phénomène avec le bouton enlever quand je selectionne un élément à enlever de la liste de selection.

    En attentant, je vais me pencher dans la rubrique liaisons office.

    Pour mon cas le volume à traiter sera important.

    J’ai quelques 200000 enregistrements à traiter répartis sur environ 200 fichiers excel( ils ont tous la même structure).

    J’ai été attiré par votre méthode de selection, au départ pour l’initialisation de la base.

    Je m’explique:

    Mon projet servira à des utilisateurs à vocation régionale.

    j’ai environ 200 fichiers comportant des données au niveau national.

    Chaque utilisateur choisira les départements concernés à sa région. Le choix fait, Il sera créé une table avec les données extraites des fichiers excel nationaux correspondant aux départements choisis.

    tous les traitement suivants se feront sur la table nouvellement créée. Les utilisateurs auront ainsi une base propre à leur région.

    Dans mon projet, c’est la phase d’initialisation.

    Merci pour votre aide.

  22. Hervé Inisan dit :

    Jean-Guy > Le bouton Ajouter est couplé à quel code VBA pour l’instant ?

    Pour la partie 2, il y a quelques articles sur l’interface Access/Excel dans la rubrique « Liaisons Office », mais sans doute pas d’article répondant précisément à la question. Ça peut déjà donner quelques pistes.

    Selon le volume à traiter, ce sera plus rapide d’importer les données Excel dans une table temporaire Access, puis de filtrer par requête.

  23. Jean-Guy dit :

    Bonjour.

    Suite a votre tuto sur le sélecteur de liste:version 1 je viens de suivre celui-ci.

    Je suis bloqué par la procédure « inverserSelection ».

    Je vous rassure, cette procédure fonctionne bien mais le résultat est déroutant pour un ultilsateur lambda.

    Je m’explique: J’ai un bouton ajouter.

    Je clique une fois sur le bouton, la sélection s’ajoute bien dans l’autre liste. Mais si l’on clique une seconde fois, cette même selection retourne dans la première liste, c’est normal puisqu’on inverse la selection.

    Mais comment faire pour que cette selection reste bien ajoutée dans la seconde liste et qu’elle ne retourne pas à son emplacement initial ?

    D’autre part, je voudrais pouvoir, avec les elements selectionnés, rechercher des enregistrements dans plusieurs fichiers excel et les importer dans une nouvelle table.

    Avez vous travaillé sur des tutos qui pourraient m’aider à avancer dans mon projet.

    En vous remerciant.

    Jean-Guy

  24. massi15 dit :

    Bonjour,
    Ce n’est pas ainsi. Les données sont affichées dans la liste, par exemple colonne « mot » et colonne « long ». Ordere de tri : long, mot. Je cherche à afficher le premier mot de chaque nouvelle longueur, sans savoir combien il y a de mots entre deux longueurs. J’essaye Alt+flèche bas, ou Ctrl+flèche bas pour avancer.
    Mais rien de concluant. Une idée ?
    merci. daniel

  25. Hervé Inisan dit :

    massi15 > Est-ce que cet article ne répondrait pas mieux à ton besoin ?

  26. massi15 dit :

    Bonjour,
    Effectivement, j’ai plus d’enregistrements qu’il est possible d’afficher.
    Exemple : j’affiche 20 enregistrements à l’écran, donc visibles.
    Mais je veux afficher le 59° de la liste dans l’écran.
    En VBA, quels ordres dois-je utiliser pour rendre visible cet enregistrement ?
    Merci beaucoup
    daniel

  27. Hervé Inisan dit :

    massi15 > Je verrais les choses autrement : « faire défiler » est un raisonnement qui repose sur l’interface graphique, mais pas sur les données. Il vaut mieux raisonner sur les données, l’interface vient ensuite : l’idée est « d’atteindre un enregistrement précis de la table » ?

  28. massi15 dit :

    Bonjour,
    J’ai effectivement suivi votre conseil et utilidé DAO. Trés facile à mettre en oeuvre.
    Mais, toujours en VBA, je cherche à faire défiler les enregistrements affichés, de manière à voir l’enregistrement sur lequel porte un certain travail.
    Une idée des ordres à utiliser ? J’ai longuement cherché. Je sais faire bouger une fenêtre mais pas son contenu, ni l’ascenseur.
    Bizarre.
    Merci pour votre réponse
    daniel

  29. Hervé Inisan dit :

    massi15 > Si c’est un problème de pur calcul de TVA (par exemple), et si les tables sont correctement structurées, on peut effectivement extraire le taux de TVA associé à un produit, et créer un champ calculé pour obtenir le TTC. Ça se fera dans une requête (graphique ou SQL) basée elle-même sur la jonction des tables concernées, avec un champ calculé donnant le TTC.

    Comme la question de départ portait sur une fonction VBA, la question de DAO se posait effectivement. Mais si c’est du calcul « direct », il n’y a pas besoin de VBA du tout.. Ou alors, éventuellement, pour simplifier une formule dans une requête (et déplacer le calcul dans une fonction VBA).

  30. massi15 dit :

    Bonjour,
    Je passe de 2003 à 2010 et réécris certaines séquences.
    Dans la facturation, je dois aller chercher différents taux, divers numéros de compte.
    Dont en particulier, dans la table TPays, les taux de TVA, les taux de réduction et remise…
    de façon à calculer le TTC.
    Tout ces accès doivent s’effectuer automatiquement (ouverture, lecture, fermeture). Or les tables sont déjà présentes puisque la base est ouverte : lancer une requête en SQl ne suffit pas sans passer par ADO ?
    Ou par tout autre moyen.
    merci
    daniel

  31. Hervé Inisan dit :

    massi15 > Si j’ai suivi, il y a plusieurs manières de faire ce que tu souhaites, mais elles tournent quasiment toutes autour de DAO ou ADO, puisque ces couches sont des interfaces entre le stockage (SQL) et VBA.

    Quel est l’objectif précis ?

    • Se positionner sur un enregistrement existant, dans le formulaire ?
    • Chercher des valeurs pour effectuer un traitement particulier ?
    • Autre chose ?
  32. massi15 dit :

    Bonjour,
    Je cherche une méthode semblable à celle que vous exposez mais en automatique.
    Je m’explique. Dans une fonction en VBA, je dois aller dans la table Pays, chercher le pays concerné pour prendre les paramètres afférents.
    Est-ce que en automatique je peux lancer dans une table déjà ouverte une recherche de type SQL, et récupérer divers paramètres.
    Sans passer par DAO, ADO…puisque la table est déjà présente.
    Merci beaucoup
    daniel

Laisser un commentaire

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