Delphi - Get and Set Scrollbar Position of a ListView
Save the top item before clearing,
FSaveTop := ListView1.TopItem;
After updating, scroll the listview so that the saved top item's 'y' position will be 0 (+ header height):
var
R: TRect;
begin
if Assigned(FSaveTop) then begin
// account for header height
GetWindowRect(ListView_GetHeader(ListView1.Handle), R);
ListView1.Scroll(0, FSaveTop.Position.Y - (R.Bottom - R.Top));
end;
end;
Actually, since you're re-populating the listview, you have to devise a mechanism to find which item you want to be at the top instead of saving a reference to it.
If you don't like modifying scroll position through 'top item', since functions like SetScrollInfo
, SetScrollPos
won't update the client area of the control, you can use GetScrollInfo
to get the 'nPos' of a TScrollInfo
before clearing the list, and then send that many WM_VSCROLL
messages with 'SB_LINEDOWN` after populating.
Save scroll position:
var
FPos: Integer;
SInfo: TScrollInfo;
begin
SInfo.cbSize := SizeOf(SInfo);
SInfo.fMask := SIF_ALL;
GetScrollInfo(ListView1.Handle, SB_VERT, SInfo);
FPos := SInfo.nPos;
...
After populating, scroll (assuming scroll position is 0):
var
R: TRect;
begin
...
R := ListView1.Items[0].DisplayRect(drBounds);
ListView1.Scroll(0, FPos * (R.Bottom - R.Top));
or,
var
i: Integer;
begin
...
for i := 1 to FPos do
SendMessage(ListView1.Handle, WM_VSCROLL, SB_LINEDOWN, 0);