Recent

Author Topic: Resize  (Read 2391 times)

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Resize
« on: June 25, 2022, 11:43:13 am »
Hello,

probably I am confused how resize works !
here what I see:
In one application of mine I have a lot of graphical elements (3D, chart, XY-plot, etc... all derived by TGrpahicControl) placed on different tabs of a TPageControl.
I noticed, but this seems not happening in the delphi version, that there is a large time-lag in updating the tab content when switching among them (well visible).
After some investigation I have understood that the "resize" is fired for all the graphical elements placed on the application (even regardeless the tab is visible or not and nothing is really "resized"), this causes a lot of repaint of them becaues they have their "resize" procedure implemented that fire the repaint.
Trying to isolate the problem I prepare the code here attached (Self standing compilable), I see the "TXY component" Resize is called not only if the main form is resized bue even if just click on the button (top left on the toolbar) that show the "resize" counter continuosly growing !
I was expecting for TXYcomponent "resize" was fired just if the component change Size, but it seems not the case.
Wath did I miss ?
This justify in LAZ+FPC the time-lag, but I do not understand the meaning of resize

when I run the attache code at first click on the button I see alerdy 5 call to resize ! then for any further click the counter increases by 1

win 10 pro, laz+FPC 2.2.0+3.2.2

Code: Pascal  [Select][+][-]
  1.   TXY = class(TGraphicControl)
  2.   public
  3.     procedure Resize; override;
  4.     procedure Paint; override;
  5.   end;
  6.  
  7.   TForm1 = class(TForm)
  8.     Edit3: TEdit;
  9.     ToolBar21: TToolBar;
  10.     ToolButton4: TToolButton;
  11.     procedure FormCreate(Sender: TObject);
  12.     procedure ToolButton4Click(Sender: TObject);
  13.   private
  14.  
  15.   public
  16.     pippo : TXY;
  17.   end;
  18.  
  19. var
  20.   Form1: TForm1;
  21.   drawcount : integer;
  22.  
  23. implementation
  24.  
  25. {$R *.lfm}
  26.  
  27. { TXY }
  28.  
  29. procedure TXY.Resize;
  30. begin
  31.   inherited Resize;
  32.   beep;  //for "feedback"
  33.   drawcount:=drawcount+1; //counter of resize call
  34. end;
  35.  
  36. procedure TXY.Paint;
  37. begin
  38.   inherited Paint;
  39.   canvas.Brush.Color:=clBlue;
  40.   Canvas.Rectangle(0, 0, width-1, height-1);
  41. end;
  42.  
  43. { TForm1 }
  44.  
  45. procedure TForm1.ToolButton4Click(Sender: TObject);
  46. begin
  47.   edit3.text:=drawcount.tostring;
  48. end;
  49.  
  50. procedure TForm1.FormCreate(Sender: TObject);
  51. begin
  52.   pippo:=TXY.Create(Self);
  53.   Pippo.Parent:=Self;
  54.   pippo.Top:=1;
  55.   pippo.Left:=1;
  56.   pippo.Width:=100;
  57.   pippo.height:=100;
  58.   pippo.Visible:=true;
  59. end;
  60.  
  61. initialization
  62.   drawcount:=0;  //it should be not necessary
  63. end.
  64.  

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #1 on: June 25, 2022, 12:36:34 pm »
just tested my application on
laz-fpc 2.0.12+3.2.0 it is faster, even if coming back on the tab with graphical elements it tooks a lot to be repainted even if it shouldn't repainted at all (nothing is changed), still resize is fired a lot of time!

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Resize
« Reply #2 on: June 25, 2022, 12:58:21 pm »
Putting a breakpoint in your Resize method and calling the stack trace leads me to TWinControl.RealSetText which contains an unconditional call to AdjustSize. In my understanding AdjustSize performs the AutoSize action. Of course, your Edit displaying the counter value has no AutoSize, and I wonder whether there should not be an "if AutoSize then" in front of the AdjustSize. Doing this, in fact, silences the counter.

I am not sure however, whether this is the correct solution since it might have many side-effects.

Since your application seems to be rather complex, I'd ask you to open file "wincontrol.inc" (in (lazarus)/lcl/include), find this procedure and replace the AdjustSize as follows
Code: Pascal  [Select][+][-]
  1. procedure TWinControl.RealSetText(const AValue: TCaption);
  2. ...
  3.     if AutoSize then  // <--- added
  4.       AdjustSize;  
  5. ...
Rebuild the IDE ("Tools" > "Build Lazarus with profile..."). Then test and check whether it solves the issue (it should) and - more importantly - has any sideeffects on toolbars, ChildSizing, anchoring, align etc.

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #3 on: June 25, 2022, 01:52:13 pm »
thanks wp, I'll try as soon as possible your suggestion.
But what is the link between "RealSetText" (of which control in my code ?) and my Resize of TXY class in my code ?
I just perss the toolbutton and I see fired the TXXY.Resize ???

