Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
Solved

# Sorting a Virtual Listview

Posted on 2007-11-20
Medium Priority
2,057 Views
Hi,
I asked a question sometime ago (http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_21718319.html?sfQueryTermInfo=1+listview+virtual) and would liek some addtional help.

In the solution given in the link above - I am left with MyList. This virtual list is displayed in a listview. Can somebody show me how to sort this now when I click on one of the three column headers.

I would appreciate some working code if possible.
0
Question by:Romans
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• 3
• 3

LVL 14

Expert Comment

ID: 20323762
You need to sort your list and then redisplay the contents.
This code fragment is not complete but has the principal parts.
Let me know if you need more detail.

Steve
``````function SortWord(Item1,Item2 : pointer) : integer;
begin
result := CompareText( TOccurrence(Item1).TheWord, TOccurrence(Item2).TheWord);
end;

function SortCount(Item1,Item2 : pointer) : integer;
begin
result := TOccurrence(Item2).Count - TOccurrence(Item1).Count;
end;

function SortFirstPos(Item1,Item2 : pointer) : integer;
begin
result := TOccurrence(Item2).FirstPos - TOccurrence(Item1).FirstPos;
end;

procedure TForm1.ListView1ColumnClick(Sender: TObject;    Column: TListColumn);
begin
if Column.Index = 0 then
MyList.Sort(SortWord)
else if Column.Index = 1 then
MyList.Sort(SortCount)
else if Column.Index = 2 then
MyList.Sort( SortFirstPos);

// Refresh ListView Display.
end;
``````
0

LVL 14

Accepted Solution

SteveBay earned 2000 total points
ID: 20323897
Here is the complete working Unit. I made a minor mistake in the number sort routines.
It sould be Item1 - Item2 not Item2 - Item1

Steve
``````unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, Contnrs;
type
TOccurrence = class
TheWord: string;
Count: integer;
FirstPos: integer;
end;

type
TForm1 = class(TForm)
ListView1: TListView;
procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
procedure FormShow(Sender: TObject);
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
MyList : TObjectList;

{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{\$R *.dfm}
function SortWord(Item1,Item2 : pointer) : integer;
begin
result := CompareText( TOccurrence(Item1).TheWord, TOccurrence(Item2).TheWord);
end;

function SortCount(Item1,Item2 : pointer) : integer;
begin
result := TOccurrence(Item1).Count - TOccurrence(Item2).Count;
end;

function SortFirstPos(Item1,Item2 : pointer) : integer;
begin
result := TOccurrence(Item1).FirstPos - TOccurrence(Item2).FirstPos;
end;

procedure TForm1.ListView1ColumnClick(Sender: TObject;    Column: TListColumn);
begin
if Column.Index = 0 then
MyList.Sort(SortWord)
else if Column.Index = 1 then
MyList.Sort(SortCount)
else if Column.Index = 2 then
MyList.Sort( SortFirstPos);

ListView1.Refresh;
end;

procedure TForm1.FormShow(Sender: TObject);
var oc  : TOccurrence;
begin
MyList := TObjectList.Create;

oc := TOccurrence.Create;
oc.TheWord := 'The';
oc.Count := 2;
oc.FirstPos := 0;

oc := TOccurrence.Create;
oc.TheWord := 'brown';
oc.Count := 2;
oc.FirstPos := 4;

oc := TOccurrence.Create;
oc.TheWord := 'dog';
oc.Count := 1;
oc.FirstPos := 10;

oc := TOccurrence.Create;
oc.TheWord := 'jumped';
oc.Count := 1;
oc.FirstPos := 14;

oc := TOccurrence.Create;
oc.TheWord := 'over';
oc.Count := 1;
oc.FirstPos := 21;

oc := TOccurrence.Create;
oc.TheWord := 'fence';
oc.Count := 1;
oc.FirstPos := 36;
ListView1.Items.Count := MyList.Count;
end;

procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := TOccurrence(MyList[Item.Index]).TheWord;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MyList.Free
end;

end.
``````
0

Author Comment

ID: 20326963
Thanks for the help - really appreciated. I added the ability to sort ascending and decending. Here is what I ended up with...

If you know how to get the little up/down arrows to appear on the top of the column headers when sorted let me know.

Thanks
Romans
``````unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, Contnrs;

type
TOccurrence = class
TheWord: string;
Count: integer;
FirstPos: integer;
end;

type
TForm1 = class(TForm)
ListView1: TListView;
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
private
MyList : TObjectList;

{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
LvSortOrder: array[0..4] of Boolean; // High[LvSortOrder] = Number of Lv Columns
SortColumn : Integer;

implementation

{\$R *.dfm}

function SortWord(Item1,Item2 : pointer) : integer;
begin
result := CompareText( TOccurrence(Item1).TheWord, TOccurrence(Item2).TheWord);

if LvSortOrder[SortColumn] then
Result := - Result;
end;

function SortCount(Item1,Item2 : pointer) : integer;
begin
result := TOccurrence(Item1).Count - TOccurrence(Item2).Count;

if LvSortOrder[SortColumn] then
Result := - Result;

end;

function SortFirstPos(Item1,Item2 : pointer) : integer;
begin
result := TOccurrence(Item1).FirstPos - TOccurrence(Item2).FirstPos;

if LvSortOrder[SortColumn] then
Result := - Result;
end;

procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := TOccurrence(MyList[Item.Index]).TheWord;
end;

procedure TForm1.FormShow(Sender: TObject);
var oc  : TOccurrence;
begin
MyList := TObjectList.Create;

oc := TOccurrence.Create;
oc.TheWord := 'The';
oc.Count := 2;
oc.FirstPos := 0;

oc := TOccurrence.Create;
oc.TheWord := 'brown';
oc.Count := 2;
oc.FirstPos := 4;

oc := TOccurrence.Create;
oc.TheWord := 'dog';
oc.Count := 1;
oc.FirstPos := 10;

oc := TOccurrence.Create;
oc.TheWord := 'jumped';
oc.Count := 1;
oc.FirstPos := 14;

oc := TOccurrence.Create;
oc.TheWord := 'over';
oc.Count := 1;
oc.FirstPos := 21;

oc := TOccurrence.Create;
oc.TheWord := 'fence';
oc.Count := 1;
oc.FirstPos := 36;
ListView1.Items.Count := MyList.Count;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MyList.Free;
end;

procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
SortColumn := Column.Index;

if Column.Index = 0 then
MyList.Sort(SortWord)
else if Column.Index = 1 then
MyList.Sort(SortCount)
else if Column.Index = 2 then
MyList.Sort(SortFirstPos);

ListView1.Refresh;

LvSortOrder[Column.Index] := not LvSortOrder[Column.Index];

end;

end.
``````
0

Author Closing Comment

ID: 31410212
Thanks!!
0

LVL 14

Expert Comment

ID: 20328494
Put an imagelist on your form. Add two small images, an up arrow and a down arrow. Then put this code in your ListView1ColumnClick event

for i := 0 to ListView1.Columns.Count - 1 do
ListView1.Columns[i].ImageIndex := -1;
if LvSortOrder[Column.Index] then
Column.ImageIndex := 0
else
Column.ImageIndex := 1;

0

Author Comment

ID: 20328510
Thanks Steve - Great help to me and I really appreciate it!
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…