Recent

Author Topic: Setting TMemo.VertScrollBar.Position does not scroll the text field  (Read 20510 times)

henrik

  • Newbie
  • Posts: 2
This issue has been brought up multiple times over the past many years, but none of the suggested solutions seem to work. Therefore I will bring it up again and add as detailed info as possible, in the hope that someone will be able to reproduce it and find a real solution.

I need to scroll the text in a TMemo automatically.
To do this I set the value of TMemo.VertScrollBox.Position.
Setting Position moves the thumb of the ScrollBar, but the text does not scroll.

I am using Lazarus version 1.4.2, FreePascal version 2.6.4, and I am compiling and executing the program on Windows 8 ver 6.3.
Please note that I have tried this on earlier versions of Lazarus and Windows with the same result.
I have not tried it on Linux, so it might be a Windows only problem.

Here is a quick program which shows the problem:
Create a new application.
Add a Tmemo and a TButton on the form.
Set the TMemo.ScrollBars property to ssAutoVertical.
Create a OnPress handler for the TButton.
Create a OnCreate handler for the TForm.
Enter this code in the two handlers:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Memo1.VertScrollBar.Position:=Memo1.VertScrollBar.Position+1;
  4. end;
  5.  
  6. procedure TForm1.FormCreate(Sender: TObject);
  7. var
  8.   i:integer;
  9. begin
  10.   for i:=1 to 99 do
  11.     Memo1.Lines.Add(format('Line %d', [i]));
  12. end;
  13.  

Now run the program, and press the button a number of times.
If it works like it does for me, then you will notice that the thumb of the scroll bar moves down, but the text doesn't scroll.
Now move the mouse over the thumb, and give it a click, you will now see that the text jumps to the line which matches the scroll bar position.

The attached png shows two screen shots of the program.
On the left screen shot I pressed the button 46 times, so the thumb is half way down the scroll bar, but the text field still shows the top line.
On the right screen shot the scroll bar is still at position 46, and I have clicked the thumb with the mouse. Now the text field is aligned with the scroll bar and top line is line 46.

I really hope someone can fix this, or come up with a decent workaround, because my current workaround is a bit of a pain.


balazsszekely

  • Guest
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #1 on: November 22, 2015, 08:16:32 am »
Confirmed! You should fill a bug report here: http://bugs.freepascal.org/main_page.php. Please attach a small demo application(zip), which reproduce the problem.
Until the bug it's fixed, use the following code as a workaround:
Code: Pascal  [Select][+][-]
  1.  SendMessage(Memo1.Handle, WM_VSCROLL, SB_LINEDOWN, 0);  
Just don't forget to add windows to the uses clauses. It should be the first in the list.

henrik

  • Newbie
  • Posts: 2
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #2 on: November 22, 2015, 12:26:46 pm »
Thank you GetMem
I have now filed a bug-report, as you suggested.

In my real application I need random access to up to 4000 lines, so I expanded your workaround a bit and ended up with this:

Code: Pascal  [Select][+][-]
  1.   newPos:=Memo1.VertScrollBar.Position+10;
  2.  
  3.   {$ifdef WINDOWS}
  4.   SendMessage(Memo1.Handle, EM_LINESCROLL, 0, newPos - Memo1.VertScrollBar.Position);
  5.   {$else}
  6.   Memo1.VertScrollBar.Position:=newPos;
  7.   {$endif}
  8.  

« Last Edit: November 22, 2015, 08:34:57 pm by henrik »

balazsszekely

  • Guest
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #3 on: November 22, 2015, 08:52:49 pm »
Quote
I have now filed a bug-report, as you suggested
Thank you!

Unfortunately it's not working under linux(GTK2) and OSX either.

Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #4 on: November 23, 2015, 12:01:27 am »
Does it (setting scrollbar position) work in Delphi?

Bart

balazsszekely

  • Guest
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #5 on: November 23, 2015, 06:31:58 am »
@Bart
Delphi does not have a HorzScrollBar/VertScrollBar property, so setting the Position it's not possible directly, only through SendMessage/Perfrom. 
However Memo1.VertScrollBar.Position(Lazarus) it should work in my opinion. Place a large enough image inside a TScrollBox, then change the position of the scrollbar, the images is scrolled nicely(see attachment).

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4599
  • I like bugs.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