thanks again. (later I'll report if the patch you suggest it is ok or not)

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Resize
« Reply #4 on: June 25, 2022, 02:10:52 pm »
The issue is not in the click, but in the change of the Edit.Text. When you set the Edit.Text to the new value of the resize counter RealSetText is called internally, and this calls AdjustSize which triggers a call to Resize.

As a test, activate a text console (in Windows uncheck "Win32 gui application" in the project options ("Config and Target"), and replace the "edit3.Text := drawcount.toString" by a "WriteLn(drawcount)". You will see that the displayed number in the console does NOT change after clicking.
« Last Edit: June 25, 2022, 02:17:14 pm by wp »

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #5 on: June 25, 2022, 06:37:08 pm »
recompiled lazarus, ma no effects on the code, I did:

locate "wincontrol.inc" (in (lazarus)/lcl/include)
open with text editor,
applied the correction you suggest
Rebuild the IDE ("Tools" > "Build Lazarus with profile : Normal")

but it seems nothing is changed !

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #6 on: June 25, 2022, 07:02:56 pm »
@wp,

Quote
your Edit displaying the counter value has no AutoSize

edit has autosize !

I make Edit3.autosize:=false; and after clicking the button the counter does not inrement.

but in the attached code where I put a TPAgecontrol as per my application I still see the problem

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Resize
« Reply #7 on: June 25, 2022, 07:54:41 pm »
@wp,

Quote
your Edit displaying the counter value has no AutoSize

edit has autosize !
Sorry, I got confused because I did also other tests. Without the modification in the RealGetSize method, the counter incremented even when the form caption was used to display the value rather than the edit.

But that's not the problem...

I did some more tests: Added a TPanel (or a TPaintbox for a TCustomControl) and put your ResizeCounter into the OnResize event. Notice that here the counter does NOT increment! Having this in mind, I used the debugger to step into the inherited Resize instruction of your TXY component; it leads immediately to the inherited TControl.Resize:
Code: Pascal  [Select][+][-]
  1. procedure TControl.Resize;
  2. begin
  3.   if ([csLoading,csDestroying]*ComponentState<>[]) then exit;
  4.   if AutoSizeDelayed then exit;                    // <-------------- Here the procedure is exited.
  5.  
  6.   if (FLastResizeWidth<>Width) or (FLastResizeHeight<>Height)
  7.   or (FLastResizeClientWidth<>ClientWidth)
  8.   or (FLastResizeClientHeight<>ClientHeight) then begin
  9.     {if CompareText('SubPanel',Name)=0 then begin
  10.       DebugLn(['[TControl.Resize] ',Name,':',ClassName,
  11.       ' Last=',FLastResizeWidth,',',FLastResizeHeight,
  12.       ' LastClient=',FLastResizeClientWidth,',',FLastResizeClientHeight,
  13.       ' New=',Width,',',Height,
  14.       ' NewClient=',ClientWidth,',',ClientHeight]);
  15.       DumpStack;
  16.     end;}
  17.     FLastResizeWidth:=Width;
  18.     FLastResizeHeight:=Height;
  19.     FLastResizeClientWidth:=ClientWidth;
  20.     FLastResizeClientHeight:=ClientHeight;
  21.     DoOnResize;
  22.   end;
  23. end;

Stepping through the code line by line, it can be seen that the method is already exited in the 2nd line, "if AutoSizeDelayed then exit". So, the bulk of the method is not executed, it cannot be the cause of your performance issues.

Of course, if your own components implement their own Resize methods this code will be executed, and depending on what it is doing it can cause some noticeable delay. To prevent this you should do the same as TControl.Resize: Put an "if AutoSizedelayed then exit" before your code (AutoSizeDelayed is a public method of TControl and thus accessible to all controls):
Code: Pascal  [Select][+][-]
  1. procedure TXY.Resize;
  2. begin
  3.   inherited;
  4.   if AutoSizeDelayed then exit;
  5.   // here should be your code, e.g. drawcount := drawcount+1;
  6. end;

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #8 on: June 25, 2022, 10:33:10 pm »
thank wp,

tommorow I'll check your suggestion.

have I to remove the previously added line in wincontrol.inc

Code: Pascal  [Select][+][-]
  1. procedure TWinControl.RealSetText(const AValue: TCaption);
  2. ...
  3.     if AutoSize then  // <--- Have I to remove this line ?
  4.       AdjustSize;  
  5. ...

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9791
  • Debugger - SynEdit - and more
    • wiki
Re: Resize
« Reply #9 on: June 25, 2022, 10:34:21 pm »
Are we sure that
Code: Text  [Select][+][-]
  1. TWinControl.RealSetText
is never called for anything that changes it's size, regardless of the "AutoSize" property?

E.g. something like the text on a tab of a pagecontrol? Ok, that would have to lead to wrapping or similar, before it affects other components. And then it might trigger resized via other means.


Anyway, another case.

Put a (or several) label (label.autosize := false)
on a panel (panel.autosize = true)

Enable ChildSizing on the panel
LeftToRight
2 per line
no changes to Enlarge../Shrink...

Changing the label.caption will change the size of the label and panel.
Yes, weird... Should it? No idea... But it does. (Laz 2.3)



AutoSizeDelayed
Afaik that simply means that some outer caller is holding it back, but that when the execution returns to the outer caller it will be run.






Quote
I did some more tests: Added a TPanel (or a TPaintbox for a TCustomControl) and put your ResizeCounter into the OnResize event. Notice that here the counter does NOT increment

Yet, that does not mean that the AutoSize code doesn't run.
In
Code: Pascal  [Select][+][-]
  1. procedure TControl.Resize;
the OnResize event is only called, if the computation of the AutoSize code actually made changes.

Yet of course, you are right, such checks should be done by any inherited code too.
Especially if that inherited code will cause repainting of the control.

Code: Pascal  [Select][+][-]
  1. procedure TControl.Resize;
  2. begin
  3.   if ([csLoading,csDestroying]*ComponentState<>[]) then exit;
  4.   if AutoSizeDelayed then exit;
  5.  
  6.   if (FLastResizeWidth<>Width) or (FLastResizeHeight<>Height)
  7.   or (FLastResizeClientWidth<>ClientWidth)
  8.   or (FLastResizeClientHeight<>ClientHeight) then begin
  9. ..........
  10.     DoOnResize;
  11.   end;
  12. end;
  13.  
« Last Edit: June 25, 2022, 10:40:00 pm by Martin_fr »

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #10 on: June 25, 2022, 10:49:31 pm »
added in the attached code the check on AutosizeDelayed

nothing chenge (click on tab1 and then tab2 and viceversa several times and the resize is fire everytime.

Anyway why "Resize" is fired if no resizing of TXY instance is happening ?

PS: for my issue I see 3 situation (with same code)

1- delphi 10.2, no delay among tbasheet (so very likle no resize is fired)
2- laz+FPC 2.0.12+3.2.0  I see the delay in repainting only moving from "empty" tab to the tab with heavy graphical components (because the "resize" is fired !)
3- laz+FPC 2.2.0+3.2.2 whatever is the tab all the repaint has significant delay (you can sse the content of frirst tab, then some component of nw tab draw on the old tab, finallly the final tab with its compnent, a sort of trasparency effect 1-2 seconds).

the code I have in my application is as per attached reduced program, where obviusly there are not heavy drawing involved for sake semplicity.


wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Resize
« Reply #11 on: June 25, 2022, 11:35:10 pm »
The attached demo contains a pagecontrol with three tabs and 50 labels and 50 edits on page 1 and 2 (each) and 40 labels and 40 comboboxes on page 3. Switching between tabs occurs instantly. This demontrates that the LCL controls do not show this issue.

As I wrote I suspect the slow switching performance is due to your own components. The Resize method is an internal method of a component, and it is the responsibility of the component writer that it is behaving properly.

Looking again at the Resize code, I see other checks which must be passed - e.g. "if FLastResizeWidth <> Width" etc - this means the inner part of Resize is executed only when all these checks are passed. And what is done then? Resize simply calls another method: DoOnResize. This method is executed only when the size has changed. Therefore you should move all your resizing code in your components from Resize to DoOnResize, and leave Resize alone. DoOnResize is virtual, and when you override it you will replace the inherited code. Do call inherited, though, because it fires the event OnResize.
Code: Pascal  [Select][+][-]
  1. procedure TControl.DoOnResize;
  2. begin
  3.   if Assigned(FOnResize) then FOnResize(Self);
  4.   DoCallNotifyHandler(chtOnResize);
  5. end;
« Last Edit: June 25, 2022, 11:38:19 pm by wp »

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #12 on: June 26, 2022, 01:13:58 am »
Quote
This demontrates that the LCL controls do not show this issue.
As I wrote I suspect the slow switching performance is due to your own components

sure, no doubt.

I'll do some test.


Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: Resize
« Reply #13 on: June 26, 2022, 01:18:56 pm »
@wp I did some change, now it works "quickly" after moved the logic in DoOnResize.

It avoids the continous hard-recomputing in the refresh (even if not real resizing is happening, this part for me it is still obscure).

Anyway now I need help in case of real resizing, since in this case I need hard-recomputing, I am looking for something that works "after" resizing is complete (eg when the user resize the form with mouse I would like to do a single Hard-refresh at the end of user interaction).

thank you in advance.
« Last Edit: June 26, 2022, 01:30:50 pm by Paolo »

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Resize
« Reply #14 on: June 26, 2022, 01:37:35 pm »
Anyway now I need help in case of real resizing, since in this case I need hard-recomputing, I am looking for something that works "after" resizing is complete (eg when the user resize the form with mouse I would like to do a single Hard-refresh at the end of user interaction).
Sorry, I don't know in detail what you are talking about. It could also be that you are trying to reinvent the wheel because the LCL can handle a lot of sizing issues amazingly well (anchoring, auto-sizing, ... - that's why the sizing code is so complex). Please read https://wiki.freepascal.org/Autosize_/_Layout#Custom_Controls.

 

TinyPortal © 2005-2018