Delphi - 获取并设置ListView的滚动条位置

时间:2013-12-29 22:25:14

标签: delphi scrollbar tlistview

这看起来像是一个愚蠢的&简单的问题,然而,我一直无法找到令人满意的答案。基本上,我有一个带有数据的 TListview (style = vsReport)。有时,我必须更新它,因此,我必须清除列表视图并使用更新的数据再次填充它。

然而,当我这样做时,滚动条位置重置为0.我希望能够在清除之前获得滚动条位置并将其设置回原来的状态。如果更新的数据与旧数据具有完全相同的行数,我需要滚动条与之前的位置完全相同;如果没有,我只需要它和以前在同一个地方或多或少。

看起来很简单,对吗?然而,我发现的只有 TopItem MakeVisible 的黑客或调整。有没有合适的方法呢?

谢谢!

2 个答案:

答案 0 :(得分:13)

清除前保存顶部项目

FSaveTop := ListView1.TopItem;

更新后,滚动列表视图,以便保存的顶部项目的“y”位置为0(+标题高度):

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;

实际上,由于您要重新填充列表视图,因此您必须设计一种机制来查找您想要位于顶部的项目,而不是保存对它的引用。


如果你不喜欢通过'top item'修改滚动位置,因为像SetScrollInfoSetScrollPos这样的函数不会更新控件的客户区域,你可以使用GetScrollInfo在清除列表之前获取TScrollInfo的'nPos',然后在填充后用'SB_LINEDOWN`发送那么多WM_VSCROLL条消息。

保存滚动位置:

var
  FPos: Integer;
  SInfo: TScrollInfo;
begin
  SInfo.cbSize := SizeOf(SInfo);
  SInfo.fMask := SIF_ALL;
  GetScrollInfo(ListView1.Handle, SB_VERT, SInfo);
  FPos := SInfo.nPos;
  ...

填充后,滚动(假设滚动位置为0):

var
  R: TRect;
begin
  ...
  R := ListView1.Items[0].DisplayRect(drBounds);
  ListView1.Scroll(0, FPos * (R.Bottom - R.Top));

,或者

var
  i: Integer;
begin
  ...
  for i := 1 to FPos do
    SendMessage(ListView1.Handle, WM_VSCROLL, SB_LINEDOWN, 0);

答案 1 :(得分:-2)

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Timer1: TTimer;
    Timer2: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
    pb:array [0..20] of Tprogressbar;
    i:integer;
      mintop,spacetop,readtop:integer;
    implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);


begin

mintop:=19;
spacetop:=14;
for i:=0 to 20 do
begin
listview1.AddItem('Item no'+inttostr(i),nil);
pb[i]:=Tprogressbar.create(self);
pb[i].Parent:=listview1;
pb[i].width:=120;
pb[i].height:=14;
pb[i].top:=mintop+i*spacetop;
pb[i].position:=i*5;
pb[i].Left:=listview1.Column[0].Width;



end;


end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  z,FPos: Integer;
  SInfo: TScrollInfo;
begin
  SInfo.cbSize := SizeOf(SInfo);
  SInfo.fMask := SIF_ALL;
  GetScrollInfo(ListView1.Handle, SB_VERT, SInfo);
  FPos := SInfo.nPos;
  form1.caption:='FPOS='+inttostr(fpos);
if fpos>0 then
begin
for z:=0 to 11 do
begin
pb[z+fpos-1].Top:=mintop+z*spacetop;
form1.caption:=form1.caption+' Z='+inttostr(z)+' !';
     end;
     end;

 end;
procedure TForm1.Timer2Timer(Sender: TObject);
var x:integer;
begin
  for  x:=0 to 20 do
  begin
  pb[x].Position:=Pb[x].position+1;
  end;


end;

end.


/// Code by BRTH1 - Simao Coelho - Portugal