source: ListViewSort/UListViewSort.pas

Last change on this file was 130, checked in by george, 13 years ago
File size: 9.8 KB
Line 
1unit UListViewSort;
2
3// Date: 2010-11-03
4
5interface
6
7uses
8 Windows, Types, Classes, ComCtrls, Contnrs, Graphics, SysUtils, StdCtrls,
9 Controls, DateUtils, CommCtrl, Dialogs, SpecializedList;
10
11type
12 TSortOrder = (soNone, soUp, soDown);
13
14 TListViewSort = class;
15
16 TCompareEvent = function (Item1, Item2: TObject): Integer of object;
17 TListFilterEvent = procedure (ListViewSort: TListViewSort) of object;
18
19 TListViewSort = class
20 private
21 FListView: TListView;
22 FOnCompareItem: TCompareEvent;
23 FOnFilter: TListFilterEvent;
24 FOnCustomDraw: TLVCustomDrawItemEvent;
25 FHeaderHandle: HWND;
26 FColumn: Integer;
27 FOrder: TSortOrder;
28 procedure SetListView(const Value: TListView);
29 procedure ColumnClick(Sender: TObject; Column: TListColumn);
30 procedure Sort(Compare: TCompareEvent);
31 procedure DrawCheckMark(Item: TListItem; Checked: Boolean);
32 procedure GetCheckBias(var XBias, YBias, BiasTop, BiasLeft: Integer;
33 const ListView: TListView);
34 procedure ListViewCustomDrawItem(Sender: TCustomListView;
35 Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
36 procedure ListViewClick(Sender: TObject);
37 procedure UpdateColumns;
38 procedure SetColumn(const Value: Integer);
39 procedure SetOrder(const Value: TSortOrder);
40 public
41 List: TListObject;
42 Source: TListObject;
43 constructor Create;
44 destructor Destroy; override;
45 function CompareTime(Time1, Time2: TDateTime): Integer;
46 function CompareInteger(Value1, Value2: Integer): Integer;
47 function CompareString(Value1, Value2: string): Integer;
48 function CompareBoolean(Value1, Value2: Boolean): Integer;
49 procedure Refresh;
50 property ListView: TListView read FListView write SetListView;
51 property OnCompareItem: TCompareEvent read FOnCompareItem
52 write FOnCompareItem;
53 property OnFilter: TListFilterEvent read FOnFilter
54 write FOnFilter;
55 property OnCustomDraw: TLVCustomDrawItemEvent read FOnCustomDraw
56 write FOnCustomDraw;
57 property Column: Integer read FColumn write SetColumn;
58 property Order: TSortOrder read FOrder write SetOrder;
59 end;
60
61implementation
62
63{ TListViewSort }
64
65
66procedure TListViewSort.ColumnClick(Sender: TObject; Column: TListColumn);
67begin
68 if Column.Index = Self.Column then begin
69 if FOrder = soUp then FOrder := soDown
70 else if FOrder = soDown then FOrder := soUp
71 else FOrder := soUp;
72 end else Self.Column := Column.Index;
73 Refresh;
74 UpdateColumns;
75end;
76
77procedure TListViewSort.SetOrder(const Value: TSortOrder);
78begin
79 FOrder := Value;
80 UpdateColumns;
81end;
82
83procedure TListViewSort.SetColumn(const Value: Integer);
84begin
85 FColumn := Value;
86 UpdateColumns;
87end;
88
89procedure TListViewSort.SetListView(const Value: TListView);
90begin
91 FListView := Value;
92 FListView.OnColumnClick := ColumnClick;
93 FListView.OnCustomDrawItem := ListViewCustomDrawItem;
94 FListView.OnClick := ListViewClick;
95end;
96
97procedure TListViewSort.Sort(Compare: TCompareEvent);
98begin
99 if (List.Count > 0) then
100 List.Sort(Compare);
101end;
102
103procedure TListViewSort.Refresh;
104begin
105 if Assigned(FOnFilter) then FOnFilter(Self)
106 else if Assigned(Source) then
107 List.Assign(Source) else
108 List.Clear;
109 if ListView.Items.Count <> List.Count then
110 ListView.Items.Count := List.Count;
111 if Assigned(FOnCompareItem) then Sort(FOnCompareItem);
112 ListView.Items[-1]; // Workaround for not show first row if selected
113 ListView.Refresh;
114 // Workaround for not working item selection on first row
115 if not Assigned(ListView.Selected) then begin
116 ListView.Items.Count := 0;
117 ListView.Items.Count := List.Count;
118 end;
119 //if ListView.Items.Count > 0 then
120 // ListView.Items[0].Selected := True;
121 //ListView.Selected := nil;
122 UpdateColumns;
123end;
124
125const
126 W_64: Integer = 64; {Width of thumbnail in ICON view mode}
127 H_64: Integer = 64; {Height of thumbnail size}
128 CheckWidth: Integer = 14; {Width of check mark box}
129 CheckHeight: Integer = 14; {Height of checkmark}
130 CheckBiasTop: Integer = 2; {This aligns the checkbox to be in centered}
131 CheckBiasLeft: Integer = 3; {In the row of the list item display}
132
133function TListViewSort.CompareBoolean(Value1, Value2: Boolean): Integer;
134begin
135 if Value1 > Value2 then Result := 1
136 else if Value1 < Value2 then Result := -1
137 else Result := 0;
138end;
139
140function TListViewSort.CompareInteger(Value1, Value2: Integer): Integer;
141begin
142 if Value1 > Value2 then Result := 1
143 else if Value1 < Value2 then Result := -1
144 else Result := 0;
145end;
146
147function TListViewSort.CompareString(Value1, Value2: string): Integer;
148begin
149 Result := AnsiCompareStr(Value1, Value2);
150// if Value1 > Value2 then Result := -1
151// else if Value1 < Value2 then Result := 1
152// else Result := 0;
153end;
154
155function TListViewSort.CompareTime(Time1, Time2: TDateTime): Integer;
156begin
157 Result := DateUtils.CompareDateTime(Time1, Time2);
158end;
159
160constructor TListViewSort.Create;
161begin
162 List := TListObject.Create;
163 List.OwnsObjects := False;
164end;
165
166destructor TListViewSort.Destroy;
167begin
168 List.Free;
169 inherited;
170end;
171
172procedure TListViewSort.DrawCheckMark(Item: TListItem; Checked:
173 Boolean);
174var
175 TP1: TPoint;
176 XBias, YBias: Integer;
177 OldColor: TColor;
178 BiasTop, BiasLeft: Integer;
179 Rect1: TRect;
180 lRect: TRect;
181 ItemLeft: Integer;
182begin
183 Item.Left := 0;
184 GetCheckBias(XBias, YBias, BiasTop, BiasLeft, ListView);
185 OldColor := ListView.Canvas.Pen.Color;
186 //TP1 := Item.GetPosition;
187 lRect := Item.DisplayRect(drBounds); // Windows 7 workaround
188 TP1.X := lRect.Left;
189 TP1.Y := lRect.Top;
190 //ShowMessage(IntToStr(Item.Index) + ', ' + IntToStr(GetScrollPos(Item.ListView.Handle, SB_VERT)) + ' ' +
191 // IntToHex(Integer(Item), 8) + ', ' + IntToStr(TP1.X) + ', ' + IntToStr(TP1.Y));
192
193// if Checked then
194 ListView.Canvas.Brush.Color := clWhite;
195 ItemLeft := Item.Left;
196 ItemLeft := 23; // Windows 7 workaround
197
198 Rect1.Left := ItemLeft - CheckWidth - BiasLeft + 1 + XBias;
199 //ShowMessage(IntToStr(Tp1.Y) + ', ' + IntToStr(BiasTop) + ', ' + IntToStr(XBias));
200 Rect1.Top := Tp1.Y + BiasTop + 1 + YBias;
201 Rect1.Right := ItemLeft - BiasLeft - 1 + XBias;
202 Rect1.Bottom := Tp1.Y + BiasTop + CheckHeight - 1 + YBias;
203 //ShowMessage(IntToStr(Rect1.Left) + ', ' + IntToStr(Rect1.Top) + ', ' + IntToStr(Rect1.Right) + ', ' + IntToStr(Rect1.Bottom));
204
205 ListView.Canvas.FillRect(Rect1);
206 //if Checked then ListView.Canvas.Brush.Color := clBlack
207 ListView.Canvas.Brush.Color := clBlack;
208 ListView.Canvas.FrameRect(Rect1);
209 ListView.Canvas.FrameRect(Rect(Rect1.Left - 1, Rect1.Top - 1,
210 Rect1.Right + 1, Rect1.Bottom + 1));
211 if Checked then begin
212 ListView.Canvas.Pen.Color := clBlack;
213 ListView.Canvas.MoveTo(ItemLeft - BiasLeft - 2 + XBias - 2,
214 Tp1.Y + BiasTop + 3 + YBias);
215 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth div 2) + XBias,
216 Tp1.Y + BiasTop + (CheckHeight - 4) + YBias);
217 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth - 3) + XBias,
218 Tp1.Y + BiasTop + (CheckHeight div 2) + YBias - 1);
219
220 ListView.Canvas.MoveTo(ItemLeft - BiasLeft - 2 - 1 + XBias - 2,
221 Tp1.Y + BiasTop + 3 + YBias);
222 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth div 2) - 1 + XBias,
223 Tp1.Y + BiasTop + (CheckHeight - 4) + YBias);
224 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth - 3) - 1 + XBias,
225 Tp1.Y + BiasTop + (CheckHeight div 2) + YBias - 1);
226 end;
227 //ListView.Canvas.Brush.Color := ListView.Color;
228 ListView.Canvas.Brush.Color := clWindow;
229 ListView.Canvas.Pen.Color := OldColor;
230end;
231
232procedure TListViewSort.GetCheckBias(var XBias, YBias, BiasTop, BiasLeft: Integer;
233 const ListView: TListView);
234begin
235 XBias := 0;
236 YBias := 0;
237 if ListView.ViewStyle = vsICON then
238 begin
239 YBias := H_64 - CheckHeight;
240 XBias := 0;
241 end;
242 BiasTop := CheckBiasTop;
243 BiasLeft := CheckBiasLeft;
244 if ListView.ViewStyle <> vsReport then
245 begin
246 BiasTop := 0;
247 BiasLeft := 0;
248 end;
249end;
250
251procedure TListViewSort.ListViewCustomDrawItem(Sender: TCustomListView;
252 Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
253begin
254 if Assigned(Item) then begin
255 if ListView.Checkboxes then
256 DrawCheckMark(Item, Item.Checked);
257 if Assigned(FOnCustomDraw) then
258 FOnCustomDraw(Sender, Item, State, DefaultDraw);
259 end;
260end;
261
262procedure TListViewSort.ListViewClick(Sender: TObject);
263var
264 Item: TListItem;
265 Pos: TPoint;
266 DefaultDraw: Boolean;
267begin
268 Pos := ListView.ScreenToClient(Mouse.CursorPos);
269 Item := ListView.GetItemAt(Pos.X, Pos.Y);
270 //ShowMessage(IntToStr(Item.Index) + ', ' + IntToStr(Pos.X) + ', ' + IntToStr(Pos.Y));
271 if Assigned(Item) and (Pos.X < 20) then begin
272
273 Item.Checked := not Item.Checked;
274 //ShowMessage(IntToStr(Item.Index) + ', ' +BoolToStr(Item.Checked));
275 if Assigned(ListView.OnChange) then
276 ListView.OnChange(Self, Item, ctState);
277 DefaultDraw := False;
278 ListViewCustomDrawItem(ListView, Item, [], DefaultDraw);
279 //ListView.UpdateItems(Item.Index, Item.Index);
280 end;
281end;
282
283procedure TListViewSort.UpdateColumns;
284const
285 HDF_SORTUP = $0400;
286 HDF_SORTDOWN = $0200;
287 SortOrder: array[TSortOrder] of Word = (0, HDF_SORTUP, HDF_SORTDOWN);
288var
289 Item: THDItem;
290 I: Integer;
291begin
292 if Assigned(FListView) then begin
293 FHeaderHandle := ListView_GetHeader(FListView.Handle);
294 for I := 0 to FListView.Columns.Count - 1 do begin
295 FillChar(Item, SizeOf(THDItem), 0);
296 Item.Mask := HDI_FORMAT;
297 Header_GetItem(FHeaderHandle, I, Item);
298 Item.fmt := Item.fmt and not (HDF_SORTDOWN or HDF_SORTUP);
299 if (Column <> -1) and (I = Column) then
300 Item.fmt := Item.fmt or SortOrder[FOrder];
301 Header_SetItem(FHeaderHandle, I, Item);
302 end;
303 end;
304end;
305
306
307end.
Note: See TracBrowser for help on using the repository browser.