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.
procedure(Sender: TObject; Item1, Item2: TListItem;
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:
procedure TForm1.ListView1Compare(Sender: TObject; Item1,
Item2: TListItem; Data: Integer; var Compare: Integer);
var
n1, n2: integer;
begin
n1 := StrToInt(Item1.SubItems[2]);
n2 := StrToInt(Item2.SubItems[2]);
if n1 > n2 then
Compare := -1
else if n1 < n2 then
Compare := 1
else
Compare := 0;
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:
ListView1.SortType := stBoth;
ListView1.SortType := stNone;
or else:
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:
function ByFourth(Item1, Item2: TListItem; Data: integer):
integer; stdcall;
var
n1, n2: cardinal;
begin
n1 := StrToInt(Item1.SubItems[2]);
n2 := StrToInt(Item2.SubItems[2]);
if n1 > n2 then
Result := -1
else if n1 < n2 then
Result := 1
else
Result := 0;
end;
Then, every time you want to sort the list, you call CustomSort
passing the address of the ordering function. For example:
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).