View Issue Details

IDProjectCategoryView StatusLast Update
0010091LazarusLCLpublic2009-06-13 12:08
ReporterBoguslaw BrandysAssigned ToBoguslaw Brandys 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformWin32OSWindowsOS Version32bit
Product Version0.9.23 (SVN)Product Buildrev 12682 
Target Version1.0.0Fixed in Version0.9.27 (SVN) 
Summary0010091: TScrollBox.AutoScroll and scrolling is not possible
DescriptionScrolling TScrollBox is not possible now when AutoScroll := true
Scrollbox area jumps a little and then all window freeze (the only way is to wait or switch focus to another application and back to unfreeze)
TScrollBox.Range is calculated on each click on scrollbar !
Additional InformationAttached is proposition of patch which simplifies scrolling a lot in TScrollinWinControl.It must be heavy tested.I found two problems with that patch:

1.When controls placed on TScrollBox and aligned , they are scrolled down instead of up (I feel that it was caused by changes done 2007-11-01)
2. When TScrollBox is scrolled a little and then parent window is resized - controls placed on scrollbox are a little moved

TagsNo tags attached.
Fixed in Revision17085
LazTarget1.0
WidgetsetWin32/Win64
Attached Files
  • patch.diff (5,453 bytes)
    Index: lcl/forms.pp
    ===================================================================
    --- lcl/forms.pp	(revision 12682)
    +++ lcl/forms.pp	(working copy)
    @@ -89,8 +89,6 @@
         FRange: Integer;
         FSmooth : Boolean;
         FVisible: Boolean;
    -    FOldScrollInfo: TScrollInfo;
    -    FOldScrollInfoValid: Boolean;
       protected
         FControl: TWinControl;
         function ControlAutoScroll: boolean; virtual;
    @@ -116,7 +114,6 @@
         procedure SetSmooth(const Value: Boolean); virtual;
         procedure SetVisible(const Value: Boolean); virtual;
         procedure UpdateScrollBar; virtual;
    -    procedure InvalidateScollInfo;
       {$ifdef VerboseScrollingWinControl}
         function DebugCondition: Boolean;
       {$endif}
    @@ -1821,3 +1818,6 @@
     
     
     
    +
    +
    +
    Index: lcl/include/controlscrollbar.inc
    ===================================================================
    --- lcl/include/controlscrollbar.inc	(revision 12682)
    +++ lcl/include/controlscrollbar.inc	(working copy)
    @@ -68,13 +68,10 @@
       // scroll content of FControl
       OldPosition := FPosition;
       FPosition := Value;
    -  if FControl is TScrollingWinControl then
    -    TScrollingWinControl(FControl).ScrollbarHandler(Kind, OldPosition);
     
       // check that the new position is also set on the scrollbar
       if HandleAllocated and (GetScrollPos(ControlHandle, IntfBarKind[Kind]) <> FPosition) then
       begin
    -    InvalidateScollInfo;
         {$IFDEF VerboseScrollingWinControl}
         if DebugCondition then
           DebugLn(['TControlScrollBar.SetPosition FPosition=',FPosition]);
    @@ -82,6 +79,13 @@
         // send position to interface and store it back to FPosition (this way LCL will have actual position value)
         FPosition := SetScrollPos(ControlHandle, IntfBarKind[Kind], FPosition, Visible);
       end;
    +  
    +  if OldPosition = FPosition then Exit;
    +
    +
    +  if (FControl is TScrollingWinControl)  then
    +    TScrollingWinControl(FControl).ScrollbarHandler(Kind, OldPosition);
    +  
     end;
     
     function TControlScrollBar.SmoothIsStored: boolean;
    @@ -102,7 +106,6 @@
       begin
         ScrollInfo.fMask := SIF_PAGE;
         GetScrollInfo(ControlHandle, IntfBarKind[Kind], ScrollInfo);
    -    InvalidateScollInfo;
         FPage := ScrollInfo.nPage;
       end;
       Result := FPage;
    @@ -116,7 +119,6 @@
       begin
         ScrollInfo.fMask := SIF_POS;
         GetScrollInfo(ControlHandle, IntfBarKind[Kind], ScrollInfo);
    -    InvalidateScollInfo;
         FPosition := ScrollInfo.nPos;
       end;
       Result := FPosition;
    @@ -130,7 +132,6 @@
       begin
         ScrollInfo.fMask := SIF_Range + SIF_Page;
         GetScrollInfo(ControlHandle, IntfBarKind[Kind], ScrollInfo);
    -    InvalidateScollInfo;
         FRange := ScrollInfo.nMax - ScrollInfo.nMin - integer(ScrollInfo.nPage);
       end;
       Result := FRange;
    @@ -144,10 +145,7 @@
     function TControlScrollBar.GetVisible: Boolean;
     begin
       if HandleAllocated and (not (FControl is TScrollingWinControl)) then
    -  begin
    -    InvalidateScollInfo;
         FVisible := GetScrollbarVisible(Controlhandle, IntfBarKind[Kind]);
    -  end;
       Result := FVisible;
     end;
     
    @@ -178,10 +176,8 @@
       else
         KindID := SM_CXVSCROLL;
       if HandleAllocated then
    -  begin
    -    Result := LCLIntf.GetScrollBarSize(ControlHandle,KindID);
    -    InvalidateScollInfo;
    -  end else
    +    Result := LCLIntf.GetScrollBarSize(ControlHandle,KindID)
    +  else
         Result := GetSystemMetrics(KindID);
     end;
     
    @@ -295,12 +291,8 @@
         ScrollInfo.nPos := FPosition;
         ScrollInfo.nPage := FPage;
         ScrollInfo.nTrackPos := FPosition;
    -    if (not FOldScrollInfoValid) or (not CompareMem(@ScrollInfo,@FOldScrollInfo,SizeOf(TScrollInfo))) then
    -    begin
    -      FOldScrollInfo:=ScrollInfo;
    -      FOldScrollInfoValid := true;
    -      SetScrollInfo(FControl.Handle, IntfBarKind[Kind], ScrollInfo, FVisible);
    -    end;
    +    SetScrollInfo(FControl.Handle, IntfBarKind[Kind], ScrollInfo, FVisible);
    +
         {$IFDEF VerboseScrollingWinControl}
         if DebugCondition then
           DebugLn(['TControlScrollBar.UpdateScrollBar ',DbgSName(FControl),' ',DbgSName(Self),' FVisible=',FVisible,' Range=',FRange,' FPosition=',FPosition,' FPage=',FPage,' FAutoRange=',FAutoRange]);
    @@ -318,10 +310,6 @@
       end;
     end;
     
    -procedure TControlScrollBar.InvalidateScollInfo;
    -begin
    -  FOldScrollInfoValid:=false;
    -end;
     
     {$ifdef VerboseScrollingWinControl}
     function TControlScrollBar.DebugCondition: Boolean;
    @@ -372,7 +360,6 @@
         NewPos := 0;
       if NewPos > FRange then
         NewPos := FRange;
    -  InvalidateScollInfo;
       SetPosition(NewPos);
     end;
     
    Index: lcl/include/scrollingwincontrol.inc
    ===================================================================
    --- lcl/include/scrollingwincontrol.inc	(revision 12682)
    +++ lcl/include/scrollingwincontrol.inc	(working copy)
    @@ -52,20 +52,25 @@
     procedure TScrollingWinControl.AlignControls(AControl: TControl;
       var ARect: TRect);
     begin
    +  inherited AlignControls(AControl, ARect);
       if (HorzScrollBar=nil) or (VertScrollBar=nil) then exit;
    -  inherited AlignControls(AControl, ARect);
    -  HorzScrollBar.AutoCalcRange;
    -  VertScrollBar.AutoCalcRange;
       if not AutoScroll then
         UpdateScrollBars;
    +
     end;
     
     procedure TScrollingWinControl.DoOnResize;
     begin
       inherited DoOnResize;
    +  if (HorzScrollBar=nil) or (VertScrollBar=nil) then exit;
       if AutoScroll or HorzScrollBar.Visible or VertScrollBar.Visible
       then
    +  begin
    +    HorzScrollBar.AutoCalcRange;
    +    VertScrollBar.AutoCalcRange;
         UpdateScrollBars;
    +  end;
    +
     end;
     
     class function TScrollingWinControl.GetControlClassDefaultSize: TPoint;
    
    patch.diff (5,453 bytes)
  • testcase.zip (2,856 bytes)

