Thursday, April 30, 2020

TAniIndicator - How to make it work

Delphi 10.3.3

Many want to use a busy indicator to show the user there is a non visible process in operation. Usually when Delphi programmers try this the first time they notice the TAniIndicator doesn't rotate when they want it to. The problem is that the background process is in the same main form thread as the AniIndicator, which stops the AniIndicator from visibly moving.

In this example we download a file from the internet in the background while the Delphi TAniIndicator component is busy rotating.

The main issue is that the AniIndicator needs to be running in the main form thread and whatever long process you are doing in the background has to be running in another created thread. It wont work the other way around.

You can download the example code below. This example works the same on Windows, Android, IOS and MacOS.







unit MainUnit;

interface

uses
  System.Types, System.Classes, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Layouts, System.Net.HttpClient, System.Net.HttpClientComponent, System.Net.URLClient,
  FMX.Controls.Presentation, FMX.Objects;

type
  TMainform = class(TForm)
    LoadButton: TButton;
    AniIndicator1: TAniIndicator;
    Layout1: TLayout;
    Layout2: TLayout;
    Layout3: TLayout;
    Image1: TImage;
    NetHTTPClient1: TNetHTTPClient;
    Layout4: TLayout;
    ClearImageButton: TButton;
    procedure LoadButtonClick(Sender: TObject);
    procedure ClearImageButtonClick(Sender: TObject);
  private
    { Private declarations }
    procedure load_from_internet;
  public
    { Public declarations }
  end;

var
  Mainform: TMainform;

implementation

{$R *.fmx}
uses
  System.threading, system.uitypes;

procedure TMainform.ClearImageButtonClick(Sender: TObject);
begin
  Image1.Bitmap.Clear(TAlphaColorRec.White);
end;

procedure TMainform.load_from_internet;
var
  Task: ITask;
  url: string;
begin

// turn on ani indicator
  mainform.AniIndicator1.Enabled := True;
  mainform.AniIndicator1.Visible := True;

  Task := TTask.Create(
    procedure
    var
      ms: tmemorystream;
      resp: IHTTPResponse;
    begin
      // ***** do what you need to do in the thread 

      // while the aniindicator is running **********
      NetHTTPClient1.UserAgent := 'Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64;+rv:75.0)+Gecko/20100101+Firefox/75.0';
      ms := tmemorystream.Create;
     // some image file on internet
      url := 'https://www.i-logic.com/kitten.jpg';
      try
        resp := NetHTTPClient1.Get(url, ms);

        if TTask.CurrentTask.Status <> TTaskStatus.Canceled then
        begin
          TThread.Queue(TThread.CurrentThread,
            procedure
            begin
              // ****** this is where it comes when the

              // thread is finished *************
              // we can work with the visual form components
              ms.Position := 0;
              // put the data into image1
              try
               if resp.StatusCode = 200 then  // file was found
                  image1.Bitmap.LoadFromStream(ms);
              finally
                ms.Free;
               // turn off aniindicator
                mainform.AniIndicator1.Enabled := False;
                mainform.AniIndicator1.Visible := False;
              end;
            end);
        end;
      except
       // ****** error in get url *************
        TThread.Queue(TThread.CurrentThread,
          procedure
          begin
            ms.Free;
            // turn off aniindicator
            mainform.AniIndicator1.Enabled := False;
            mainform.AniIndicator1.Visible := False;
          end);
      end;
    end);

  Task.Start;
end;

procedure TMainform.LoadButtonClick(Sender: TObject);
begin
  load_from_internet;
end;

end.



**********************************************


The mainunit FMX file:


object Mainform: TMainform
  Left = 0
  Top = 0
  Caption = 'AniIndicator'
  ClientHeight = 480
  ClientWidth = 258
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object Layout1: TLayout
    Align = Top
    Size.Width = 258.000000000000000000
    Size.Height = 73.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 1
    object LoadButton: TButton
      Align = Center
      Size.Width = 195.000000000000000000
      Size.Height = 35.000000000000000000
      Size.PlatformDefault = False
      TabOrder = 0
      Text = 'Load From Internet'
      OnClick = LoadButtonClick
    end
  end
  object Layout2: TLayout
    Align = Top
    Position.Y = 73.000000000000000000
    Size.Width = 258.000000000000000000
    Size.Height = 76.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 2
    object AniIndicator1: TAniIndicator
      Align = Center
      Size.Width = 81.000000000000000000
      Size.Height = 68.000000000000000000
      Size.PlatformDefault = False
    end
  end
  object Layout3: TLayout
    Align = Top
    Position.Y = 149.000000000000000000
    Size.Width = 258.000000000000000000
    Size.Height = 156.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 3
    object Image1: TImage
      MultiResBitmap = <
        item
        end>
      Align = Center
      Size.Width = 185.000000000000000000
      Size.Height = 117.000000000000000000
      Size.PlatformDefault = False
    end
  end
  object Layout4: TLayout
    Align = Top
    Position.Y = 305.000000000000000000
    Size.Width = 258.000000000000000000
    Size.Height = 80.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 5
    object ClearImageButton: TButton
      Align = Center
      Size.Width = 124.000000000000000000
      Size.Height = 32.000000000000000000
      Size.PlatformDefault = False
      TabOrder = 0
      Text = 'Clear Image'
      OnClick = ClearImageButtonClick
    end
  end
  object NetHTTPClient1: TNetHTTPClient
    Asynchronous = False
    ConnectionTimeout = 60000
    ResponseTimeout = 60000
    HandleRedirects = True
    AllowCookies = True
    UserAgent = 'Embarcadero URI Client/1.0'
    Left = 92
    Top = 200
  end
end


**************************************
Source Code:
https://i-logic.com/ftp/AniInicatorCode.zip

2 comments:

  1. excellent. please keep posting to your blog. highly useful stuff

    ReplyDelete