如何重建 TListView 但保留滚动信息?
How to rebuild a TListView but keep the scroll information?
在 TListView
中有一个错误:当您处于 vsReport
模式并设置了 GroupView
并尝试插入一个项目时,它显示在组的最后而不是您所在的位置插入。争论的问题 here。有几个答案,但其中 none 个有效。所以,我认为唯一的解决办法是每次插入一个项目时重建整个列表。这并不简单,但我想我能做到。但是有一个大问题。如果滚动 window 位于列表的中间并且我重建列表,它会将我送回开头。可以以某种方式保留滚动信息吗?
我试过这个:
procedure TNutrientsForm.Button2Click(Sender: TObject);
var ix,iy:Integer;
begin
ix:= NList.ViewOrigin.X;
iy:= NList.ViewOrigin.Y;
NList.Items.BeginUpdate;
RefreshList;
NList.Scroll(ix, iy);
NList.Items.EndUpdate;
end;
...但在 vsReport
模式下,您只能滚动行高的倍数,因此它不会将我准确定位到应有的位置。
无论如何,如果您对上面link中的问题也有答案,您可以post在那里,我会很高兴。我为此工作了 3 天,但还没有找到解决方案。这个问题已经有 9 年了。也许我们可以再试一次。
如何将插入的项目移动到正确的位置?
实际上不需要rebuild list view to workaround the original issue. It's the problem of the Windows list view control (it can be reproduced even when inserting items in a raw API way by using the LVM_INSERTITEM消息,例如)。
幸运的是,Delphi 列表视图项目对象持有正确的索引值(在控件中的预期位置),所以剩下的就是由它们重新排序 Windows 控件中的项目。这可以通过自定义排序来完成。例如,您可以编写这样的辅助方法:
type
TListViewHelper = class helper for TListView
public
function FixItemsOrder: Boolean;
end;
function FixComparer(lParam1, lParam2, lParamSort: LPARAM): Integer; stdcall;
begin
Result := TListItem(lParam1).Index - TListItem(lParam2).Index;
end;
function TListViewHelper.FixItemsOrder: Boolean;
begin
Result := Boolean(SendMessage(Handle, LVM_SORTITEMS, 0, LPARAM(@FixComparer)));
end;
并且每当您插入一个项目(或多个项目)时,调用这样的方法:
var
ListItem: TListItem;
begin
ListView1.Items.BeginUpdate;
try
ListItem := ListView1.Items.Insert(0);
ListItem.Caption := 'Item 1';
ListItem.GroupID := 0;
ListItem := ListView1.Items.Insert(0);
ListItem.Caption := 'Item 2';
ListItem.GroupID := 0;
ListItem := ListView1.Items.Insert(0);
ListItem.Caption := 'Item 3';
ListItem.GroupID := 0;
ListView1.FixItemsOrder;
finally
ListView1.Items.EndUpdate;
end;
end;
在 TListView
中有一个错误:当您处于 vsReport
模式并设置了 GroupView
并尝试插入一个项目时,它显示在组的最后而不是您所在的位置插入。争论的问题 here。有几个答案,但其中 none 个有效。所以,我认为唯一的解决办法是每次插入一个项目时重建整个列表。这并不简单,但我想我能做到。但是有一个大问题。如果滚动 window 位于列表的中间并且我重建列表,它会将我送回开头。可以以某种方式保留滚动信息吗?
我试过这个:
procedure TNutrientsForm.Button2Click(Sender: TObject);
var ix,iy:Integer;
begin
ix:= NList.ViewOrigin.X;
iy:= NList.ViewOrigin.Y;
NList.Items.BeginUpdate;
RefreshList;
NList.Scroll(ix, iy);
NList.Items.EndUpdate;
end;
...但在 vsReport
模式下,您只能滚动行高的倍数,因此它不会将我准确定位到应有的位置。
无论如何,如果您对上面link中的问题也有答案,您可以post在那里,我会很高兴。我为此工作了 3 天,但还没有找到解决方案。这个问题已经有 9 年了。也许我们可以再试一次。
如何将插入的项目移动到正确的位置?
实际上不需要rebuild list view to workaround the original issue. It's the problem of the Windows list view control (it can be reproduced even when inserting items in a raw API way by using the LVM_INSERTITEM消息,例如)。
幸运的是,Delphi 列表视图项目对象持有正确的索引值(在控件中的预期位置),所以剩下的就是由它们重新排序 Windows 控件中的项目。这可以通过自定义排序来完成。例如,您可以编写这样的辅助方法:
type
TListViewHelper = class helper for TListView
public
function FixItemsOrder: Boolean;
end;
function FixComparer(lParam1, lParam2, lParamSort: LPARAM): Integer; stdcall;
begin
Result := TListItem(lParam1).Index - TListItem(lParam2).Index;
end;
function TListViewHelper.FixItemsOrder: Boolean;
begin
Result := Boolean(SendMessage(Handle, LVM_SORTITEMS, 0, LPARAM(@FixComparer)));
end;
并且每当您插入一个项目(或多个项目)时,调用这样的方法:
var
ListItem: TListItem;
begin
ListView1.Items.BeginUpdate;
try
ListItem := ListView1.Items.Insert(0);
ListItem.Caption := 'Item 1';
ListItem.GroupID := 0;
ListItem := ListView1.Items.Insert(0);
ListItem.Caption := 'Item 2';
ListItem.GroupID := 0;
ListItem := ListView1.Items.Insert(0);
ListItem.Caption := 'Item 3';
ListItem.GroupID := 0;
ListView1.FixItemsOrder;
finally
ListView1.Items.EndUpdate;
end;
end;