Jump to content
pieomy

Delphi Rio Android application.processMessages; dosent work

Recommended Posts

Hi,

 

Delphi Rio Android application.processMessages; dosent work.

  ProgressBar1.Value:=0;
  ProgressBar1.Max:=100;

  for I := 0 to 100 do
  begin
    ProgressBar1.Value:=I;
    application.ProcessMessages;
    sleep(100);
  end;

 

trying this but progressbar not update position.

 

any alternative way?

Share this post


Link to post
Posted (edited)

I think you need to add a call to ProgressBar1.Repaint inside the loop.

Edited by DelphiMT
grammer

Share this post


Link to post
Posted (edited)

This is definitely not the right way to write code.  Avoid ProcessMessages() whenever possible.  The example given can be replaced with a simple UI Timer instead, eg:

 

ProgressBar1.Value : =0;
ProgressBar1.Max := 100;
Timer1.Enabled := True;

...

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  ProgressBar1.Value := ProgressBar1.Value + 1;
  if ProgressBar1.Value >= ProgressBar1.Max then
  begin
    Timer1.Enabled := True;
    Exit;
  end;
  //...
end;

But, if your real project is using the ProgressBar to tracking status of actual tasks, those tasks should be done in the background, and updates to the UI synced with the main UI thread accordingly.

Edited by Remy Lebeau
  • Like 2

Share this post


Link to post

Thanks for all answers, this is simple example but I dont need only progressbar, Im using application.processmessages; a lot of procedure already. Before Rio all was good for me but on Rio I have to many problems, I can not convert all application.processmessages to timer or thread need to alternative way if have.

 

another example; on start procedure Im changing TabControl1 page (TabControl1.TabIndex:=1;) but page change after procedure completed. it didn't work like that before Rio.

 

 

 

Share this post


Link to post
Posted (edited)
59 minutes ago, pieomy said:

Thanks for all answers, this is simple example but I dont need only progressbar, Im using application.processmessages; a lot of procedure already.

Well, then you went down the wrong rabbit hole, and you need to start climbing your way out of it.

Quote

Before Rio all was good for me but on Rio I have to many problems

Such as?

Quote

I can not convert all application.processmessages to timer or thread need to alternative way if have.

You really need to stop using ProcessMessages(), and start using proper code designs.  Even if you don't want to use timers/threads, there is always TThread.ForceQueue(), for instance.  Anything that allows code flow to return to the main UI message loop naturally will be better than manually pumping the message queue artificially.

Quote

another example; on start procedure Im changing TabControl1 page (TabControl1.TabIndex:=1;) but page change after procedure completed. it didn't work like that before Rio.

Then file a bug report with Embarcadero.  But don't litter your code with ProcessMessages() calls just to satisfy the framework.  Find other alternatives.  Stay away from ProcessMessages() whenever possible.  That was true even in the old days of the VCL.  More so now in the days of FMX on mobile.

Edited by Remy Lebeau
  • Like 3
  • Thanks 1

Share this post


Link to post

@Remy Lebeau, thank you for interest

I hope I can explain my problem

Left gif from Tokyo, right gif from Rio

 

on Rio application full freeze, I wanna run this procedure like tokyo 

   

tokyo.thumb.gif.b29ba6f83dafb3386ce20b4bb41fae61.gif            rio.thumb.gif.62cb1e6f6c3369403e4e5ab45b0acd2e.gif

 

Button Click;

procedure TForm2.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  TabControl1.TabIndex:=1;
  application.ProcessMessages;

  ProgressBar1.Max:=100;
  ProgressBar1.Value:=0;

  for I := 0 to 10 do
  begin
    application.ProcessMessages;
    ProgressBar1.Value:=(I*10);
    sleep(500);
  end;

end;

 

Share this post


Link to post
19 hours ago, Remy Lebeau said:

This is definitely not the right way to write code.  Avoid ProcessMessages() whenever possible.  The example given can be replaced with a simple UI Timer instead, eg:

 


ProgressBar1.Value : =0;
ProgressBar1.Max := 100;
Timer1.Enabled := True;

...

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  ProgressBar1.Value := ProgressBar1.Value + 1;
  if ProgressBar1.Value >= ProgressBar1.Max then
  begin
    Timer1.Enabled := True;
    Exit;
  end;
  //...
end;

But, if your real project is using the ProgressBar to tracking status of actual tasks, those tasks should be done in the background, and updates to the UI synced with the main UI thread accordingly.

 

Remy,

 

shouldn't it be Timer1.Enabled := False; in Timer1Timer?

 

Otherwise, I do not understand how this code works. Example has been very helpful as I did it wrong as well so far!

Share this post


Link to post
6 hours ago, pieomy said:

@Remy Lebeau, thank you for interest

I hope I can explain my problem

Since you are developing for mobile.  DO NOT run blocking tasks in the main UI thread, it must service only the UI.  Long-running tasks must be done in the background instead.  In your case, you have a LONG-running task (5.5 seconds) that blocks the UI until the task is finished.  Tokyo let you get away with it using a hack.  Rio doesn't.  So just don't do it anymore. 

6 hours ago, pieomy said:

on Rio application full freeze, I wanna run this procedure like tokyo 

You need to change the code (even for Tokyo) to work with the main UI thread correctly, stay away from ProcessMessages() at all costs (especially now that Embarcadero has broken it and doesn't want to fix it).  Do things asynchronously so flow returns to the main UI message loop in a timely manner (otherwise Android is likely to kill your app!).

 

For example:

procedure TForm2.Button1Click(Sender: TObject);
var
  StartTimer: TProc;
begin
  ProgressBar1.Max := 100;
  ProgressBar1.Value := 0;

  StartTimer := procedure
  begin
    Timer1.Interval := 500; // <-- can be set at design-time
    Timer1.Enabled := True;
  end;

  {$IF CompilerVersion < 33}
  // 10.2 Tokyo or earlier
  TabControl1.TabIndex := 1;
  StartTimer;
  {$ELSE}
  // 10.3 Rio or later
  TabControl1.SetActiveTabWithTransitionAsync(TabControl1.Tabs[1], TTabTransition.None, TTabTransitionDirection.Normal, StartTimer);
  {$IFEND}
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  ProgressBar1.Value := ProgressBar1.Value + 10;
  if ProgressBar1.Value >= ProgressBar1.Max then
    Timer1.Enabled := False;
end;
6 hours ago, Holger Flick said:

shouldn't it be Timer1.Enabled := False; in Timer1Timer?

Yes, sorry about that.  Fixed above.

6 hours ago, Holger Flick said:

Otherwise, I do not understand how this code works.

What is there not to understand?  The TTabControl is transitioned to the desired Tab and a timer is started, then flow is returned to the main UI message loop.  When the timer fires after 500ms, the ProgressBar is incremented and flow is returned to the main UI message loop.  The timer fires again after another 500ms, and again, each time returning to the main UI message loop.  Eventually, the ProgressBar reaches its Max and the timer is stopped.

  • Like 1

Share this post


Link to post

Thanks Remy.
I was always hesitating to use the "Transition" animations, because I never can be 100% sure where it may use Application.ProcessMessages internally.

There are a lot of places where this is maybe used, and only by digging deep inside the sources I can check it out, but I'm never sure on what happens in future versions.

  procedure AnimateControlPositionXWait(AParent: TFmxObject; const NewValue: Integer);
  var
    A: TIntAnimation;
  begin
    TAnimator.StopPropertyAnimation(AParent, 'Position.X');

    A := TIntAnimation.Create(AParent);
    try
      A.Parent := AParent;
      A.AnimationType := DefaultSlidingAnimationType;
      A.Interpolation := DefaultSlidingInterpoation;
      A.Duration := DefaultSlidingDuration;
      A.PropertyName := 'Position.X';
      A.StartFromCurrent := True;
      A.StopValue := NewValue;
      A.Start;
      while A.Running do
      begin
        Application.ProcessMessages;
        Sleep(0);
      end;
    finally
      A.DisposeOf;
    end;
  end;

The SetActiveTabWithTransitionAsync is maybe a good starting point for Async transitions, I will check that more deeply.

TabControl1.SetActiveTabWithTransitionAsync(

On the other hand I banned all unnecessary transitions from my apps anyway, because users don't feel like "cool" anymore,
they often consider the UI as "slow".

 

 

Share this post


Link to post
16 hours ago, Rollo62 said:

I was always hesitating to use the "Transition" animations, because I never can be 100% sure where it may use Application.ProcessMessages internally.

Doubtful, since transitions are meant to be used asynchronously.

16 hours ago, Rollo62 said:

There are a lot of places where this is maybe used, and only by digging deep inside the sources I can check it out, but I'm never sure on what happens in future versions.


  procedure AnimateControlPositionXWait(AParent: TFmxObject; const NewValue: Integer);
  var
    A: TIntAnimation;
  begin
    TAnimator.StopPropertyAnimation(AParent, 'Position.X');

    A := TIntAnimation.Create(AParent);
    try
      A.Parent := AParent;
      A.AnimationType := DefaultSlidingAnimationType;
      A.Interpolation := DefaultSlidingInterpoation;
      A.Duration := DefaultSlidingDuration;
      A.PropertyName := 'Position.X';
      A.StartFromCurrent := True;
      A.StopValue := NewValue;
      A.Start;
      while A.Running do
      begin
        Application.ProcessMessages;
        Sleep(0);
      end;
    finally
      A.DisposeOf;
    end;
  end;

TIntAnimation has an OnFinish event, you are supposed to use that instead of using a blocking wait loop on the Running property.

16 hours ago, Rollo62 said:

On the other hand I banned all unnecessary transitions from my apps anyway, because users don't feel like "cool" anymore,

they often consider the UI as "slow".

Good thing SetActiveTabWithTransitionASync() has an option to skip the actual transition.

 

Share this post


Link to post
On 4/3/2019 at 4:11 PM, Remy Lebeau said:

What is there not to understand?  The TTabControl is transitioned to the desired Tab and a timer is started, then flow is returned to the main UI message loop.  When the timer fires after 500ms, the ProgressBar is incremented and flow is returned to the main UI message loop.  The timer fires again after another 500ms, and again, each time returning to the main UI message loop.  Eventually, the ProgressBar reaches its Max and the timer is stopped.

 

You fixed the mistake. I was unclear if you were right, and then I was not able to understand how it should have worked. After the fix, I understand the code.

Share this post


Link to post

Thank you for all answers, SetActiveTabWithTransitionASync working good.

Share this post


Link to post

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

×