Search code examples
delphifiremonkeydelphi-10.2-tokyo

FMX Delphi 10.2 Show form or please wait panel while task executed


I have several task on button click.

eg.

  1. Show form or please wait panel....
  2. Load data from database (duration 5-10 seconds)
  3. Clear all TEdit field
  4. Hide form or please wait panel....
  5. ShowMessage('completed')

Is it possible After click on button show please wait panel or form and after all completed hide that panel.

How to Synchronize Perform Tasks One by one.

Or any other simple solution.


Solution

  • This is a simple example that creates a "placeholder" which looks like this:

    enter image description here

    The rectangle has a black background and contains a layout which is aligned to Center; inside you can find a label (aligned to Top) and an arc (aligned to Client). The code is here:

    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 418
      ClientWidth = 490
      FormFactor.Width = 320
      FormFactor.Height = 480
      FormFactor.Devices = [Desktop]
      OnCreate = FormCreate
      DesignerMasterStyle = 0
      object Rectangle1: TRectangle
        Align = Client
        Fill.Color = xFF222222
        Size.Width = 490.000000000000000000
        Size.Height = 418.000000000000000000
        Size.PlatformDefault = False
        Visible = False
        object Layout1: TLayout
          Align = Center
          Size.Width = 170.000000000000000000
          Size.Height = 102.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 0
          object Label1: TLabel
            Align = Top
            StyledSettings = [Family, Size, Style]
            Size.Width = 170.000000000000000000
            Size.Height = 41.000000000000000000
            Size.PlatformDefault = False
            TextSettings.FontColor = claWhite
            TextSettings.HorzAlign = Center
            Text = 'Please wait'
            TabOrder = 0
          end
          object Arc1: TArc
            Align = Center
            Size.Width = 50.000000000000000000
            Size.Height = 50.000000000000000000
            Size.PlatformDefault = False
            Stroke.Color = claCoral
            EndAngle = -90.000000000000000000
            object FloatAnimation1: TFloatAnimation
              Enabled = True
              Duration = 1.000000000000000000
              Loop = True
              PropertyName = 'RotationAngle'
              StartValue = 0.000000000000000000
              StopValue = 360.000000000000000000
            end
          end
        end
      end
    end
    

    The Visible property of the rectangle is set to False so that you won't see immediately the rectangle. Note that I have created an animation in the arc component so that you can see it spinning around:

    enter image description here

    In this way you can mimic a loading spinner. Then I have added this code in the OnCreate event of the form just as example of how you could do this.

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      TTask.Run(procedure
                begin
                  TThread.Synchronize(nil, procedure
                                     begin
                                       Rectangle1.Visible := true;
                                       //Rectangle1.BringToFront;
                                       // ^ call the above if needed, just to be sure
                                       // that you'll always see the rectangle on screen 
                                     end);
    
                  Sleep(4000);
    
                  TThread.Synchronize(nil, procedure
                                     begin
                                       Rectangle1.Visible := false;
                                       ShowMessage('Finish!');
                                     end);
                end);
    end;
    

    The Sleep(4000) simulates a long task and this piece of code should be replaced with your tasks. Actually I'd do something like this:

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      TTask.Run(procedure
                var
                  arr: array [0..1] of ITask;
                begin
                  TThread.Synchronize(nil, procedure
                                     begin
                                       Rectangle1.Visible := true;
                                       Rectangle1.BringToFront;
                                     end);
    
                  arr[0] := TTask.Run(procedure
                                      begin
                                        //load data from the database
                                      end);
    
                  arr[1] := TTask.Run(procedure
                                      begin
                                        //something else
                                      end);
    
                  //this call is blocking but you are calling this in a worker thread!
                  //your UI won't freeze and at the end you'll see the message appearing
                  TTask.WaitForAll(arr);
                  TThread.Synchronize(nil, procedure
                                     begin
                                       Rectangle1.Visible := false;
                                       ShowMessage('Finish!');
                                     end);
                end);
    end;
    

    Of course you should place this code in a ButtonClick and not in a FormCreate event handler!