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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants VCL Delphi Discussion :

Comment récupérer les élements sélectionnés d'une ListBox ?


Sujet :

Composants VCL Delphi

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 54
    Points : 36
    Points
    36
    Par défaut Comment récupérer les élements sélectionnés d'une ListBox ?
    'lut

    J'ai beau chercher, je ne vois pas comment récuperer l'index de tous les élements sélectionnés d'une listBox avec multiSelect et Extendedselect activés. La propriété Count donne bien le nombre d'items sélectionnés, mais comment accéder à ceux qui n'ont pas le focus ?

  2. #2
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut,

    Il faut que tu examines la propriété Selected.

    Je te donne un cours exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    begin
      for i :=0 to(ListBox1.Items.Count -1)do begin
        if ListBox1.Selected[i]then 
          // Elément sélectionné
        else
          // Elément non sélectionné
    end;
    Voilou !
    @+

  3. #3
    Membre expérimenté
    Avatar de Frank
    Homme Profil pro
    Chef de projet Informatique
    Inscrit en
    Avril 2002
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Chef de projet Informatique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 095
    Points : 1 392
    Points
    1 392
    Par défaut
    Exemple de lecture d'une listbox

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure Tfrm_testD2006.Bt_fermetureClick(Sender: TObject);
      var i:integer;
    begin
      for I := 0 to lbtest.Count - 1 do begin
        showmessage(lbtest.Items.ValueFromIndex[i]);
      end;

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 54
    Points : 36
    Points
    36
    Par défaut
    merci bien, ça marche nickel.

  5. #5
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 064
    Points : 420
    Points
    420
    Par défaut
    On est obligés de parcourir toute la liste pour avoir les élements sélectionnés ?

    Je ne trouve pas ca très optimisé...
    David.

  6. #6
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Points : 64
    Points
    64
    Par défaut ListBox avec MultiSelect actif
    Ce post est un peu vieux mais j'aimerais attirer l'attention sur une faille de la solution proposée par Cl@udius :

    parcourir une longue liste de valeurs couplé à une évaluation à chaque itération est très malsain pour les ressources d'un ordinateur !!!

    donc vivement une propriété encapsulée dans le ListBox à cet effet.

  7. #7
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 747
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 747
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par Fandyz Voir le message
    parcourir une longue liste de valeurs couplé à une évaluation à chaque itération est très malsain pour les ressources d'un ordinateur !!!
    Ce qui veut dire ?

  8. #8
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    Il n'y a aucun problème avec la solution proposée car de toute façon c'est la seule solution possible, parcourir pour savoir qui est à True ou pas.

    Ce serait plus lourd de maintenir une liste des indexs sélectionnés/désélectionnés et dégraderait les performances globale de la liste...

    Tant qu'on ne touche pas à l'aspect de la liste, les boucles de ce genre sont très rapides à s’exécuter.
    Il faudra par contre faire appel à Items.BeginUpdate/EndUpdate si l'on inverse les état ou que l'on modifie les chaines de la liste.

    On peu par contre maintenir un compteur d'itération dans la boucle pour break dés qu'on dépasse le nombre de SelectCount !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for N := 0 to ListBox1.Count-1 do
    begin
      if ListBox1.Selected[N] then
        // 
      else
        //
      inc(I);
      if I >= ListBox1.SelectCount then
        break;
    end;
    Il ne faut pas oublier que l'on vas parcourir une List de booléens et non une liste de chaines !
    [ Sources et programmes de Dr.Who | FAQ Delphi | FAQ Pascal | Règlement | Contactez l'équipe ]
    Ma messagerie n'est pas la succursale du forum... merci!

  9. #9
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Points : 64
    Points
    64
    Par défaut
    Ce serait plus lourd de maintenir une liste des indexs sélectionnés/désélectionnés et dégraderait les performances globale de la liste...
    J'avoue que je ne saisie pas ton idée Dr.Who.
    Pour ma part, pour palier à cette "insuffisance" des ListBox, j'ajoute un champ TStrings dans mon unité. Ensuite, à chaque clic sur la liste, il me suffit de :
    • ajouter l'index sélectionné à la liste s'il n'y figure pas
    • retirer l'index de la liste s' il y est déjà

    Ainsi, j'ai toujours une liste des index sélectionnés.
    Je choisit un TStrings afin d'utiliser la méthode "IndexOf()" pour la recherche de l'index.

    On peu par contre maintenir un compteur d'itération dans la boucle pour break dés qu'on dépasse le nombre de SelectCount !

    for N := 0 to ListBox1.Count-1 do
    begin
    if ListBox1.Selected[N] then
    //
    else
    //
    inc(I);
    if I >= ListBox1.SelectCount then
    break;
    end;
    Il ne faut pas oublier que l'on vas parcourir une List de booléens et non une liste de chaines !
    En réalité, c'est bien ceci qui m'inquiète : il y a une évaluation à chaque itération et ça c'est (forcément) mauvais pour les performances d'un programme.

    Une dernière chose : je ne critique pas la méthode proposée par Cl@udius et je l'utilise même souvent (quand la liste n'est pas trop longue) mais je pense que trouver une autre approche serait préférable.

    Fandyz.

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 547
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 547
    Points : 25 116
    Points
    25 116
    Par défaut
    Citation Envoyé par Fandyz Voir le message
    donc vivement une propriété encapsulée dans le ListBox à cet effet.
    la TListBox n'est qu'un wrapper pour List Box (Windows) en jouant avec LB_GETSEL et LB_GETSELCOUNT
    mais il est vrai qu'il manque un accès à LB_GETSELITEMS

    Citation Envoyé par Extrait du Win32 SDK fourni avec C++Builder 6 pour Win32 (9x) et WinNT (4)
    An application sends an LB_GETSELITEMS message to fill a buffer with an array of integers that specify the item numbers of selected items in a multiple-selection list box.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    LB_GETSELITEMS  
    wParam = (WPARAM) cItems;           // maximum number of items  
    lParam = (LPARAM) (LPINT) lpnItems; // address of buffer
    Mais suffit de faire un effort !

    un code C++Builder théorique :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    int * Selections = new int[ListBox->SelCount];
    try
    {
      int SelectionCount = ListBox->Perform(LB_GETSELITEMS, ListBox->SelCount, (LPARAM)Selections);
      for (int i = 0; i < SelectionCount; i++)
      {
        // Ici je n'ai que les éléments sélectionnés !
        // Il est très rapide de trouver un entier dans un tableau d'entier
      }
    }  
    __finally
    {
      delete [] Selections;
    }

    en Delphi, ça doit ressemble à ça, je suis un peu rouillé !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
      Length(Selections, ListBox.SelCount); // TIntegerDynArray
      SelectionCount = ListBox.Perform(LB_GETSELITEMS, ListBox.SelCount, LPARAM(@Selections[0]));
      for i := 0 to SelectionCount - 1 do
      begin
     
        // Ici je n'ai que les éléments sélectionnés !
      end;
    Pour vouloir faire sa propre liste d'index alors qu'il suffit d'utiliser LB_GETSELITEMS !


    Citation Envoyé par Fandyz Voir le message
    J'avoue que je ne saisie pas ton idée Dr.Who.
    Dr.Who avait anticipé que l'utilisation d'un TStrings était une fausse bonne idée !

    Citation Envoyé par Fandyz Voir le message
    quand la liste n'est pas trop longue
    Tout dépend ce que l'on appel long !

    Long pour un CPU, c'est plusieurs milliers !
    Long pour un utilisateur, c'est une centaine !




    Citation Envoyé par Fandyz Voir le message
    Je choisit un TStrings afin d'utiliser la méthode "IndexOf()" pour la recherche de l'index.
    Une TStrings pour stocker des Entiers ?
    Donc tu converti ton Entier pour utiliser IndexOf qui lui compare les nombres stockés en Texte !
    Si ta liste est triée, cela fait le Find à chaque Add, sans compter le décalage en mémoire pour conserver le tri, idem le Delete provoque une boucle puis un décalage des pointeurs de chaines, et ne parle même pas des réallocations même si optimisé par le Grow en multiple de 16

    Si ta liste n'est pas triée, tu fais explicitement le IndexOf ... le temps de recherche est plus long que sur une liste triée, mais ta liste ne sera jamais si longue pour que l'on puisse s’inquiéter de la différence de performance avec ou sans tri !

    Au final, tu as consommé bien plus de CPU mais dispersé dans le temps, avec une très grande sélection ton code consomme plus en plus de CPU à chaque nouvel item, donc tu ralentis ton IHM, et en plus cela consomme de plus en plus de RAM !

    Citation Envoyé par Fandyz Voir le message
    En réalité, c'est bien ceci qui m'inquiète : il y a une évaluation à chaque itération et ça c'est (forcément) mauvais pour les performances d'un programme. ...

    ... méthode proposée par Cl@udius je l'utilise même souvent (quand la liste n'est pas trop longue) ...
    Si je comprends bien tu utilses une TStrings d'index pour une liste longue ?!

    Ce qui m'inquiète c'est que tu utilises cette technique d'indexation dans le cas qui la rend le plus potentiellement contre-performante !

    Change ton code et utilise LB_GETSELITEMS !
    Mais il est vrai qu'il est toujours fun de réinventez la roue carrée !
    Je l'ai tellement fait !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  11. #11
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    Que dire de plus que Shay qui à parfaitement démontré l'inutilité de la méthode.

    Un traitement est un traitement, s'il faut une plombe pour le faire, une progressbar pour ne pas énerver l'utilisateur.

    Une action se doit par contre d'être rapide.
    [ Sources et programmes de Dr.Who | FAQ Delphi | FAQ Pascal | Règlement | Contactez l'équipe ]
    Ma messagerie n'est pas la succursale du forum... merci!

  12. #12
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    Citation Envoyé par Dr.Who Voir le message
    Que dire de plus que Shay qui à parfaitement démontré l'inutilité de la méthode.

    Un traitement est un traitement, s'il faut une plombe pour le faire, une progressbar pour ne pas énerver l'utilisateur.

    Une action se doit par contre d'être rapide.
    j'ajouterais que pour une longue liste, TListBox n'est intéressant qu'en mode virtuel, et dans ce cas la liste réelle des items peut très bien conserver l'état de chaque item.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 13
    Dernier message: 21/05/2012, 15h46
  2. Réponses: 1
    Dernier message: 29/07/2010, 16h10
  3. [OpenOffice][Tableur] [Macro] Comment récupérer un nom sélectionné dans une listBox
    Par Big Brother dans le forum OpenOffice & LibreOffice
    Réponses: 1
    Dernier message: 07/11/2008, 17h42
  4. Réponses: 1
    Dernier message: 07/06/2006, 18h56
  5. Réponses: 1
    Dernier message: 18/05/2006, 11h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo