I recently got help for sorting a TListView's columns based on columns data type.
Here is the code:
procedure TfrmFind.lvwTagsColumnClick(Sender: TObject; Column: TListColumn);
begin
ColumnToSort := Column.Index;
(Sender as TCustomListView).AlphaSort;
end;
procedure TfrmFind.lvwTagsCompare(Sender: TObject; Item1, Item2: TListItem;
Data: Integer; var Compare: Integer);
var
ix: Integer;
begin
if ColumnToSort = 0 then
Compare := CompareText(Item1.Caption,Item2.Caption)
else
if ColumnToSort = 1 then
Compare := CompareTextAsInteger(Item1.subitems[0],Item2.subitems[0])
else
if ColumnToSort = 2 then
Compare := CompareTextAsDateTime(Item1.subitems[1],Item2.subitems[1])
else
begin
ix := ColumnToSort - 1;
Compare := CompareText(Item1.SubItems[ix],Item2.SubItems[ix]);
end;
end;
I would like to add the capability to sort ascending and descending if it is possible?
User clicks once to sort ascending, then a second time to sort descending
Can I do this from the code I currently have?
What about adding a glyph to the left column to show the type of sort (ascending vs descending)?
******************************************************************************
Modifications based on experts answers: 03/25/2013
procedure TfrmFind.lvwTagsColumnClick(Sender: TObject; Column: TListColumn);
begin
ColumnToSort := Column.Index;
Column.Tag:= Column.Tag * -1;
if Column.Tag = 0 then Column.Tag:=1;
(Sender as TCustomListView).AlphaSort;
end;
procedure TfrmFind.lvwTagsCompare(Sender: TObject; Item1, Item2: TListItem;
Data: Integer; var Compare: Integer);
begin
Case ColumnToSort of
0: Compare := TRzListView(Sender).Tag * CompareText(Item1.Caption, Item2.Caption);
1: Compare := TRzListView(Sender).Tag * CompareTextAsInteger(Item1.subitems[0],Item2.subitems[0]);
2: Compare := TRzListView(Sender).Tag * CompareTextAsDateTime(Item1.subitems[1],Item2.subitems[1]);
else
Compare := TRzListView(Sender).Tag * CompareText(Item1.Caption, Item2.Caption);
End;
end;
Best Answer
What you are attempting to do is now rather complex. To be able to keep on top of this I would recommend that you build a well-factored set of low-level helper routines. Then you can compose the high-level UI code in short, clear methods.
To start with, lets have some routines that get and set list header sort state. That's the up/down sort icon in the list view's header control.
I took this code from this answer: How to show the sort arrow on a TListView column?
Next up I would make a record to hold the sort specification. Ideally this would arrive at the sort compare function in its
Data
parameter. But sadly the VCL framework missed the opportunity to use that parameter for its intended purpose. So instead we will need to store the specification for the active sort in the form that owns the list view.And then in the form itself you'll declare a field to hold one of these:
The compare function uses the specification. It's very simple:
Next up we'll implement a sort function.
This
Sort
function is decoupled from theOnClick
handler. That will allow you to sort columns independently from the user's UI actions. For example, perhaps you want to sort the control on a particular column when you first show the form.Finally, the
OnClick
handler can then call the sort function:For the sake of completeness, here is a complete unit that implements these ideas: