Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
How to sort TListView columns by date or time Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
31-Oct-02
Category
VCL-General
Language
Delphi 2.x
Views
115
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Tomas Rutkauskas

Is there any way to sort columns in a TListView by date or time when a user clicks 
on the header of the column?

Answer:

Solve 1:

LV1 is a TListView with vsReport.
1   
2   function CustomDateSortProc(Item1, Item2: TListItem; ParamSort: integer): integer;
3     stdcall;
4   begin
5     result := 0;
6     if StrToDateTime(item1.SubItems[0]) > StrToDateTime(item2.SubItems[0]) then
7       Result := 1
8     else if StrToDateTime(item1.SubItems[0]) < StrToDateTime(item2.SubItems[0]) then
9       Result := -1;
10  end;
11  
12  function CustomNameSortProc(Item1, Item2: TListItem; ParamSort: integer): integer;
13    stdcall;
14  begin
15    Result := CompareText(Item1.Caption, Item2.Caption);
16  end;
17  
18  procedure TForm1.GetFilesClick(Sender: TObject);
19  var
20    sr: TSearchRec;
21    Item: TListItem;
22  begin
23    if FindFirst('e:\*.*', faAnyFile, sr) = 0 then
24      repeat
25        if (sr.Attr and faDirectory) <> sr.Attr then
26        begin
27          item := LV1.items.add;
28          item.Caption := sr.name;
29          Item.SubItems.Add(DateTimeToStr(filedatetodatetime(sr.time)));
30        end;
31      until
32        FindNext(sr) <> 0;
33    FindClose(sr);
34  end;
35  
36  procedure TForm1.LV1ColumnClick(Sender: TObject; Column: TListColumn);
37  begin
38    if column = LV1.columns[0] then
39      LV1.CustomSort(@CustomNameSortProc, 0)
40    else
41      LV1.CustomSort(@CustomDateSortProc, 0)
42  end;



Solve 2:

Open a new Delphi application project. Drop a listview (ListView1) onto the default 
form. Paste in the attached code. Hook up the FormCreate and ListView1ColumnClick 
event handlers.

The custom sort procedure (and the callback) save the day. There are some limits 
and drawbacks to this approach though. Since the listview is inherently unaware of 
data types, you have to bolt that onto the outside. This extra thrashing can 
represent a performance hit if you're doing something funky in the callback. This 
example uses up the TListView.Tag, TListColumn.Tag and TListItem.Data properties. 
This might clash with a scheme in place, or may sicken you because of its 
bold-faced greed. This system only allows for single-column sorts. This can easily 
be extended, though, by a reinterpretation of TListView.Tag into sort column_s_. No 
graphics in the column headers.

