I want a feature, that the content of a Memo can be replaced by a new content, but the previous cursor- and scroll-positions in the Memo shall be unchanged (restored). For problems to restore the vertical scroll position on Linux I had another Topic last week and found a solution. Now I have problems to restore the horizontal scroll position on
Windows and hope to find a solution/workaround here.
This is a short demo for my current code:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
end;
var Form1: TForm1;
implementation
{$R *.lfm}
procedure TForm1.FormCreate(Sender: TObject);
var s: string;
begin
s:='1234qwert' + LineEnding {fill the Memo with demo text: }
+ 'xxx enable/disable deprecated unixutil.EpochToLocal() + unixutil.LocalToEpoch(): ]'
+ LineEnding;
Memo1.ScrollBars:=ssAutoBoth;
Memo1.Text:=s;
end;
procedure wait_ms_AppProcMsg(ms: word);
{waits some ms and calls Application.ProcessMessages repeatedly}
const Step = 125;
var n: word;
begin
while ms > 0 do
begin
n:=Step; if n > ms then n:=ms;
sleep(n);
Application.ProcessMessages;
dec(ms,n);
end;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
{Key 'F5' shows a changed content in the Memo and the previous cursor- and
scroll-positions in the Memo shall be unchanged (restored)}
var curpos,vpos,hpos,dummy: longint;
begin
if Key <> VK_F5 then exit;
curpos:=Memo1.SelStart; {remember previous cursor position}
vpos:=Memo1.VertScrollBar.Position; {remember previous scroll position}
hpos:=Memo1.HorzScrollBar.Position; {remember previous scroll position}
writeln('curpos=', curpos, ' vpos=', vpos, ' hpos=', hpos);
Memo1.Text:=Memo1.Text + 'hello' + LineEnding; {simulate Memo content changed}
dummy:=Memo1.VertScrollBar.Position; // update scroll cache (?)
dummy:=Memo1.HorzScrollBar.Position;
Memo1.VertScrollBar.Position:=vpos; {restore vertical scroll position}
// write('1---'); wait_ms_AppProcMsg(4000); writeln('1'); {wait 4 s}
Memo1.HorzScrollBar.Position:=hpos; {restore horizontal scroll position}
// write('2---'); wait_ms_AppProcMsg(4000); writeln('2'); {wait 4 s}
Memo1.SelStart:=curpos; {restore cursor position}
writeln('hpos=', Memo1.HorzScrollBar.Position);
end;
end.
It works to restore the cursor position and vertical scroll position, but for the horizontal scroll position there can be 2 different wrong behaviours.
How to produce wrong behaviour #1: - compile and run attached project
- scroll horizontally until "1234" disappears left and "qwert" is still visible
- set the cursor behind "qwert" and press key F5
Result: the Memo is scrolled completely to the left (as if 'hpos' would be '0', but 'hpos' is about 24).
How to produce wrong behaviour #2: - scroll again horizontally until "1234" disappears left and "qwert" is still visible
- set the cursor in line 2 directly left of "EpochToLocal" and press key F5
Results:
- the Memo is scrolled completely to the right (as if 'hpos' would be about 110, but 'hpos' is about 24)
- but the horizontal ScrollBar itself has the correct position
- if you click on this ScrollBar, then the Memo scrolls correctly to it's position before pressing F5
When you activate lines 65 and 67 than you can see:
- after 'Memo1.VertScrollBar.Position:=vpos' the Memo is scrolled to the left (the default after it's content was changed)
- directly after 'Memo1.HorzScrollBar.Position:=hpos' the Memo is scrolled to the right end. So this does
not occur by 'Memo1.SelStart:=curpos'.
I tested on Win10 64-bit and Win7 32-bit and compiled (32-bit) with Lazarus/FPC 3.6.0/3.2.2 and 2.0.10/3.2.0 (same result).
Question 1Is it possible to "refresh" the Memo at the end in any kind, so that it is scrolled to it's correct position accordingly to 'hpos'?
I tried Memo1.Update, .Refresh, .Repaint and .Invalidate without success.
Question 2When I click on the horizontal ScrollBar (after "wrong behaviour #2"), then the Memo scrolls to it's correct position. Can somebody point me to the Sources, where this mouse-click is handled and the "trigger" for the Memo is activated, so that it scrolls corecctly?
Maybe I could call this code (or copy it and call it).
Or has somebody another / better idea? Thanks in advance.