I am trying to save and then restore the vertical scroll position in RichEdit.
A global var to store scroll pos:
SI: TScrollInfo;
This code saves the scroll position:
FillChar( SI, SizeOf(SI), #0 );
SI.cbSize := SizeOf(SI);
SI.fMask := SIF_POS;
GetScrollInfo( RichEdit1.Handle, SB_VERT, SI );
This code tries to restore it:
RichEdit1.Perform( WM_VSCROLL, MakeLong(SB_THUMBTRACK, SI.nPos), 0 );
The text in RichEdit restores its older position OK. The problem is the vertical scrollbar won't jump to the older location.
My system: Win 7 64, Delphi 2009
What am I doing wrong?
In many ways, the "cleanest" solution would be to use the EM_GETSCROLLPOS
and EM_SETSCROLLPOS
messages:
const
EM_GETSCROLLPOS = $04DD;
EM_SETSCROLLPOS = $04DE;
var
P: TPoint;
procedure TForm1.btnSaveClick(Sender: TObject);
begin
RichEdit1.Perform(EM_GETSCROLLPOS, 0, @P)
end;
procedure TForm1.btnRestoreClick(Sender: TObject);
begin
RichEdit1.Perform(EM_SETSCROLLPOS, 0, @P)
end;
However, beware of the 16-bit limitation described in the documentation, which limits the vertical range you are able to represent using these messages. If you display large RTF documents, this might be an issue (a showstopper, really).
Actually, your initial approach seems (to my surprise) not to suffer from this limitation. You will lose in precision, not range. The problem you are observing with the scrollbar can be fixed by using SB_THUMBPOSITION
instead of SB_THUMBTRACK
.
var
Y: Integer;
procedure TForm1.btnSaveClick(Sender: TObject);
begin
y := RichEdit1.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
end;
procedure TForm1.btnRestoreClick(Sender: TObject);
var
NewY: Integer;
begin
NewY := RichEdit1.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
RichEdit1.Perform(EM_LINESCROLL, 0, Y - NewY);
end;
might be a viable option.