这看起来像是一个愚蠢的&简单的问题,然而,我一直无法找到令人满意的答案。基本上,我有一个带有数据的 TListview (style = vsReport)。有时,我必须更新它,因此,我必须清除列表视图并使用更新的数据再次填充它。
然而,当我这样做时,滚动条位置重置为0.我希望能够在清除之前获得滚动条位置并将其设置回原来的状态。如果更新的数据与旧数据具有完全相同的行数,我需要滚动条与之前的位置完全相同;如果没有,我只需要它和以前在同一个地方或多或少。
看起来很简单,对吗?然而,我发现的只有 TopItem 和 MakeVisible 的黑客或调整。有没有合适的方法呢?
谢谢!
答案 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'修改滚动位置,因为像SetScrollInfo
,SetScrollPos
这样的函数不会更新控件的客户区域,你可以使用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