Relationships

related to 0010188 closedPaul Ishenin ScrollBox scrolls backwards 

Activities

2007-11-01 22:54

 

patch.diff (5,453 bytes)
Index: lcl/forms.pp
===================================================================
--- lcl/forms.pp	(revision 12682)
+++ lcl/forms.pp	(working copy)
@@ -89,8 +89,6 @@
     FRange: Integer;
     FSmooth : Boolean;
     FVisible: Boolean;
-    FOldScrollInfo: TScrollInfo;
-    FOldScrollInfoValid: Boolean;
   protected
     FControl: TWinControl;
     function ControlAutoScroll: boolean; virtual;
@@ -116,7 +114,6 @@
     procedure SetSmooth(const Value: Boolean); virtual;
     procedure SetVisible(const Value: Boolean); virtual;
     procedure UpdateScrollBar; virtual;
-    procedure InvalidateScollInfo;
   {$ifdef VerboseScrollingWinControl}
     function DebugCondition: Boolean;
   {$endif}
@@ -1821,3 +1818,6 @@
 
 
 
+
+
+
Index: lcl/include/controlscrollbar.inc
===================================================================
--- lcl/include/controlscrollbar.inc	(revision 12682)
+++ lcl/include/controlscrollbar.inc	(working copy)
@@ -68,13 +68,10 @@
   // scroll content of FControl
   OldPosition := FPosition;
   FPosition := Value;
-  if FControl is TScrollingWinControl then
-    TScrollingWinControl(FControl).ScrollbarHandler(Kind, OldPosition);
 
   // check that the new position is also set on the scrollbar
   if HandleAllocated and (GetScrollPos(ControlHandle, IntfBarKind[Kind]) <> FPosition) then
   begin
-    InvalidateScollInfo;
     {$IFDEF VerboseScrollingWinControl}
     if DebugCondition then
       DebugLn(['TControlScrollBar.SetPosition FPosition=',FPosition]);
@@ -82,6 +79,13 @@
     // send position to interface and store it back to FPosition (this way LCL will have actual position value)
     FPosition := SetScrollPos(ControlHandle, IntfBarKind[Kind], FPosition, Visible);
   end;
+  
+  if OldPosition = FPosition then Exit;
+
+
+  if (FControl is TScrollingWinControl)  then
+    TScrollingWinControl(FControl).ScrollbarHandler(Kind, OldPosition);
+  
 end;
 
 function TControlScrollBar.SmoothIsStored: boolean;
@@ -102,7 +106,6 @@
   begin
     ScrollInfo.fMask := SIF_PAGE;
     GetScrollInfo(ControlHandle, IntfBarKind[Kind], ScrollInfo);
-    InvalidateScollInfo;
     FPage := ScrollInfo.nPage;
   end;
   Result := FPage;
@@ -116,7 +119,6 @@
   begin
     ScrollInfo.fMask := SIF_POS;
     GetScrollInfo(ControlHandle, IntfBarKind[Kind], ScrollInfo);
-    InvalidateScollInfo;
     FPosition := ScrollInfo.nPos;
   end;
   Result := FPosition;
@@ -130,7 +132,6 @@
   begin
     ScrollInfo.fMask := SIF_Range + SIF_Page;
     GetScrollInfo(ControlHandle, IntfBarKind[Kind], ScrollInfo);
-    InvalidateScollInfo;
     FRange := ScrollInfo.nMax - ScrollInfo.nMin - integer(ScrollInfo.nPage);
   end;
   Result := FRange;
@@ -144,10 +145,7 @@
 function TControlScrollBar.GetVisible: Boolean;
 begin
   if HandleAllocated and (not (FControl is TScrollingWinControl)) then
