问题
In TListView
there is a bug: when you are in vsReport
mode with GroupView
set and try to insert a item, it is displayed last in the group not where you inserted. The problem is debated here. There are a few answers but none of them work. So, I think the only solution is to rebuild the entire list every time you insert a item. It's not simple but I think I can do it. But there is a big problem. If the scroll window is in the middle of the list and I rebuild the list, it send me back to the begining. It is possible to keep somehow the scroll information ?
I tried this:
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;
... but in vsReport
mode you can only scroll in multiple of row height, so it does not position me exactly where it is supposed to.
Anyway, if you have an answer too for the problem in the link above, you can post it there and I will be verry happy. I worked for 3 days on this and I have not found a solution. That question is 9 years old. Maybe we can try again.
回答1:
How to move inserted items to the correct position?
There's actually no need to 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 message, for example).
Luckily, Delphi list view item objects are holding correct index values (of the intended placement in the control), so what remains is reordering the items in the Windows control by them. And that can be done by custom sorting. For example you can write a helper method like this:
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;
And whenever you insert an item (or multiple items), call such method:
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;
来源:https://stackoverflow.com/questions/50510543/how-to-rebuild-a-tlistview-but-keep-the-scroll-information