5

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;
JakeSays
  • 2,048
  • 8
  • 29
  • 43

2 Answers2

14

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;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Remy, I dited the main post. I need to update the main form's listbox during my processing. – JakeSays Dec 19 '13 at 19:24
  • The thread can use the `TThread.Synchronize()` method to update the ListBox when needed. – Remy Lebeau Dec 19 '13 at 19:32
  • Thanks! I was missing the h in Synchronize. I will update my working sample in a minute - thanks for the help – JakeSays Dec 19 '13 at 19:44
  • 3
    You are using `Synchronize()` to do **all** of your processing in the main thread, thus defeating the purpose of using a thread at all. Use `Synchronize()` to just update the ListBox by itself, but do the rest of your processing in the thread instead. – Remy Lebeau Dec 19 '13 at 20:30
2

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}
  • 1
    That isn't the problem (looks like lengthly processing in the main thread) but an upvote for an interesting possible solution anyway. (I didn't know that global existed!) – David Feb 15 '14 at 01:22