[Actualité] TControlList et sélection multiple
par
, 11/11/2023 à 12h03 (4122 Affichages)
La version Delphi 11 a apporté la possibilité de faire une multiple sélection d'éléments avec les classiques manipulations de clavier (Ctrl+Click, Ctrl+Shift+Click). Si je n'avais rien publié à ce sujet, c'est parce que l'obtention des éléments sélectionnés me paraissait boguée (ce qui a d'ailleurs fait l'objet d'une demande sur le portail qualité RSP-40821). En effet, lorsque l'on tentait d'obtenir la liste des éléments sélectionnés, souvent le dernier élément était omis.
L'objectif de ce billet est de vous montrer le symptôme et surtout de proposer une solution.
Le design du programme est simple :
- Un TControList, l'élément contiendra un TLabel pour afficher une valeur
- Un TMemo.
- Un TButton.
- Et, pour ce qui est des données, un TProtypeBindSource pour obtenir une liste de contact.
Comme déjà montré dans mes billets sur ce composant, il faudra utiliser LiveBinding pour lier la liste à la source de données et au libellé (Label1)
Cette fonctionnalité de multiple sélection doit être activée par code
Pour les besoins de mon test, je le fais dès la création de la forme.
La version 12 propose une propriété mutiselect accessible au design.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 procedure TFormTest.FormCreate(Sender: TObject); begin ControlList1.MultiSelect:=True; end;
Pour obtenir la liste des éléments sélectionnés, il faut parcourir l'ensemble des éléments et tester si oui ou non, il l'est.
À l'exécution, la sélection fonctionne
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 procedure TFormTest.btnListeSelectionClick(Sender: TObject); begin Memo1.Lines.Clear; // efface l'ancien résultat for var i:= 0 to ControlList1.ItemCount-1 do // parcourir l'ensemble des élémnts if ControlList1.Selected[i] then // élément sélectionné ? begin ControlList1.ItemIndex:=i; // se positionner dessus pour accéder à label1 Memo1.Lines.Add(i.ToString+ ' - ' +label1.caption); end; end;
mais le résultat déçoit
Christine Jones, dernier nom sélectionné, n'est pas listé dans le mémo et n'apparait plus comme tel dans la TControlList
La faute en est très certainement au repositionnement pour accéder à label1.
P.S. Cet effet sera beaucoup plus visible si vous jouez avec les ItemSelectionOptions permettant de modifier couleurs et transparences
- HotColor
- SelectedColor
- FocusedColor
- HotColorAlpha
- SelectedColorAlpha
- FocusedColorAlpha
et même la couleur de fonte selon l'état
- HotFontColor
- SelectedFontColor
- FocusedFontColor
- UseFontColorForLabels
Maintenant, voici comment contourner ce problème
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 procedure TFormTest.btnListeSelectionClick(Sender: TObject); var lastSelected : integer; begin Memo1.Lines.Clear; // mémorise la position LastSelected:=ControlList1.ItemIndex; // au cas où l'élément ne ferait pas partie de la sélection // ne devrait pas arriver if not ControlList1.Selected[LastSelected] then LastSelected:=-1; for var i:= 0 to ControlList1.ItemCount-1 do if ControlList1.Selected[i] OR (i=lastSelected) then begin ControlList1.ItemIndex:=i; Memo1.Lines.Add(i.ToString+ ' - '+label1.caption); end; // Se repositionner sur le dernier élément sélectionné ControlList1.ItemIndex:=LastSelected; // redessiner la liste ControlList1.Invalidate; end;