zeljko

  • Hero Member
  • *****
  • Posts: 1770
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #7 on: November 23, 2015, 03:24:28 pm »
See my note in
 http://bugs.freepascal.org/view.php?id=29067

GetScrollinfo() ,SetScrollinfo() from lcl winapi does not work ?

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4599
  • I like bugs.
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #8 on: November 23, 2015, 05:44:24 pm »
GetScrollinfo() ,SetScrollinfo() from lcl winapi does not work ?

No. Actually SetScrollinfo is already called at the end of TControlScrollBar.SetPosition.
Even this does not work :
Code: Pascal  [Select][+][-]
  1. procedure TMemoScrollbar.SetControlPosition;
  2. begin
  3.   if Kind = sbVertical then
  4.     TCustomMemo(FControl).ScrollBy(0, FPosition - FPrevPosition)
  5.   else
  6.     TCustomMemo(FControl).ScrollBy(FPosition - FPrevPosition, 0);
  7. end;
  8.  

This is frustrating. I fail almost always when I try to fix something in LCL. :(
Can you please look at it.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

balazsszekely

  • Guest
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #9 on: November 23, 2015, 06:09:17 pm »
@Juha

I just test this and it's not working either:
Memo1.ScrollBy(0, 4)
With delphi it's working fine.

PS: It seems that there are more then one issue with TMemo.
« Last Edit: November 23, 2015, 06:27:37 pm by GetMem »

balazsszekely

  • Guest
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #10 on: November 24, 2015, 12:21:20 pm »
@Juha
I studied the code today and I found the following:
1. The relevant scrolling code it's widgetset dependent
2.  It's located in the following units:

a. Windows(Win32WSForms.pp)
Code: Pascal  [Select][+][-]
  1. function ScrollWindowPtr(hWnd:HWND; XAmount:longint; YAmount:longint; lpRect: pointer; lpClipRect: pointer):WINBOOL; stdcall; external 'user32' name 'ScrollWindow';
  2.  
  3. class procedure TWin32WSScrollingWinControl.ScrollBy(
  4.   const AWinControl: TScrollingWinControl; const DeltaX, DeltaY: integer);
  5. begin
  6.   if Windows.IsWindowVisible(AWinControl.Handle) then
  7.     ScrollWindowPtr(AWinControl.Handle, DeltaX, DeltaY, nil, nil);
  8. end;      
  9.  

 b. Carbon(CarbonWSForms.pp)
Code: Pascal  [Select][+][-]
  1. class procedure TCarbonWSScrollingWinControl.ScrollBy(const AWinControl: TScrollingWinControl; const DeltaX, DeltaY: integer);
  2. begin
  3.   if not CheckHandle(AWinControl, Self, 'ScrollBy') then Exit;
  4.  
  5.   TCarbonWidget(AWinControl.Handle).ScrollBy(DeltaX, DeltaY);
  6.   AWinControl.Invalidate;
  7. end;
  8.  

c. GTK2(GTK2WSForms.pp)
Code: Pascal  [Select][+][-]
  1. class procedure TGtk2WSScrollingWinControl.ScrollBy(
  2.   const AWinControl: TScrollingWinControl; const DeltaX, DeltaY: integer);
  3. var
  4.   Scrolled: PGtkScrolledWindow;
  5.   Adjustment: PGtkAdjustment;
  6.   h, v: Double;
  7.   NewPos: Double;
  8. begin
  9.   if not AWinControl.HandleAllocated then exit;
  10.   Scrolled := GTK_SCROLLED_WINDOW({%H-}Pointer(AWinControl.Handle));
  11.   if not GTK_IS_SCROLLED_WINDOW(Scrolled) then
  12.     exit;
  13.   Adjustment := gtk_scrolled_window_get_hadjustment(Scrolled);
  14.   if Adjustment <> nil then
  15.   begin
  16.     h := gtk_adjustment_get_value(Adjustment);
  17.     NewPos := Adjustment^.upper - Adjustment^.page_size;
  18.     if h - DeltaX <= NewPos then
  19.       NewPos := h - DeltaX;
  20.     gtk_adjustment_set_value(Adjustment, NewPos);
  21.   end;
  22.   Adjustment := gtk_scrolled_window_get_vadjustment(Scrolled);
  23.   if Adjustment <> nil then
  24.   begin
  25.     v := gtk_adjustment_get_value(Adjustment);
  26.     NewPos := Adjustment^.upper - Adjustment^.page_size;
  27.     if v - DeltaY <= NewPos then
  28.       NewPos := v - DeltaY;
  29.     gtk_adjustment_set_value(Adjustment, NewPos);
  30.   end;
  31.   AWinControl.Invalidate;
  32. end;                          
  33.  

d. ...and so on

3. It's triggered from WSForms.pp
4. The code is only implemented for TScrollingWinControl but it also works for TWinControls(TMemo for example), I tested this by moving the relevant code in a separate unit.
5. The implementation would be a non-trivial one,  besides there is a workaround(see above). 



zeljko

  • Hero Member
  • *****
  • Posts: 1770
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #11 on: November 24, 2015, 12:43:52 pm »
GetScrollinfo() ,SetScrollinfo() from lcl winapi does not work ?

No. Actually SetScrollinfo is already called at the end of TControlScrollBar.SetPosition.
Even this does not work :
Code: Pascal  [Select][+][-]
  1. procedure TMemoScrollbar.SetControlPosition;
  2. begin
  3.   if Kind = sbVertical then
  4.     TCustomMemo(FControl).ScrollBy(0, FPosition - FPrevPosition)
  5.   else
  6.     TCustomMemo(FControl).ScrollBy(FPosition - FPrevPosition, 0);
  7. end;
  8.  

This is frustrating. I fail almost always when I try to fix something in LCL. :(
Can you please look at it.

It works with qt-lcl :) Just try example provided with that issue :)

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4599
  • I like bugs.
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #12 on: November 24, 2015, 03:49:38 pm »
It works with qt-lcl :) Just try example provided with that issue :)

