How to rebuild a TListView but keep the scroll information?

余生长醉 提交于 2019-12-23 21:12:52

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!