-  begin
-    InvalidateScollInfo;
     FVisible := GetScrollbarVisible(Controlhandle, IntfBarKind[Kind]);
-  end;
   Result := FVisible;
 end;
 
@@ -178,10 +176,8 @@
   else
     KindID := SM_CXVSCROLL;
   if HandleAllocated then
-  begin
-    Result := LCLIntf.GetScrollBarSize(ControlHandle,KindID);
-    InvalidateScollInfo;
-  end else
+    Result := LCLIntf.GetScrollBarSize(ControlHandle,KindID)
+  else
     Result := GetSystemMetrics(KindID);
 end;
 
@@ -295,12 +291,8 @@
     ScrollInfo.nPos := FPosition;
     ScrollInfo.nPage := FPage;
     ScrollInfo.nTrackPos := FPosition;
-    if (not FOldScrollInfoValid) or (not CompareMem(@ScrollInfo,@FOldScrollInfo,SizeOf(TScrollInfo))) then
-    begin
-      FOldScrollInfo:=ScrollInfo;
-      FOldScrollInfoValid := true;
-      SetScrollInfo(FControl.Handle, IntfBarKind[Kind], ScrollInfo, FVisible);
-    end;
+    SetScrollInfo(FControl.Handle, IntfBarKind[Kind], ScrollInfo, FVisible);
+
     {$IFDEF VerboseScrollingWinControl}
     if DebugCondition then
       DebugLn(['TControlScrollBar.UpdateScrollBar ',DbgSName(FControl),' ',DbgSName(Self),' FVisible=',FVisible,' Range=',FRange,' FPosition=',FPosition,' FPage=',FPage,' FAutoRange=',FAutoRange]);
@@ -318,10 +310,6 @@
   end;
 end;
 
-procedure TControlScrollBar.InvalidateScollInfo;
-begin
-  FOldScrollInfoValid:=false;
-end;
 
 {$ifdef VerboseScrollingWinControl}
 function TControlScrollBar.DebugCondition: Boolean;
@@ -372,7 +360,6 @@
     NewPos := 0;
   if NewPos > FRange then
     NewPos := FRange;
-  InvalidateScollInfo;
   SetPosition(NewPos);
 end;
 
Index: lcl/include/scrollingwincontrol.inc
===================================================================
--- lcl/include/scrollingwincontrol.inc	(revision 12682)
+++ lcl/include/scrollingwincontrol.inc	(working copy)
@@ -52,20 +52,25 @@
 procedure TScrollingWinControl.AlignControls(AControl: TControl;
   var ARect: TRect);
 begin
+  inherited AlignControls(AControl, ARect);
   if (HorzScrollBar=nil) or (VertScrollBar=nil) then exit;
-  inherited AlignControls(AControl, ARect);
-  HorzScrollBar.AutoCalcRange;
-  VertScrollBar.AutoCalcRange;
   if not AutoScroll then
     UpdateScrollBars;
+
 end;
 
 procedure TScrollingWinControl.DoOnResize;
 begin
   inherited DoOnResize;
+  if (HorzScrollBar=nil) or (VertScrollBar=nil) then exit;
   if AutoScroll or HorzScrollBar.Visible or VertScrollBar.Visible
   then
+  begin
+    HorzScrollBar.AutoCalcRange;
+    VertScrollBar.AutoCalcRange;
     UpdateScrollBars;
+  end;
+
 end;
 
 class function TScrollingWinControl.GetControlClassDefaultSize: TPoint;
patch.diff (5,453 bytes)

Boguslaw Brandys

2007-11-02 12:21

developer   ~0015892

Patch works nice when all controls placed on TScrollBox are not anchored or aligned.In case when one of them is anchored or aligned (for example alTop) all scrollbox area is moving down instead of up.

Boguslaw Brandys

2007-11-02 12:22

developer   ~0015893

Changes done in revision 12678 to TControlScrollBar.AutoCalcRange are not changing anything - it works the same with and without those restrictions

