Recent

Author Topic: [SOLVED] Set horizontal scroll position in a TMemo does not work (Windows only)  (Read 7850 times)

rvk

  • Hero Member
  • *****
  • Posts: 7025
Just a short intermediate info: I tested a file with ALL lines of the same length (80 characters, 65550 lines) and in my real program the horizontal scroll issue occurs the same as always :-((
Will try further...
Ok. That's strange then.

In your own program you can use getscrollinfo with sif_all to get the nmin/nmax from the horizontal scrollbars. You can do that before adding a line. Then also do this just before setting the X for horizontal scroll. The nmin/nmax should be the same. If they are not, then the horz scrollbars is not updated directly yet.

(You can see how I did that in my latest example and updated a label.)

Hope you can find out some useful info from that to pinpoint the problem.

jamie

  • Hero Member
  • *****
  • Posts: 7711
MEMO = A Short Note!

Jamie
The only true wisdom is knowing you know nothing

Hartmut

  • Hero Member
  • *****
  • Posts: 1137
In your own program you can use getscrollinfo with sif_all to get the nmin/nmax from the horizontal scrollbars. You can do that before adding a line. Then also do this just before setting the X for horizontal scroll. The nmin/nmax should be the same. If they are not, then the horz scrollbars is not updated directly yet.

I implemented LCLIntf.GetScrollInfo() at several places in my real program. As I assumed (but I was not sure) 'nMax' is independant of a "current" line. It contains always the length in pixels of the longest existing line. 'nMin' is always '0'. So what you assumed in reply #26, from my understanding, can only apply, if the longest line is deleted or shortened, but we only add 1 line.

Here are some results of GetScrollInfo() for vertical + horizontal scrollbars with my real program:
// at the time where all current positions are read and stored (before Memo1.Text is changed):
--GET: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--GET: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0
// after Memo1.Text was changed and before vertical position is restored by SetScrollInfo():
--SET-V: style=VERT nMin=0 nMax=65541 nPage=52 nPos=0 nTrack=0
--SET-V: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0
// after vertical position was restored and before horizontal position is restored by SetScrollInfo():
--SET-H: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--SET-H: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0
// after horizontal position was restored:
--SET-DONE: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--SET-DONE: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=153 nTrack=153

You see in the last line (marked red), that horizontal 'nPos' now becomes 153, but it should be '0' as before. That is the issue as described before.

Then I tested your new demo from reply #26 in my real program, but unfortunately it made no difference :-((

But I made (again, only forgot to mention it here before) a strange observation about the horizontal scrollbar behavior in my real program, if Memo1.Lines.Count >= 65534:

What still works normally:
 - click left or right of the slider in the "empty space" to scroll 1 "page" left or right
 - click on the little arrows at the left or right end of the scrollbar to scroll a small amout left or right.

But what does not work if Memo1.Lines.Count >= 65534 is, to drag the slider via mouse:
  • if I try this, the slider at first moves correctly (corresponding to the mouse movement) as it should, but as soon as I realease the left mouse button, the slider jumps to a wrong position (which has a correlation with the current vertikal scroll position, it jumps often to the very right end position).
  • and, if the text currently is scrolled to it's left end (and the slider is at it's left end), in the moment where I click on the slider (wanting to start a drag), at this moment the text itself is automatically scrolled to it's very right end (but the slider stays at it's left end as before). If I release the left mouse button, the slider jumps to the very right end position (the exact target position has also a correlation with the current vertikal scroll position).
If I delete some text lines, so that Memo1.Lines.Count becomes < 65534, this issue stops immediately (without starting the program new or reloading the file). If I then add again some text lines, so that Memo1.Lines.Count becomes >= 65534, the issue occurs again (without starting the program new or reloading the file). The maximum line length is 214 characters.

Tested with Win10 and Win7 with Lazarus 3.6.0, 2.0.10, 1.8.4 and 1.4.4 (needed a large duster ;-)
This happens also directly after program start, without having pressed F5-key ever.
This issue occurs only in my real program (about 64000 lines of code) and not in rvk's demos in reply #23 and #26, always loading exactly the same textfile.
The vertical scrollbar does not have this issue!

Question:
Has anybody an idea, what the reason for such a strange behavior of the horizontal scrollbar might be?

rvk

  • Hero Member
  • *****
  • Posts: 7025
// after vertical position was restored and before horizontal position is restored by SetScrollInfo():
--SET-H: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--SET-H: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0

UpdateWindow(Memo1.Handle); <---- HERE

--> then restore HORZ scrollbar...

// after horizontal position was restored:
--SET-DONE: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--SET-DONE: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=153 nTrack=153


