Bonjour,
La recherche dans un TListView via la SearchBox reste une de mes bêtes noires. En effet, de base, tous les éléments texte d'un item sont pris en considération (visibles ou non) et par défaut, la recherche se fait sur un Contains sans casse. [Aparté] vous ne trouvez pas que Contains devrait avoir, comme StartsWith ou EndsWith, la possibilité d'être "case sensitive" !? [/Aparté]
Vous me rétorquerez qu'il existe un évènement OnFilter qui permet de modifier ce comportement.
Exact mais, problème : OnFilter n'indique que la valeur testée mais aucune indication de l'élément de l'item, qu'en est-il si je ne veux tester un seul élément (pour l'instant je m'arrête à un seul )
Donc, je repars en croisade après cette discussion.
Par rapport au bébé de la discussion (je n'aimais pas trop cette variable booléenne restrictive),
j'ai établi un premier "brouillon" (qui fonctionne) mon idée de départ, ajouter, en quelque sorte, des propriétés (TSearchInlist) à la TListView par l'intermédiaire de son TagObject.
Avantage de cette solution : la recherche devient "paramétrable" puisqu'il me suffit de changer l'objet
Cela va certainement évoluer dans la journée pour avoir quelque chose de plus "portable" :
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
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 type TSearchMode = (smContains, smStartwith, smEndwith); TSearchinList = Class(TObject) private CurIndice : UInt8; FieldIndice :Smallint; MaxIndice : UInt8; Mode : TSearchMode; casesensitive : Boolean; end; TForm1 = class(TForm) ListView1: TListView; PrototypeBindSource1: TPrototypeBindSource; BindingsList1: TBindingsList; LinkFillControlToField1: TLinkFillControlToField; procedure ListView1Filter(Sender: TObject; const AFilter, AValue: string; var Accept: Boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Déclarations privées } S : TSearchinList; public { Déclarations publiques } end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.FormCreate(Sender: TObject); begin S:=TSearchinList.Create; S.CurIndice:=0; S.FieldIndice:=-1; // -1 tout les éléments S.MaxIndice:=1; // nombre d'élements avec caption d'un item de liste S.Mode:=smContains; S.casesensitive:=False; ListView1.TagObject:=S; end; procedure TForm1.FormDestroy(Sender: TObject); begin S.Free; end; procedure TForm1.ListView1Filter(Sender: TObject; const AFilter, AValue: string; var Accept: Boolean); var AVal, AFil : String; // à cause de Contains je dois passer par des variables locales pour la casse :-( begin Accept:=True; if AFilter.IsEmpty then Exit; AVal:=AValue; AFil:=AFilter; if not TSearchInList(Listview1.TagObject).casesensitive then begin AVal:=LowerCase(AValue); AFil:=LowerCase(AFilter); end; case S.Mode of smContains : Accept:=((S.FieldIndice=-1) OR (S.CurIndice=S.FieldIndice)) AND AVal.Contains(AFil); smStartwith : Accept:=((S.FieldIndice=-1) OR (S.CurIndice=S.FieldIndice)) AND AVal.StartsWith(AFil); smEndwith : Accept:=((S.FieldIndice=-1) OR (S.CurIndice=S.FieldIndice)) AND Aval.EndsWith(AFil); end; if Accept then S.CurIndice:=0 else inc(S.CurIndice); {TODO : à revoir} if S.CurIndice>S.MaxIndice then S.CurIndice:=0; // Oui mais s'il s'agit d'un Entête ou d'un Pied ? end; end.
1 - Ajouter un constructor (avec initialisation des "propriétés"). À ce propos coder ça proprement <?
2 - mettre une partie du "filtre" dans l'objet
3 - retrouver le MaxIndice (nombre d'élements avec caption d'un item de liste), le constructeur me fournirait le nom de la liste
4 - plutôt que d'utiliser le FieldIndice, retrouver les noms des éléments ce qui serait plus facile
Mes autres questions
- tout d'abord ma démarche, qu'en pensez vous ?
- il serait mieux de savoir de quel élément/item il s'agit mais comment ?
- d'autres suggestions ?
Partager