2007-11-02 12:24

 

testcase.zip (2,856 bytes)

Boguslaw Brandys

2007-11-02 12:24

developer   ~0015894

Testcase (sample project) uploaded

Mattias Gaertner

2007-11-02 12:45

manager   ~0015895

Main problem is win32 intf still moves the childs instead of moving the client area like all other widgetsets. So when the win32 'scrolls' the childs, the LCL will apply the anchoring/aligning undoing the change.
It is planned to change the win32 implementation.

Boguslaw Brandys

2007-11-02 13:57

developer   ~0015896

Win32 implementation is fine, it is using ScrollWindow to scroll client area as far as I know. Just in AlignControls there is no check if parent is TScrollingWincontrol and children are allowed to be realigned and anchored.It is not needed once parent is TScrollingWincontrol and Range > 0 because scrollbars appear to scroll that area.

Mattias Gaertner

2007-11-02 14:10

manager   ~0015897

AlignControls must work with Range>0.
The way win32 scrolls is not portable and makes anchoring unnecessary difficult.

Vincent Snijders

2008-03-09 23:14

manager   ~0018261

See also:
http://wiki.lazarus.freepascal.org/Win32/64_Interface#Scrolling

Boguslaw Brandys

2008-10-24 21:36

developer   ~0022941

Revision 17085, scrolling looks fine now, except a lot of flicker and some flicker when clicking on thumb when it has max or min value which maybe related to other not resolved problems with TScrollBox.
I don't know if TScrollBox.Range is still calculated many times but scrolling is nice and do not freeze.

Boguslaw Brandys

2008-10-24 21:50

developer   ~0022942

There are other problems but with TScrollBox.AutoScroll:=false so new bugreport should be created.This one seems resolved.

Boguslaw Brandys

2008-10-24 21:54

developer   ~0022943

No more freezing.Probably fixed in meantime.

Issue History

Date Modified Username Field Change
2007-11-01 22:54 Boguslaw Brandys New Issue
2007-11-01 22:54 Boguslaw Brandys Status new => assigned
2007-11-01 22:54 Boguslaw Brandys Assigned To => Boguslaw Brandys
2007-11-01 22:54 Boguslaw Brandys File Added: patch.diff
2007-11-01 22:54 Boguslaw Brandys LazTarget => -
2007-11-01 22:54 Boguslaw Brandys Widgetset => Win32
2007-11-02 12:21 Boguslaw Brandys Note Added: 0015892
2007-11-02 12:22 Boguslaw Brandys Note Added: 0015893
2007-11-02 12:24 Boguslaw Brandys File Added: testcase.zip
2007-11-02 12:24 Boguslaw Brandys Note Added: 0015894
2007-11-02 12:45 Mattias Gaertner Note Added: 0015895
2007-11-02 13:57 Boguslaw Brandys Note Added: 0015896
2007-11-02 14:10 Mattias Gaertner Note Added: 0015897
2008-03-09 23:14 Vincent Snijders Note Added: 0018261
2008-03-09 23:15 Vincent Snijders Relationship added related to 0010188
2008-03-09 23:16 Vincent Snijders LazTarget - => 1.0
2008-04-24 09:57 Vincent Snijders Target Version => 1.0.0
2008-10-24 21:21 Boguslaw Brandys Assigned To Boguslaw Brandys =>
2008-10-24 21:36 Boguslaw Brandys Note Added: 0022941
2008-10-24 21:50 Boguslaw Brandys Note Added: 0022942
2008-10-24 21:54 Boguslaw Brandys Fixed in Revision => 17085
2008-10-24 21:54 Boguslaw Brandys Status assigned => resolved
2008-10-24 21:54 Boguslaw Brandys Fixed in Version => 0.9.27 (SVN)
2008-10-24 21:54 Boguslaw Brandys Resolution open => fixed
2008-10-24 21:54 Boguslaw Brandys Assigned To => Boguslaw Brandys
2008-10-24 21:54 Boguslaw Brandys Note Added: 0022943
2009-06-13 12:08 Marc Weustink Status resolved => closed