Question:
Has anybody an idea, what the reason for such a strange behavior of the horizontal scrollbar might be?
Just to clarify... did you try putting an UpdateWindow(Memo1.Handle) directly after restoring HORZ scrollbar but BEFORE restoring VERT scrollbar?
(It will visibly redraw but for now we first need to debug this to see what the reason is)

Hartmut

  • Hero Member
  • *****
  • Posts: 1137
Just to clarify... did you try putting an UpdateWindow(Memo1.Handle) directly after restoring HORZ scrollbar but BEFORE restoring VERT scrollbar?
(It will visibly redraw but for now we first need to debug this to see what the reason is)
Yes (probably you mean "after restoring VERT scrollbar but BEFORE restoring HORZ scrollbar").
I had both made a copy of your procedure TForm1.Memo1KeyDown() from reply #26 and called this in my real program and I had added UpdateWindow(Memo1.Handle) into my "normal" code (after restoring VERT and before restoring HORZ). Unfortunately both with the same result as before.

rvk

  • Hero Member
  • *****
  • Posts: 7025
Yes (probably you mean "after restoring VERT scrollbar but BEFORE restoring HORZ scrollbar").
Oops, yes. Because you indeed always need to restore the vertical first (to view the correct lines), the UpdateWindows should update the horizontal bar with the correct limits, after which you can restore the horizontal position.

Unfortunately both with the same result as before.
I take it in your example, your horizontal scrollbar was at position 0 (all the way to the left)?

--GET: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--GET: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0


I've never seen the restore get to something higher than it was.
What was the ScrollPos.X before adding anything? Was it 0? And was it still 0 when you get to the line for:
SendMessage(Memo1.Handle, WM_HSCROLL, MakeWParam(SB_THUMBPOSITION, ScrollPos.X), 0);
?

Hartmut

  • Hero Member
  • *****
  • Posts: 1137
I take it in your example, your horizontal scrollbar was at position 0 (all the way to the left)?
--GET: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--GET: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0

Correct.

Quote
I've never seen the restore get to something higher than it was.
From what I have seen I assume, that restoring the cursor position does often change the vertical and/or horizontal scroll positions. In this case only vertical scroll position was changed:
// after Memo1.Text was changed and before vertical position is restored by SetScrollInfo():
--SET-V: style=VERT nMin=0 nMax=65541 nPage=52 nPos=0 nTrack=0
--SET-V: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0


Quote
What was the ScrollPos.X before adding anything? Was it 0?
Yes. This I meant with
// at the time where all current positions are read and stored (before Memo1.Text is changed):
--GET: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--GET: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0


Quote
And was it still 0 when you get to the line for:
SendMessage(Memo1.Handle, WM_HSCROLL, MakeWParam(SB_THUMBPOSITION, ScrollPos.X), 0);
?
Yes.
I tried both a simple sleep() to be able to observe this and a procedure, which waits some time and calls Application.ProcessMessages() repeatedly to allow LCL updates. In both cases the text stayed scrolled to the very left position (ScrollPos.X=0) as it had been all the time before. Only after calling SendMessage(WM_HSCROLL) the text scrolled to the right to ScrollPos.X=153 (which was the initial vertical scroll position - very strange).

To avoid problems with MakeWParam(), which exists in 2 different Units, I made my own copy and showed it's result:

Code: Pascal  [Select][+][-]
  1. function myMAKELONG(a,b : longint) : LONG;
  2.   begin
  3.      myMAKELONG:=LONG((WORD(a)) or ((DWORD(WORD(b))) shl 16));
  4.   end;
  5.  
  6. // WPARAM = LONG_PTR = PtrInt
  7. function myMAKEWPARAM(l,h : longint) : WPARAM;
  8.   begin
  9.      myMAKEWPARAM:=WPARAM(myMAKELONG(l,h));
  10.   end;  
  11.  
  12. ...  
  13. writeln('UpdateWindow():');
  14. UpdateWindow(Memo1.Handle);
  15. showScrollInfosBoth(Memo1.Handle,'--SET-H: '); // shows both scrollbars
  16.  
  17. writeln('ScrollPos.X=', ScrollPos.X);
  18. wp:=myMakeWParam(SB_THUMBPOSITION,ScrollPos.X);
  19. writeln('wp=', int6Str(wp));
  20. // sleep(6000);
  21. wait_ms_AppProcMsg(6000);
  22. SendMessage(Memo1.Handle, WM_HSCROLL, wp , 0);
  23. showScrollInfosBoth(Memo1.Handle,'--SET-DONE: '); // shows both scrollbars
 
The Output is:
UpdateWindow():
--SET-H: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--SET-H: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=0 nTrack=0
ScrollPos.X=0
wp=4
--SET-DONE: style=VERT nMin=0 nMax=65541 nPage=52 nPos=153 nTrack=153
--SET-DONE: style=HORZ nMin=0 nMax=1023 nPage=627 nPos=153 nTrack=153


Must stop in the next time for today, but can continue tomorrow.

rvk

  • Hero Member
  • *****
  • Posts: 7025
 %)
It could be that 0 sometimes is interpreted as "do nothing" (which might even take something/invalid from a buffer).

I have two small tests for you for tomorrow.
Before that... I assume var wp is really a WPARAM type?

1. Before restoring horizontal bar and setting wp:
if ScrollPos.X = 0 then ScrollPos.X := 1;
just to see if it does set it at 1 then.

2. Instead of using SB_THUMBPOSITION...
if ScrollPos.X = 0 then wp := SB_LEFT;
SendMessage(Memo1.Handle, WM_HSCROLL, wp , 0);


Aaaah, having fun with TMemo  8-)
« Last Edit: April 03, 2026, 09:26:50 pm by rvk »

Hartmut

  • Hero Member
  • *****
  • Posts: 1137
I'm again impressed about your ideas and how much you know.

Before that... I assume var wp is really a WPARAM type?
Yes.

Quote
1. Before restoring horizontal bar and setting wp:
if ScrollPos.X = 0 then ScrollPos.X := 1;
just to see if it does set it at 1 then.
Unfortunately it makes no difference.

And if the initial horiz. scroll position was > 0, the same issue as always occurs, not only if it was '0'.

Quote
2. Instead of using SB_THUMBPOSITION...
if ScrollPos.X = 0 then wp := SB_LEFT;
SendMessage(Memo1.Handle, WM_HSCROLL, wp , 0);
On the 1st view it seems to work, because now the resulting horiz. scroll position is 0.
But if I skip the horiz. restore commands completely, I have the same result (horiz. scroll position stays 0) as said in reply #36:
Quote
In both cases the text stayed scrolled to the very left position (ScrollPos.X=0) as it had been all the time before. Only after calling SendMessage(WM_HSCROLL) the text scrolled to the right to ScrollPos.X=153
So we don't know, whether SendMessage(SB_LEFT) does something or not.



Then I simplified my test code drastically: when F5 key is pressed, now only the horiz. scroll position is tried to increase by 20. Memo1.Text is not changed and cursor position and vert. scroll position also are not changed:
Code: Pascal  [Select][+][-]
  1. procedure scrollHoriz(MM: TMemo);
  2.    {scrolls horizontally by 'Step' pixels by 1 of 4 different methods (A..D) by removing the '//'
  3.     in front of the executing line}
  4.    const Step = 20;
  5. {$IFNDEF LINUX}
  6.    var SI: windows.TScrollInfo;
  7.        wp: WPARAM;    {WPARAM  = Windows.WPARAM  = LONG_PTR = PtrInt = int3264}
  8.        lres: LRESULT; {LRESULT = Windows.LRESULT = LONG_PTR = PtrInt = int3264}
  9. {$ENDIF}
  10.    var h,res: longint;
  11.    begin
  12.    h:=GetScrollPos(MM.Handle, SB_HORZ);
  13.    writeln('h=', h, ' => ', h+Step, ' Count=', MM.Lines.Count);
  14.    inc(h,Step);
  15.    showScrollInfosBoth(MM.Handle,'--GET: '); // shows both scrollbars
  16.  
  17. {A) the following moves the slider and increments horiz. 'nPos' correctly (even
  18.     if Count=65587), but the Text itself does NEVER scroll anyway (even not if
  19.     Count < 65520), an initial horiz. scroll position stays always unchanged: }
  20.    zeroMem(SI,SizeOf(SI));
  21.    SI.cbSize:=SizeOf(SI);
  22.    SI.fMask:=SIF_POS;
  23.    SI.nPos:=h;
  24.    res:=-1;
  25. // res:=windows.SetScrollInfo(MM.Handle,SB_HORZ,SI,true);
  26.    writeln('SSI=', res);
  27.  
  28. {B) works completely identically as A): }
  29.    lres:=-1;
  30. // lres:=windows.SetScrollPos(MM.Handle,SB_HORZ,h,true);
  31.    writeln('SSP=', lres);
  32.  
  33. {C) the following works only, if Count < 65534 / if Count >= 65535 then the
  34.     horiz. scroll position becomes always the current vert. scroll position: }
  35.    wp:=myMakeWParam(SB_THUMBPOSITION,h); // myMakeWParam() see in reply #36
  36.    writeln('wp=', int6Str(wp));
  37.    lres:=-1;
  38. // lres:=windows.SendMessage(MM.Handle, WM_HSCROLL, wp, 0);
  39.    writeln('SM=', lres);
  40.  
  41. {D) the following always works correctly: independant from an arbitrary starting
  42.     horiz. scroll position the Text always is scrolled correctly to the very
  43.     left, even if Count=65588: }
  44.    wp:=SB_LEFT; // 6
  45.    writeln('wp=', int6Str(wp));
  46.    lres:=-1;
  47. // lres:=windows.SendMessage(MM.Handle, WM_HSCROLL, wp, 0);
  48.    writeln('SM0=', lres);
  49.                                  {makes always no difference with or without: }
  50.    UpdateWindow(MM.Handle); writeln('UpdateWindow()');
  51.    showScrollInfosBoth(MM.Handle,'--SET-DONE: '); // shows both scrollbars
  52.    end; {scrollHoriz}