43  unit Unit1;
44  
45  interface
46  
47  uses
48    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
49  ComCtrls;
50  
51  type
52    TForm1 = class(TForm)
53      ListView1: TListView;
54      procedure FormCreate(Sender: TObject);
55      procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
56    private
57    public
58    end;
59  
60  var
61    Form1: TForm1;
62  
63  implementation
64  
65  {$R *.DFM}
66  
67  function UnformatText(const Text: string; const VarType: Integer): Variant;
68  begin
69    {This is an ambitious function, in simple form. The standard text to type 
70  	variable conversion is fairly weak, so this function is a good place to
71  	canonize that thinking.}
72    if Length(Text) = 0 then
73      Result := Null
74    else
75    begin
76      case VarType of
77        varBoolean:
78          if CompareText(Text, 'True') = 0 then
79            Result := True
80          else if CompareText(Text, 'False') = 0 then
81            Result := False
82          else if CompareText(Text, 'Yes') = 0 then
83            Result := True
84          else if CompareText(Text, 'No') = 0 then
85            Result := False
86          else
87          begin
88            Result := Null;
89          end;
90      else
91        {use the default handler}
92        Result := VarAsType(Text, VarType);
93      end;
94    end;
95  end;
96  
97  function LVItemValue(const Item: TListItem; const Col, VarType: Integer): Variant;
98  begin
99    {get the indicated "cell's" text, return an empty string if either index is out 
100 of range}
101   if Item = nil then
102     Result := Null
103   else if Col < 0 then
104     Result := Null
105   else if Col > Item.SubItems.Count then
106     Result := Null
107   else if Col = 0 then
108     Result := UnformatText(Item.Caption, VarType)
109   else
110   begin
111     Result := UnformatText(Item.SubItems[Col - 1], VarType);
112   end;
113 end;
114 
115 function LVSort(lParam1, lParam2: Integer; lParamSort: Integer): Integer; stdcall;
116 const
117   NULL_COMPARE = -1; {-1 floats nulls to top, +1, to bottom}
118 var
119   oLV: TListView;
120   iSortCol: Integer;
121   bSortAsc: Boolean;
122   iSortVarType: Integer;
123   vData1: Variant;
124   vData2: Variant;
125 begin
126   try
127     {resolve the reference to the listview being sorted}
128     oLV := TListView(lParamSort);
129     {is "no sort" being requested?}
130     if oLV.Tag = 0 then
131     begin
132       {not a very economic use of the data property...}
133       Result := Integer(TListItem(lParam1).Data) - Integer(TListItem(lParam2).Data);
134       exit;
135     end;
136     iSortCol := Abs(oLV.Tag) - 1;
137     bSortAsc := oLV.Tag >= 0;
138     {determine the data type}
139     if iSortCol < 0 then
140       iSortVarType := varString
141     else if iSortCol >= oLV.Columns.Count then
142       iSortVarType := varString
143     else
144     begin
145       iSortVarType := oLV.Columns[iSortCol].Tag;
146     end;
147     {get the data of interest}
148     vData1 := LVItemValue(TListItem(lParam1), iSortCol, iSortVarType);
149     vData2 := LVItemValue(TListItem(lParam2), iSortCol, iSortVarType);
150     {do some "null" handling that supercedes typed comparisons}
151     if VarIsNull(vData1) and VarIsNull(vData2) then
152       Result := 0 {they're both null}
153     else if VarIsNull(vData1) then
154       Result := NULL_COMPARE
155     else if VarIsNull(vData2) then
156       Result := -NULL_COMPARE
157     else if vData1 > vData2 then
158       Result := 1
159     else if vData1 < vData2 then
160       Result := -1
161     else
162     begin
163       Result := 0;
164     end;
165     if not bSortAsc then
166       Result := -Result;
167   except
168     Result := 0;
169   end;
170 end;
171 
172 procedure TForm1.FormCreate(Sender: TObject);
173 
174   function RandomNull(const Text: string): string;
175   begin
176     if Random(8) < 1 then
177       Result := ''
178     else
179     begin
180       Result := Text;
181     end;
182   end;
183 
184 var
185   oCol: TListColumn;
186   oItem: TListItem;
187   iItem: Integer;
188 begin
189   Randomize;
190   {set listview properties}
191   with ListView1 do
192   begin
193     Items.Clear;
194     Columns.Clear;
195     Align := alClient;
196     ReadOnly := True;
197     SortType := stNone;
198     Tag := 0;
199     ViewStyle := vsReport;
200   end;
201   {default columns of different types}
202   oCol := ListView1.Columns.Add;
203   oCol.Caption := 'varDate';
204   oCol.Tag := varDate;
205   oCol.Width := 100;
206   oCol := ListView1.Columns.Add;
207   oCol.Caption := 'varBoolean';
208   oCol.Tag := varBoolean;
209   oCol.Width := 100;
210   oCol := ListView1.Columns.Add;
211   oCol.Caption := 'varInteger';
212   oCol.Tag := varInteger;
213   oCol.Width := 100;
214   oCol := ListView1.Columns.Add;
215   oCol.Caption := 'varCurrency';
216   oCol.Tag := varCurrency;
217   oCol.Width := 100;
218   oCol := ListView1.Columns.Add;
219   oCol.Caption := 'varString';
220   oCol.Tag := varString;
221   oCol.Width := 100;
222   {add items to the listview}
223   for iItem := 0 to 100 + Random(100) do
224   begin
225     {data property stores "original index" info}
226     oItem := ListView1.Items.Add;
227     oItem.Data := Pointer(iItem); {using this more like a Tag property}
228     {plug in some fake data}
229     oItem.Caption := RandomNull(FormatDateTime('dd-mmm-yyyy', Now() - 
230 Random(1000)));
231     if Random(2) < 1 then
232       oItem.SubItems.Add(RandomNull('Yes'))
233     else
234     begin
235       oItem.SubItems.Add(RandomNull('No'));
236     end;
237     oItem.SubItems.Add(RandomNull(FloatToStr(0.01 * Random(100000))));
238     oItem.SubItems.Add(RandomNull(IntToStr(Random(10000))));
239     oItem.SubItems.Add(RandomNull(Char(65 + Random(26)) + Char(65 + Random(26)) +
240       Char(65 + Random(26)) + Char(65 + Random(26)) + Char(65 + Random(26))));
241   end;
242 end;
243 
244 procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
245 begin
246   {sort the sort column and order into the listview's tag}
247   if ListView1.Tag = Column.Index + 1 then
248     ListView1.Tag := -ListView1.Tag {desc sort}
249   else if ListView1.Tag = -(Column.Index + 1) then
250     ListView1.Tag := 0 {no sort}
251   else
252   begin
253     ListView1.Tag := Column.Index + 1; {asc sort}
254   end;
255   {pass the listview such that it will be sent to the sort procedure}
256   ListView1.CustomSort(LVSort, Integer(ListView1));
257 end;
258 
259 end.


			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC