Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correctly using TAniIndicator in firemonkey mobile dev for wait for processing

I am using Delphi XE-5 (Firemonkey Mobile Application)

I am trying to get the TAniIndicator to work, by displaying during my long processing. I have a TAniIndicator (AniIndi) on my main form, but it does not spin. It displays correctly, but does not spin.

begin
 Loading:= True;
 AniIndi.Visible:= True;
 AniIndi.Enabled:= True;
 UpdateAll;
 Application.ProcessMessages;

 //do my processsing here

 Loading:= False;
 AniIndi.Enabled:= False;
 AniIndi.Visible:= False;
 UpdateAll;
 Application.ProcessMessages;
end;

//EDIT BASED ON REMY's ANSWER

TLoadThread = class(TThread)
 public
  Config: Boolean;
  constructor Create(const aConfig: Boolean); reintroduce;
 protected
  procedure DoProcessing;
  procedure Execute; Override;
 end;

var
 loading: Boolean = false;
 zLThread: TLoadThread = nil;

constructor TLoadThread.Create(const aConfig: Boolean);
begin
 inherited Create(true);
 Config:= aConfig;
end;

procedure TLoadThread.DoProcessing;
var
begin
 //do processing here and update main form
end;

procedure TLoadThread.Execute;
begin
 FreeOnTerminate:= true;
 Synchronize(DoProcessing);
end;


procedure TfrmMain.FormActivate(Sender: TObject);
begin
 zLThread:= TLoadThread.Create(True, Host, NamePath, Config, Port);
 zLThread.OnTerminate := ThreadTerminated;
 zLThread.Start;
 Loading := True;
 AniIndi.Visible := True;
 AniIndi.Enabled := True;
 UpdateAll;
end;

procedure TfrmMain.ThreadTerminated(Sender: TObject);
begin
  zLThread := nil;
  Loading := False;
  AniIndi.Enabled := False;
  AniIndi.Visible := False;
  UpdateAll;
end;
like image 559
JakeSays Avatar asked Dec 03 '22 21:12

JakeSays


2 Answers

Your main thread needs to stay responsive to the message queue while your long process is running. If not, you are blocking the animation (and other aspects of the UI) from receiving new messages, like paint requests and timers notifies. You need to move any long processing to a separate thread instead. Start the thread and then start the animation. Let the main thread handle the UI normally in the meantime. When the thread is finished, have it notify the main thread, which can then stop the animation, and finish any other processing it needs on the result of the thread, if any. For example:

type
  TLoadThread = class(TThread)
  public
    Host: string;
    NamePath: string;
    Port: Integer;
    Config: Boolean;
    constructor Create(const aHost, aNamePath: string; aPort: Integer; aConfig: Boolean); reintroduce;
  protected
    procedure Execute; override;
  end;

constructor TLoadThread.Create(const aHost, aNamePath: string; aPort: Integer; aConfig: Boolean);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  Host := aHost;
  NamePath := aNamePath;
  Port := aPort;
  Config := aConfig;
end;

procedure TLoadThread.Execute;
begin
  //do processing

  Synchronize(
    procedure
      //update main form
    end
  );

  //do processing
end;

var
  Loading: Boolean = False;
  zLThread: TLoadThread = nil;

procedure TfrmMain.FormActivate(Sender: TObject);
begin
  zLThread := TLoadThread.Create(Host, NamePath, Port, Config);
  zLThread.OnTerminate := ThreadTerminated;
  zLThread.Start;
  Loading := True;
  AniIndi.Visible := True;
  AniIndi.Enabled := True;
  UpdateAll;
end;

procedure TfrmMain.ThreadTerminated(Sender: TObject);
begin
  zLThread := nil;
  Loading := False;
  AniIndi.Enabled := False;
  AniIndi.Visible := False;
  UpdateAll;
end;
like image 115
Remy Lebeau Avatar answered Jan 08 '23 12:01

Remy Lebeau


The problem come from the timer Inside the TAnimation, by chance Embarcadero add a global variable.

Add the following code in your FormCreate procedure

{$IFDEF IOS}
AniFrameRate := 10;
{$ENDIF}
like image 45
David Drouin Avatar answered Jan 08 '23 12:01

David Drouin