?
Solved

Sorting a Virtual Listview

Posted on 2007-11-20
6
Medium Priority
?
2,036 Views
Last Modified: 2012-08-13
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
Comment
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
  • Learn & ask questions
  • 3
  • 3
6 Comments
 
LVL 14

Expert Comment

by:SteveBay
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;

Open in new window

0
 
LVL 14

Accepted Solution

by:
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;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'brown';
	oc.Count := 2;
	oc.FirstPos := 4;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'dog';
	oc.Count := 1;
	oc.FirstPos := 10;
	MyList.Add(oc);
 
 
	oc := TOccurrence.Create;
	oc.TheWord := 'jumped';
	oc.Count := 1;
	oc.FirstPos := 14;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'over';
	oc.Count := 1;
	oc.FirstPos := 21;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'fence';
	oc.Count := 1;
	oc.FirstPos := 36;
	MyList.Add(oc);
	ListView1.Items.Count := MyList.Count;
end;
 
procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
	Item.Caption := TOccurrence(MyList[Item.Index]).TheWord;
	Item.SubItems.Add(IntToStr(TOccurrence(MyList[Item.Index]).Count));
	Item.SubItems.Add(IntToStr(TOccurrence(MyList[Item.Index]).FirstPos));
end;
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
	MyList.Free
end;
 
end.

Open in new window

0
 

Author Comment

by:Romans
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;
	Item.SubItems.Add(IntToStr(TOccurrence(MyList[Item.Index]).Count));
	Item.SubItems.Add(IntToStr(TOccurrence(MyList[Item.Index]).FirstPos));
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;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'brown';
	oc.Count := 2;
	oc.FirstPos := 4;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'dog';
	oc.Count := 1;
	oc.FirstPos := 10;
	MyList.Add(oc);
 
 
	oc := TOccurrence.Create;
	oc.TheWord := 'jumped';
	oc.Count := 1;
	oc.FirstPos := 14;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'over';
	oc.Count := 1;
	oc.FirstPos := 21;
	MyList.Add(oc);
 
	oc := TOccurrence.Create;
	oc.TheWord := 'fence';
	oc.Count := 1;
	oc.FirstPos := 36;
	MyList.Add(oc);
	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.

Open in new window

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 

Author Closing Comment

by:Romans
ID: 31410212
Thanks!!
0
 
LVL 14

Expert Comment

by:SteveBay
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

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

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…
Suggested Courses
Course of the Month13 days, 4 hours left to enroll

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question