You see that only method D) works correctly...

Please keep in mind the strange behavior of the horizontal scrollbar (drag via mouse does not work) if Memo1.Lines.Count >= 65534, as described in reply #32.

rvk

  • Hero Member
  • *****
  • Posts: 7025
I'm just wondering... on what platform are you? I thought you were on Windows?
You keep using writeln. Are you not using a GUI application?

(Or is there a setting that for a GUI app a console is automatically opened? I can remember something like that in the far past.)

Hartmut

  • Hero Member
  • *****
  • Posts: 1137
I'm just wondering... on what platform are you? I thought you were on Windows?
You keep using writeln. Are you not using a GUI application?
(Or is there a setting that for a GUI app a console is automatically opened? I can remember something like that in the far past.)
With this issue I'm on Windows. If you insert in a Windows GUI application
Code: Pascal  [Select][+][-]
  1. {$IFNDEF LINUX} {$apptype console} {$ENDIF}
then you get an additional console which I find very comfortable for showing debug infos very easy.

Seems that I could have a solution. I wrote, that
Code: Pascal  [Select][+][-]
  1. SendMessage(MM.Handle, WM_HSCROLL, wp, 0);
always sets the horiz. scroll position to the current vert. scroll position.
We have an idiom "If the prophet doesn't come to the mountain, the mountain must come to the prophet". So I got this idea:
 - set the vert. scroll position temporarily to the desired horiz. scroll position
 - set the horiz. scroll position to it's desired value (which will set the current vert. scroll position, which is the desired horiz. scroll position)
 - lastly set the desired vert. scroll position.

I'm not finished with tests, but until now it looks good. Wanted just to inform you soon.

If this works, this workaround would be only neccessary,
 - if the Memo has >= 65534 lines
 - and if the desired horiz. scroll position is > 0 (because for '0' I can use SendMessage(SB_LEFT), so there no workaround neccessary)

Will report the result if either all tests worked (this might be tomorrow) or if a test fails (then soon).

rvk

  • Hero Member
  • *****
  • Posts: 7025
We have an idiom "If the prophet doesn't come to the mountain, the mountain must come to the prophet". So I got this idea:
 - set the vert. scroll position temporarily to the desired horiz. scroll position
 - set the horiz. scroll position to it's desired value (which will set the current vert. scroll position, which is the desired horiz. scroll position)
 - lastly set the desired vert. scroll position.
Haha, yes, if it sets the vertical to the position of hortizontal, that would be 'a solution'.
But it's still a very strange situation.

For me, with a simple app with TMemo with 70000 lines the increment of 20 with horizontal, just this line is sufficient (regardless of vertical scrollpos).
Code: Pascal  [Select][+][-]
  1. h := GetScrollPos(MM.Handle, SB_HORZ);
  2. Inc(h, Step);
  3. SendMessage(MM.Handle, WM_HSCROLL, MakeWParam(SB_THUMBPOSITION, h), 0);

If you test this in a very small test-app and you see the same... and in your other program it's different, then there seems to be something interfering in that program.

Hartmut

  • Hero Member
  • *****
  • Posts: 1137
Lets start with the good news: it works now! I made all tests which I thought they make sense and restoring both vert. and horiz. scroll position on Win10 and Win7 now worked perfectly!.

If you test this in a very small test-app and you see the same... and in your other program it's different, then there seems to be something interfering in that program.
As said:
Quote
This issue occurs only in my real program (about 64000 lines of code) and *not* in the demos from rvk in reply #23 and #26, always using exactly the same textfile.
Yes, this must be the case. From memory I have no idea, what could be a reason in my real program for that behavior. But now, where I have a very good solution, I'm happy, that I don't need to dive very deep into this issue there (assuming that this would make much more effort).

Again thank you very much rvk for your continuous and valuable help. Without your idea of combining SetScrollInfo() and SendMessage() it would not have worked.

 

TinyPortal © 2005-2018