It works because SetScrollinfo is called at the end of TControlScrollBar.SetPosition, and for some reason that is enough with QT-LCL.
It is not enough with other widgetsets.

TCustomMemo.ScrollBy is not implemented. Calling it makes no difference. I tried to implement it using the SendMessage() workarounds but they only work on Windows.
According to GetMem the implementation in TScrollingWinControl works also for TWinControl. Maybe there should be a widgetset TScrollingHelper class which is used by TScrollingWinControl and TCustomMemo and maybe others.
Does somebody want to implement it? It is non-trivial yet it is pure refactoring and the chance for success is high.
I can try it later (not now) if nobody else will.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

zeljko

  • Hero Member
  • *****
  • Posts: 1770
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #13 on: November 24, 2015, 04:33:15 pm »
It works with qt-lcl :) Just try example provided with that issue :)

It works because SetScrollinfo is called at the end of TControlScrollBar.SetPosition, and for some reason that is enough with QT-LCL.
It is not enough with other widgetsets.

TCustomMemo.ScrollBy is not implemented. Calling it makes no difference. I tried to implement it using the SendMessage() workarounds but they only work on Windows.
According to GetMem the implementation in TScrollingWinControl works also for TWinControl. Maybe there should be a widgetset TScrollingHelper class which is used by TScrollingWinControl and TCustomMemo and maybe others.
Does somebody want to implement it? It is non-trivial yet it is pure refactoring and the chance for success is high.
I can try it later (not now) if nobody else will.

Maybe just add Scrollby() into widgetset implementation of TWSCustomMemo and fix it inside widgetsets.


JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4599
  • I like bugs.
Re: Setting TMemo.VertScrollBar.Position does not scroll the text field
« Reply #14 on: November 24, 2015, 05:31:03 pm »
Maybe just add Scrollby() into widgetset implementation of TWSCustomMemo and fix it inside widgetsets.

That means duplicating the code. That's why I thought about a helper class. Maybe global functions could be used, too.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

 

TinyPortal © 2005-2018