Author: Ernesto De Spirito
How can I sort the items in a TListView?
Answer:
Sorting by the first column
Sorting a TListView by the first column is easy:
ListView1.SortType := stText;
Setting SortType to stText is more or less like setting Sorted to True in a
TListBox object. The list will be sorted and will remain sorted after additions and
modifications, until SortType is set back to stNone:
ListView1.SortType := stNone;
It's like setting Sorted to False in a TListBox object. It won't undo the sorting,
but future additions and modifications to the items list won't be sorted.
Sorting with an OnCompare event
To have a TListView sorted on another column (or arbitrary data stored or
referenced in TListItem objects), we should either write an OnCompare event or an
ordering function to be used with the CustomSort method. If you want to sort keep a
list sorted while adding and modifying items, then you should use an OnCompare
event.
1
2 procedure(Sender: TObject; Item1, Item2: TListItem;
3 Data: Integer; var Compare: Integer) of object;
The parameter Compare which is passed by reference should be set to 1, -1 or 0
depending on whether the first item is greater than (or should be placed after) the
second item, the first item is lower than (or should be placed before) the second
item, or if the two items are equal, respectively. In the following example we are
sorting a TListView by its fourth column (wich represents integer values) in
descending order:
4
5 procedure TForm1.ListView1Compare(Sender: TObject; Item1,
6 Item2: TListItem; Data: Integer; var Compare: Integer);
7 var
8 n1, n2: integer;
9 begin
10 n1 := StrToInt(Item1.SubItems[2]);
11 n2 := StrToInt(Item2.SubItems[2]);
12 if n1 > n2 then
13 Compare := -1
14 else if n1 < n2 then
15 Compare := 1
16 else
17 Compare := 0;
18 end;
Now that we have an OnCompare event, to sort the list and having sorted, we should
set SortType to stBoth (instead of stText, that sorts by the first column without
using the OnCompare event):
ListView1.SortType := stBoth;
If you just want to perform a temporal sort, you can do the following:
19
20 ListView1.SortType := stBoth;
21 ListView1.SortType := stNone;
22
23 //or else:
24
25 ListView1.CustomSort(nil, 0);
Sorting with an ordering function
If you need a faster sort, then you should write an ordering function. This
function should return 1, -1 or 0 (like the Compare parameter of the OnCompare
event discussed above). For example:
26
27 function ByFourth(Item1, Item2: TListItem; Data: integer):
28 integer; stdcall;
29 var
30 n1, n2: cardinal;
31 begin
32 n1 := StrToInt(Item1.SubItems[2]);
33 n2 := StrToInt(Item2.SubItems[2]);
34 if n1 > n2 then
35 Result := -1
36 else if n1 < n2 then
37 Result := 1
38 else
39 Result := 0;
40 end;
Then, every time you want to sort the list, you call CustomSort passing the address
of the ordering function. For example:
41
42 ListView1.CustomSort(@ByFourth, 0);
The Data parameter of the OnCompare event is 0 if the event is called automatically
when SortType is stData or stBoth, but if it is generated because of a call to
CustomSort, then its value is the second parameter to this method. The same happens
with the Data parameter of the ordering function, so the Data parameter is normally
used to specify a column to sort (we didn't use it in our example to make it
simple).
Source Example
43 var
44 Ascending: boolean;
45
46 function SortByColumn(Item1, Item2: TListItem; Data: integer):
47 integer; stdcall;
48 // Copyright (c) 2001 Ernesto D'Spirito
49 // edspirito@latiumsoftware.com
50 // http://www.latiumsoftware.com
51 begin
52 if Data = 0 then
53 Result := AnsiCompareText(Item1.Caption, Item2.Caption)
54 else
55 Result := AnsiCompareText(Item1.SubItems[Data - 1],
56 Item2.SubItems[Data - 1]);
57 if Result < 0 then
58 begin
59 if Ascending then
60 Result := -1
61 else
62 Result := 1;
63 end
64 else if Result > 0 then
65 begin
66 if Ascending then
67 Result := 1
68 else
69 Result := -1;
70 end;
71 end;
72
73 procedure TForm1.ListView1ColumnClick(Sender: TObject;
74 Column: TListColumn);
75 begin
76 // Toggle column Tag
77 Column.Tag := 1 - Column.Tag; // 0 -> 1 ; 1 -> 0
78 // Determine sort order based on the value of the Tag
79 Ascending := Column.Tag = 1;
80 // Perform the sort
81 TListView(Sender).CustomSort(@SortByColumn, Column.Index);
82 end;
Copyright (c) 2001 Ernesto De Spiritomailto:edspirito@latiumsoftware.com
Visit: http://www.latiumsoftware.com/delphi-newsletter.php
|