Jump to content
Sign in to follow this  
IElite

Resize method called 3 times ?

Recommended Posts

I have a custom control and When I run my application, I noticed through some debugging that the Resize of this control is method is called three times.

procedure TTestCtrl.Resize;
begin
 inherited;
 if  (Handle.Valid and (csReady in ComponentState)) then
  DoSomething;
end;

Here is an external test I did

type
  TForm1 = class(TW3Form)
  private
    {$I 'Form1:intf'}
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  public
    procedure DoSomething;
  end;

implementation

var
 count: integer = 1;

{ TForm1 }

procedure TForm1.DoSomething;
begin
 ShowMessage(inttostr(count));
 inc(count);
end;

procedure TForm1.Resize;
begin
  inherited;
  if  (Handle.Valid and (csReady in ComponentState)) then
   DoSomething;
end;

Question 1: Why is it called three times and where?

Question 2: How can I call my method inside the Resize method only at the last time resize for that control is called?

 

 

Share this post


Link to post
Share on other sites

The multiple calls to ReSize have been a 'feature' from the beginning, but I don't know exactly why this happens.

The Smart Mobile Studio release page (https://smartmobilestudio.com/category/news/) says : 

28.9.2017 :

Improvements to Resizing:
– Minimize number of resizes during form create.
– Trigger only one resize during device flip.

so obviously there can be multiple resize events on startup. 

Not sure what your business case is here, but personally I use ReSize mainly for device flip purposes.

If your purpose is to DoSomething after an element or a form has been completely initialised in the DOM, you could use ReadyExecute

  Handle.ReadyExecute( procedure ()
  begin
    DoSomething;
  end);

or even when it involves doing this on a repaint

  Handle.ReadyExecute( Procedure ()
    begin
      BrowserAPI.window.requestAnimationFrame( procedure ()
      Begin
        DoSomething;
      end);
    end);

not in the ReSize proc but in the control setup

 

Share this post


Link to post
Share on other sites

In versions before 3.0 alpha, there were a lot of resizes. If I remember right, something like closer to 10 before the form was shown. Flipping the device also resulted in two resizes: One, when the width was changed and one when the height was changed. Also, every BeginUpdate/EndUpdate used to cause a resize (regardless if anything was changed) and if you peek at SmartCL.Controls.pas, they are used a lot.

For 3.0 alpha I did my best to eliminate all that were safe to be eliminated. So, the device flip causes only one resize, for example.

At the moment the RTL mostly internally calls ResizeWhenReady, which checks to see if the control and all its children are ready: If not, the resize will be delayed and sent later. Also, invalidate does call ResizeWhenReady with a delay. So if you call invalidate for a control 5 times, you will only get one resize.

I don't know if I can eliminate more resizes safely, but I can have a look.

Share this post


Link to post
Share on other sites

@jarto

Maybe the changes you made have affected something else, and affected what I am trying do do now. 

I wanted to be sure of this, so I created a new demo project to see if it would occur in the new demo like it does in my project, and it does.

See the attached project

There are two forms. Each form has 3 controls on it and uses a Layout to arrange them on each of the forms.

The first form creates a top, center, and bottom control and arranges them respectively.

The second form creates a Left, Center, and Right control and arranges them respectively. 

The first form displays correctly. When I navigate to the second form, it does not arrange correctly. The center control is not where it should be.

If I navigate back to the first form, it again displays correctly. When I navigate to the second form again....this time, it displays correctly.

Please see the attached project.

Clicking on any of the controls will navigate you to the next form.

 

 

ResizeDemo.zip

Share this post


Link to post
Share on other sites

@lynkfs  your code worked for that simple demo - It actually worked as I expect. But when I tried it in my actual application. It did not. My application has a layout that lays out (arranges) controls like the demo here, but then I have controls inside those controls and each of those controls have layouts to layout the child controls. And your code doesn't fix them all.  I know all my layouts work because if I just display the form as the first form in my application and I dont do any navigating back and fourth to other forms., it displays fine. It seems to be only an issue when i move from another form to this form using form navigation (Application.GoToForm()).... which I then believe becomes a resize issue during form activation or somewhere else.  Anyways, thanks for looking!

      //create the main layout
  fLayout:= Layout.Client(
    [Layout.Top(Layout.Height(100).Margins(50,10,50,0), fHeader),
     Layout.Top(Layout.Height(50).Margins(50,10,50,0), fScoreBoard),
     Layout.Client(Layout.Margins(50,10,50,0), fBody),
     Layout.Bottom(Layout.Height(50).Margins(50,10,50,10), fFooter),
     Layout.Bottom(Layout.Height(50).Margins(50,10,50,0), fNavigationButtons)
    ]);

  //create the header layout
  fHeaderLayout:= Layout.Client(Layout.Margins(10), fHeaderLabel);

  //create the scoreboard layout
 fScoreboardLayout:= Layout.Client([{Layout.Center(Layout.Margins(0,1,0,1), fScoreBoardButton),}
                                    Layout.Left(Layout.Margins(5,0,5,0), fScoreBoardTimeLabel),
                                    Layout.Right(Layout.Margins(5,0,5,0),fScoreBoardScoreLabel)]);
  //create the body layout
  fBodyLayout:= Layout.Client([Layout.Top(Layout.Height(100).Margins(5,5,5,0), fBodyQuestion),
                               Layout.Bottom(Layout.Height(200), Layout.Center(Layout.Margins(0,0,0,50), fBodyAnswers))]);
  //create the buttons layout
  fButtonsLayout:= Layout.Client(Layout.Right(Layout.Margins(0,1,2,1).Spacing(2), [fNavigationButtonsBack, fNavigationButtonsNext]));
  //create the footer layout
  fFooterLayout:= Layout.Client(Layout.Margins(5), fFooterLabel);

 

Share this post


Link to post
Share on other sites

Using the Resize Demo, I removed the Layouts and used strictly setBounds to position everything and it seems to work just fine

see attached demo

So,it seems to be just a resize issue when using layouts and form navigation

I am going to see about replacing all my layouts with setBounds in my application and see if it works there too

ResizeDemo.zip

Share this post


Link to post
Share on other sites

@IElite I am having a look at this. Every time the layout is wrong, it's because an exception happened during the layout. And the exceptions basically happen due to the assert-checks inside the layout code.

This is not my code so it takes some more time for me to figure things out. My gut feeling here is that when an exception happens due to asserts, we should schedule a new resize instead of quietly giving up.

Share this post


Link to post
Share on other sites

@IElite Can you check if these changes to SmartCL.Layout.pas help with your more complex application:

  1. Uncomment the raise on line 739
  2. Change the TLayoutImpl.Resize -procedure on line 751 to:
procedure TLayoutImpl.Resize(container: TW3CustomControl);
begin
  try
    LoggedResize(container);
  except
    TW3Dispatch.Execute( procedure
      begin
        try
          LoggedResize(container);
        except
        end;
      end,60);
  end;
end;

 

Share this post


Link to post
Share on other sites

Oops, sorry,  i forgot i had invalidate in the forms onActivated. If I remove this, then your change does not work

 

procedure TQuizFrm.FormActivated;
begin
 inherited;
 invalidate;
end;

 

Share this post


Link to post
Share on other sites

I dug deeper into the Layout code and it seems there's a bug in how bottom alignment is done. The code sets the bottom coordinate, which leads to the code to calculate top based on the current component height. However, the current component height at that point is still the default height right after create, so the top coordinate is calculated wrong. Height is set after that, but it does not adjust top accordingly.

A second resize helps as at that point the bottom component is already of the right height.

Share this post


Link to post
Share on other sites

@jarto - Yes, that seems to fix any issues that existed in my application....and I use a good number of layous on each form.

e.g.

 fLayout:= Layout.Client(
    [Layout.Top(Layout.Height(100).Margins(50,10,50,0), fHeader),
     Layout.Top(Layout.Height(50).Margins(50,10,50,0), fScoreBoard),
     Layout.Client(Layout.Margins(50,10,50,0), fBody),
     Layout.Bottom(Layout.Height(50).Margins(50,10,50,10), fFooter),
     Layout.Bottom(Layout.Height(50).Margins(50,10,50,0), fNavigationButtons)
    ]);

  //create the header layout
  fHeaderLayout:= Layout.Client(Layout.Margins(10), fHeaderLabel);

  //create the scoreboard layout
 fScoreboardLayout:= Layout.Client([{Layout.Center(Layout.Margins(0,1,0,1), fScoreBoardButton),}
                                    Layout.Left(Layout.Margins(5,0,5,0), fScoreBoardTimeLabel),
                                    Layout.Right(Layout.Margins(5,0,5,0),fScoreBoardScoreLabel)]);
  //create the body layout
  fBodyLayout:= Layout.Client([Layout.Top(Layout.Height(100).Margins(5,5,5,0), fBodyQuestion),
                               Layout.Bottom(Layout.Height(200), Layout.Center(Layout.Margins(0,0,0,50), fBodyAnswers))]);
  //create the buttons layout
  fButtonsLayout:= Layout.Client(Layout.Right(Layout.Margins(0,1,2,1).Spacing(2), [fNavigationButtonsBack, fNavigationButtonsNext]));
  //create the footer layout
  fFooterLayout:= Layout.Client(Layout.Margins(5), fFooterLabel);

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×