TListView 排序箭头在调整列大小时消失
TListView Sort Arrows are disappearing on column resize
我正在研究 Delphi 10.2 东京。
在 SortArrow On ListView 的帮助下,我能够为我的列表视图组件添加排序箭头(在 colclick 上添加排序箭头逻辑),当我调整列大小时,排序箭头消失了。
如何在调整列大小时保持排序箭头(类似于 Windows Explorer)?
下面是我的组件代码:
unit uMyListView1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, Menus, DB, ExtCtrls, Buttons, ADODB,Commctrl;
const ARROW_SIZE = 10;
type
TMyListView = class(TListView)
private
FDataSet: TCustomADODataSet;
FPressedColumn: integer; //column index
FLastPressedColumn: integer; //last column to be pressed
FSortDir: integer; //-1 = desc, 1 = asc
FSortOrder: integer;
procedure SetListViewColumns;
protected
procedure ColClick(Column: TListColumn); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function BuildListView: boolean;
published
property DataSet: TCustomADODataSet read FDataSet write FDataSet;
end;
implementation
procedure TMyListView.ColClick(Column: TListColumn);
var DC: HDC;
Pos: TPoint;
Header: HWND;
Item: THDItem;
begin
inherited;
FLastPressedColumn := -1;
FPressedColumn := Column.Index;
FSortDir := 1;
//implement sorting
Header := ListView_GetHeader(Self.Handle);
ZeroMemory(@Item, SizeOf(Item));
Item.Mask := HDI_FORMAT;
//remove arrow old cloumn
if FLastPressedColumn <> -1 then
begin
Header_GetItem(Header, FLastPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
Header_SetItem(Header, FLastPressedColumn, Item);
end;
Header_GetItem(Header, Column.Index, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
if (FSortDir = 1) then
Item.fmt := Item.fmt or HDF_SORTUP//include the sort ascending flag
else if (FSortDir = -1) then
Item.fmt := Item.fmt or HDF_SORTDOWN;
Header_SetItem(Header, Column.Index, Item);
end;
constructor TMYListView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FPressedColumn := -1;
FLastPressedColumn := -1;
FSortOrder := 0;
end;
destructor TMYListView.Destroy;
begin
inherited Destroy;
end;
procedure TMYListView.SetListViewColumns;
var
NewColumn: TListColumn;
i: integer;
begin
if FDataSet <> nil then with FDataSet, Self.Columns do
begin
Clear; //clears any columns
for i := 0 to FieldCount - 1 do
if Fields[i].Visible then
begin
NewColumn := Add;
NewColumn.Caption := Fields[i].DisplayLabel;
NewColumn.Width := Fields[i].DisplayWidth * 10;
NewColumn.Alignment := Fields[i].Alignment;
end;
end;
end;
function TMYListView.BuildListView: boolean;
var NewListItem: TListItem;
i: integer;
begin
Result := FALSE;
FPressedColumn := -1;
FLastPressedColumn := -1;
Items.Clear;
if FDataSet = NIL then
begin
MessageDlg('The Dataset is NIL', mtError, [mbOK], 0);
Exit;
end;
try
FDataset.Open;
SetListViewColumns;
with FDataSet do
Begin
Items.BeginUpdate;
if not EOF then while not EOF do
begin
NewListItem := Items.Add;
for i := 0 to FieldCount - 1 do
begin
if Fields[i].Visible then
begin
if i = 0 then NewListItem.Caption := Fields[0].DisplayText
else if Fields[i].Visible then NewListItem.SubItems.Add(Fields[i].DisplayText);
end;
end;
Next;
Application.ProcessMessages;
end;
end;
Result := TRUE;
finally
FDataSet.Close;
Items.EndUpdate;
end;
end;
end.
不确定为什么你的箭头会消失。更糟糕的情况是,您可能需要让 ListView 处理来自 Header 的 HDN_TRACK
/HDN_ENDTRACK
通知以重置当前箭头(如果有)。
但是,您的代码中还有一些其他问题与您管理箭头的方式有关。
您的 ColClick()
方法正在将 FLastPressedColumn
重置为 -1 ,然后 使用它来清除现有箭头:
begin
inherited;
//FLastPressedColumn := -1; // <-- REMOVE THIS!
...
//remove arrow old cloumn
if FLastPressedColumn <> -1 then
begin
...
FLastPressedColumn := -1; // <-- MOVED DOWN HERE INSTEAD!
end;
...
end;
事实上,您根本不需要 FLastPressedColumn
,FPressedColumn
本身就足够了:
procedure TMyListView.ColClick(Column: TListColumn);
var
LNewColumn: Integer;
Item: THDItem;
begin
inherited;
if Column <> nil then
LNewColumn := Column.Index
else
LNewColumn := -1;
if FPressedColumn <> LNewColumn then
begin
FSortDir := 1;
//implement sorting
Header := ListView_GetHeader(Self.Handle);
ZeroMemory(@Item, SizeOf(Item));
Item.Mask := HDI_FORMAT;
//remove arrow old cloumn
if FPressedColumn <> -1 then
begin
Header_GetItem(Header, FPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
Header_SetItem(Header, FPressedColumn, Item);
end;
FPressedColumn := LNewColumn;
if FPressedColumn <> -1 then
begin
Header_GetItem(Header, FPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
if (FSortDir = 1) then
Item.fmt := Item.fmt or HDF_SORTUP//include the sort ascending flag
else if (FSortDir = -1) then
Item.fmt := Item.fmt or HDF_SORTDOWN;
Header_SetItem(Header, FPressedColumn, Item);
end;
end;
end;
此外,您的组件根本不处理 window 娱乐。如果 ListView 的 HWND
被重新创建(can 并且 does 在进程的生命周期内发生),您需要恢复当前的排序箭头, 如果有的话。如果 FPressedColumn
不是 -1,您可以覆盖虚拟 CreateWnd()
或 CreateWindowHandle()
方法来调用 Header_SetItem()
:
type
TMyListView = class(TListView)
...
protected
...
procedure CreateWnd; override;
...
end;
...
procedure TMyListView.CreateWnd;
var
Header: HWND;
Item: THDItem;
begin
inherited;
if FPressedColumn <> -1 then
begin
Header := ListView_GetHeader(Self.Handle);
ZeroMemory(@Item, SizeOf(Item));
Item.Mask := HDI_FORMAT;
Header_GetItem(Header, FPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
if (FSortDir = 1) then
Item.fmt := Item.fmt or HDF_SORTUP//include the sort ascending flag
else if (FSortDir = -1) then
Item.fmt := Item.fmt or HDF_SORTDOWN;
Header_SetItem(Header, FPressedColumn, Item);
end;
end;
我正在研究 Delphi 10.2 东京。
在 SortArrow On ListView 的帮助下,我能够为我的列表视图组件添加排序箭头(在 colclick 上添加排序箭头逻辑),当我调整列大小时,排序箭头消失了。
如何在调整列大小时保持排序箭头(类似于 Windows Explorer)?
下面是我的组件代码:
unit uMyListView1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, Menus, DB, ExtCtrls, Buttons, ADODB,Commctrl;
const ARROW_SIZE = 10;
type
TMyListView = class(TListView)
private
FDataSet: TCustomADODataSet;
FPressedColumn: integer; //column index
FLastPressedColumn: integer; //last column to be pressed
FSortDir: integer; //-1 = desc, 1 = asc
FSortOrder: integer;
procedure SetListViewColumns;
protected
procedure ColClick(Column: TListColumn); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function BuildListView: boolean;
published
property DataSet: TCustomADODataSet read FDataSet write FDataSet;
end;
implementation
procedure TMyListView.ColClick(Column: TListColumn);
var DC: HDC;
Pos: TPoint;
Header: HWND;
Item: THDItem;
begin
inherited;
FLastPressedColumn := -1;
FPressedColumn := Column.Index;
FSortDir := 1;
//implement sorting
Header := ListView_GetHeader(Self.Handle);
ZeroMemory(@Item, SizeOf(Item));
Item.Mask := HDI_FORMAT;
//remove arrow old cloumn
if FLastPressedColumn <> -1 then
begin
Header_GetItem(Header, FLastPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
Header_SetItem(Header, FLastPressedColumn, Item);
end;
Header_GetItem(Header, Column.Index, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
if (FSortDir = 1) then
Item.fmt := Item.fmt or HDF_SORTUP//include the sort ascending flag
else if (FSortDir = -1) then
Item.fmt := Item.fmt or HDF_SORTDOWN;
Header_SetItem(Header, Column.Index, Item);
end;
constructor TMYListView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FPressedColumn := -1;
FLastPressedColumn := -1;
FSortOrder := 0;
end;
destructor TMYListView.Destroy;
begin
inherited Destroy;
end;
procedure TMYListView.SetListViewColumns;
var
NewColumn: TListColumn;
i: integer;
begin
if FDataSet <> nil then with FDataSet, Self.Columns do
begin
Clear; //clears any columns
for i := 0 to FieldCount - 1 do
if Fields[i].Visible then
begin
NewColumn := Add;
NewColumn.Caption := Fields[i].DisplayLabel;
NewColumn.Width := Fields[i].DisplayWidth * 10;
NewColumn.Alignment := Fields[i].Alignment;
end;
end;
end;
function TMYListView.BuildListView: boolean;
var NewListItem: TListItem;
i: integer;
begin
Result := FALSE;
FPressedColumn := -1;
FLastPressedColumn := -1;
Items.Clear;
if FDataSet = NIL then
begin
MessageDlg('The Dataset is NIL', mtError, [mbOK], 0);
Exit;
end;
try
FDataset.Open;
SetListViewColumns;
with FDataSet do
Begin
Items.BeginUpdate;
if not EOF then while not EOF do
begin
NewListItem := Items.Add;
for i := 0 to FieldCount - 1 do
begin
if Fields[i].Visible then
begin
if i = 0 then NewListItem.Caption := Fields[0].DisplayText
else if Fields[i].Visible then NewListItem.SubItems.Add(Fields[i].DisplayText);
end;
end;
Next;
Application.ProcessMessages;
end;
end;
Result := TRUE;
finally
FDataSet.Close;
Items.EndUpdate;
end;
end;
end.
不确定为什么你的箭头会消失。更糟糕的情况是,您可能需要让 ListView 处理来自 Header 的 HDN_TRACK
/HDN_ENDTRACK
通知以重置当前箭头(如果有)。
但是,您的代码中还有一些其他问题与您管理箭头的方式有关。
您的 ColClick()
方法正在将 FLastPressedColumn
重置为 -1 ,然后 使用它来清除现有箭头:
begin
inherited;
//FLastPressedColumn := -1; // <-- REMOVE THIS!
...
//remove arrow old cloumn
if FLastPressedColumn <> -1 then
begin
...
FLastPressedColumn := -1; // <-- MOVED DOWN HERE INSTEAD!
end;
...
end;
事实上,您根本不需要 FLastPressedColumn
,FPressedColumn
本身就足够了:
procedure TMyListView.ColClick(Column: TListColumn);
var
LNewColumn: Integer;
Item: THDItem;
begin
inherited;
if Column <> nil then
LNewColumn := Column.Index
else
LNewColumn := -1;
if FPressedColumn <> LNewColumn then
begin
FSortDir := 1;
//implement sorting
Header := ListView_GetHeader(Self.Handle);
ZeroMemory(@Item, SizeOf(Item));
Item.Mask := HDI_FORMAT;
//remove arrow old cloumn
if FPressedColumn <> -1 then
begin
Header_GetItem(Header, FPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
Header_SetItem(Header, FPressedColumn, Item);
end;
FPressedColumn := LNewColumn;
if FPressedColumn <> -1 then
begin
Header_GetItem(Header, FPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
if (FSortDir = 1) then
Item.fmt := Item.fmt or HDF_SORTUP//include the sort ascending flag
else if (FSortDir = -1) then
Item.fmt := Item.fmt or HDF_SORTDOWN;
Header_SetItem(Header, FPressedColumn, Item);
end;
end;
end;
此外,您的组件根本不处理 window 娱乐。如果 ListView 的 HWND
被重新创建(can 并且 does 在进程的生命周期内发生),您需要恢复当前的排序箭头, 如果有的话。如果 FPressedColumn
不是 -1,您可以覆盖虚拟 CreateWnd()
或 CreateWindowHandle()
方法来调用 Header_SetItem()
:
type
TMyListView = class(TListView)
...
protected
...
procedure CreateWnd; override;
...
end;
...
procedure TMyListView.CreateWnd;
var
Header: HWND;
Item: THDItem;
begin
inherited;
if FPressedColumn <> -1 then
begin
Header := ListView_GetHeader(Self.Handle);
ZeroMemory(@Item, SizeOf(Item));
Item.Mask := HDI_FORMAT;
Header_GetItem(Header, FPressedColumn, Item);
Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
if (FSortDir = 1) then
Item.fmt := Item.fmt or HDF_SORTUP//include the sort ascending flag
else if (FSortDir = -1) then
Item.fmt := Item.fmt or HDF_SORTDOWN;
Header_SetItem(Header, FPressedColumn, Item);
end;
end;