Board index » delphi » TListView Columns Sorted ?

TListView Columns Sorted ?

Hi All,

is there anyone who can explain me how to sort a listview-column ?
I can't understand how "alphasort", "sorttype" and "oncompare" work together.  
Is it possible to click on column 2 but sort by column 5 ?

thank you for your help

greetings detlef

 

Re:TListView Columns Sorted ?


Quote
"Detlef Giller" wrote...
> is there anyone who can explain me how to sort a listview-column ?
> I can't understand how "alphasort", "sorttype" and "oncompare" work
> together. Is it possible to click on column 2 but sort by column 5 ?

To get the column which is clicked you can use OnColumnClick.
(The column clicked on is stored in private Form variable FSortColumn)

procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
  FSortColumn := Column.Index;
  with Sender as TListView do
    AlphaSort;  // This will trigger the listview sort and therefore
OnCompare.
end;

When you need to sort any other columns but the first you'll have
to write an OnCompare event handler. This one gets triggered for
instance by calling AlphaSort (see above code snippet).

In the OnCompare you can use the previously stored FSortColomn to
determine which column needs to be sorted. If it is the first column
you can just compare Captions of ListView items. If it is the second
column or higher you need to compare the SubItems.

procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
begin
  case FSortColumn of
    0: Compare := CompareText(Item1.Caption, Item2.Caption);
  else Compare := CompareText(Item1.SubItems[FSortColumn-1],
                              Item2.SubItems[FSortColumn-1]);
  end;
end;

Above code shows you how to sort the column which is
clicked. With a small modification in the OnColumnClick()
you can change the column which gets sorted to any other column.

procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
  case Column.Index of
    2: FSortColumn := 5;
  else
    FSortColumn := Column.Index;
  end;
  with Sender as TListView do
    AlphaSort;
end;

If the data from the listview is added at design time you might want to call
   ListView1ColumnClick(ListView1, ListView1.Columns[0]);
from the FormCreate for instance to make sure the listview is sorted when
it is first shown.

Since sorting is triggered by code you can leave SortType at stNone in
above sample code. By doing this and when you add data from code
you'll have to call AlphaSort yourself to get the new added data sorted
again.

A short thing about SortType when it is set at anything else then stNone
AlphaSort is called 'automaticly' when a new item with a caption
[stBoth or stText] is added or with Data [stBoth or stData] is added.
If you add a new item with both a Caption and Data and SortType
is set to stBoth, AlphaSort gets called twice!

--
Pieter

Re:TListView Columns Sorted ?


Hello Pieter,

many thanks for your exact description it was very helpfull for me. Please, I have any questions on this, can you answer one more
time ?

-1-
I wish to sort ascending with the first click, with the next click descending and so on. This is will be possible with
**ascend**
compare := comparetext(item1.subitems[sortcol -1], item2.subitems[sortcol -1]);

**descend**
compare := comparetext(item1.subitems[sortcol -1], item2.subitems[sortcol -1]);
compare:= compare * (-1);

but for it I must save for every column the last sortorder (ascend=1 or descend=-1). In my opinion it is awkward. Is there a better
way ?

-2-
SortType := stBoth/stText/stNone/stData
What is the difference between item caption and item data ?

lvStatis01.Items.Add;
lvStatis01.Items.item[nI].caption := IntToStr(nI + 1);   <-- Is this the caption-column ?
lvStatis01.Items.item[nI].subitems.add(sKey);           <-- Is this the data-column ?

Thank's for your answers

Detlef

Re:TListView Columns Sorted ?


Quote
"Detlef Giller" wrote...
> -1-
> I wish to sort ascending with the first click, with the next click
descending
> and so on. This is will be possible with
> **ascend**
> compare := comparetext(item1.subitems[sortcol -1],

item2.subitems[sortcol -1]);
Quote

> **descend**
> compare := comparetext(item1.subitems[sortcol -1],

item2.subitems[sortcol -1]);

Quote
> compare:= compare * (-1);

> but for it I must save for every column the last sortorder (ascend=1 or
> descend=-1). In my opinion it is awkward. Is there a better way ?

'Normally' I don't save the sort order but default to ascending when
the user switches from one column to another. But...

You could store the last sorting order in the Column.Tag property
from within the OnColumnClick handler...

procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
  if Column.Tag = 0 then
    Column.Tag := +1 // first time, default to ascending
  else
    if FSortColumn = Column.Index then // clicked same column, toggle sort
dir.
      if Column.Tag > 0 then
        Column.Tag := -1
      else
        Column.Tag := +1;
  FSortOrder := Column.Tag;
  FSortColumn := Column.Index;
end;

procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
begin
  case FSortColumn of
    0: Compare := CompareText(Item1.Caption, Item2.Caption);
  else Compare := CompareText(Item1.SubItems[FSortColumn-1],
                              Item2.SubItems[FSortColumn-1]);
  end;
  Compare := FSortOrder * Compare;
end;

Quote
> -2-
> SortType := stBoth/stText/stNone/stData
> What is the difference between item caption and item data ?

The first holds the Caption as displayed in the first column and
Data is an extra property of a ListItem, which is just a pointer.
You could use that to store user data, for example an Object
or Record, which belogs to that TListItem

Quote

> lvStatis01.Items.Add;
> lvStatis01.Items.item[nI].caption := IntToStr(nI + 1); <-- Is this the

caption-column ?

Yes

Quote
> lvStatis01.Items.item[nI].subitems.add(sKey); <-- Is this the data-column

?

No, Data is a separate property of TListItem.

Although you can set SortType to stData you still have to provide
an OnCompare event handler and examine the Data property
yourself (normally the 'thing' Data is pointing at).

SubItems is a simple stringlist with some extras which holds the
strings for the other columns.  SubItems are not included in the
standard sorting functions of the TListView (you'll have to do
that yourself in an OnCompare like you do now).

Up to your next question <g>
How to get the little arrows in the header to indicate the sorting order?

I recently needed something similar for myself and wrote a
little component for it. You can download it from here...

  http://home.hccnet.nl/p.zylstra/downloads/ListViewEx.zip

--
Pieter

Re:TListView Columns Sorted ?


Quote
"Detlef Giller" <gill...@gmx.de> wrote:
>I wish to sort ascending with the first click, with the next click descending and so on.

FWIW, if there's no reason this has to be a VCL project, this
is default behavior built into the CLX ListView.  Just set the
properties Sorted and ShowColumnSortIndicators to "True," and
no coding is needed.

Rick Carter
Rick.Car...@cincww.rcc.org
Chair, Paradox/Delphi SIG, Cincinnati PC Users Group

Other Threads