Multithreading 如何在TThread中而不是在FMX的主进程中启用AniIndicator1?

Multithreading 如何在TThread中而不是在FMX的主进程中启用AniIndicator1?,multithreading,delphi,cursor,firemonkey,Multithreading,Delphi,Cursor,Firemonkey,嗨,我有一个基于FMX的多设备应用程序 同步数据库过程需要更长的时间,我需要启用一个指示符号1来告诉用户等待 下面的代码在n安卓手机上测试,有时有效,有时只完成第一个同步DB功能,有时完成前3个,然后退出。有时,sychDB功能没有发生 procedure TForm1.BtnSyncDBClick(Sender: TObject); begin Application.ProcessMessages; memo3.Lines.Add('Start synchronising...')

嗨,我有一个基于FMX的多设备应用程序

同步数据库过程需要更长的时间,我需要启用一个指示符号1来告诉用户等待

下面的代码在n安卓手机上测试,有时有效,有时只完成第一个同步DB功能,有时完成前3个,然后退出。有时,sychDB功能没有发生

procedure TForm1.BtnSyncDBClick(Sender: TObject);
begin 
  Application.ProcessMessages;
  memo3.Lines.Add('Start synchronising...');
  AniIndicator1.Visible:=true;
  AniIndicator1.Enabled:=true;
      TThread.CreateAnonymousThread(
    procedure
    begin
      try
        SynchDB_A;
          memo3.Lines.Add('finish 0');
         SynchDB_B;
         memo3.Lines.Add('finish 1');
         SynchDB_C ;
          memo3.Lines.Add('finish 2');
         SynchDB_D;
          memo3.Lines.Add('finish 3');
      finally
        AniIndicator1.Enabled := False;
        AniIndicator1.Visible := False;
      end;
    end
    ).start;
end;
因此,我想知道是否可以将AniIndicator1.enable函数放在子线程中,并使用主线程来同步HDB

尝试了以下代码,但未按预期工作

procedure TForm1.BtnSyncDBClick(Sender: TObject);
    begin 
           TThread.CreateAnonymousThread(
    procedure
    begin
      try
         TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
           Memo1.lines.Add('Start... ');
            AniIndicator1.Visible := True;
            AniIndicator1.Enabled := True;
          end);    
      finally

      end;
    end
  ).Start;

          try
            SynchDB_A;
              memo3.Lines.Add('finish 0');
             SynchDB_B;
             memo3.Lines.Add('finish 1');
             SynchDB_C ;
              memo3.Lines.Add('finish 2');
             SynchDB_D;
              memo3.Lines.Add('finish 3');
          finally
            AniIndicator1.Enabled := False;
            AniIndicator1.Visible := False;
          end;
end;
任何专家都可以对此提供帮助,要么修复第一个代码以确保始终工作,子线程不会被终止,要么在主进程中启动SynchDB并在子线程中启用AniIndicator1并使其旋转。或者其他简单的方法告诉用户在synchDB工作时等待


提前感谢。

您不能像现在这样直接从工作线程中访问UI控件。您必须将该访问同步到主UI线程

过程TForm1.BtnSyncDBClick(发送方:TObject);
变量
线程:TThread;
开始
Application.ProcessMessages;
备忘录3.行。添加('开始同步…');
aniindicator 1.可见:=真;
AniIndicator1.Enabled:=真;
线程:=TThread.CreateAnonymousThread(
程序
开始

SynchDB_A;//您不能像现在这样直接从工作线程中访问UI控件。您必须将该访问同步到主UI线程

过程TForm1.BtnSyncDBClick(发送方:TObject);
变量
线程:TThread;
开始
Application.ProcessMessages;
备忘录3.行。添加('开始同步…');
aniindicator 1.可见:=真;
AniIndicator1.Enabled:=真;
线程:=TThread.CreateAnonymousThread(
程序
开始

SynchDB_A;//为什么在onclick事件中调用application.processmessages? 您已经在主线程消息循环中

您还可以使用TTask.run,它比TThread.CreateAnonymousThread更简单

TTask.run(
procedure
var
  msg : string;
begin
  try
   SynchDB_A;
   msg:='finish 1';
  except
    on e:exception do begin
      msg:=e.message;
    end;
  end;
  TThread.Queue(Nil,
  procedure
  begin
    memo3.lines.add(msg);
  end);

为什么在onclick事件中调用application.processmessages? 您已经在主线程消息循环中

您还可以使用TTask.run,它比TThread.CreateAnonymousThread更简单

TTask.run(
procedure
var
  msg : string;
begin
  try
   SynchDB_A;
   msg:='finish 1';
  except
    on e:exception do begin
      msg:=e.message;
    end;
  end;
  TThread.Queue(Nil,
  procedure
  begin
    memo3.lines.add(msg);
  end);

试试这个,创建这个过程

procedure TFDashboard.fnLoading(isEnabled : Boolean);
begin
  TThread.Synchronize(nil, procedure begin
    AniIndicator1.Visible := isEnabled;
    AniIndicator1.Enabled := isEnabled;
  end);
end;
之后,您可以在TTask内部调用该过程

procedure TFDashboard.FirstShow;
begin
  TTask.Run(procedure begin
    fnLoading(True);
    try

    finally
      fnLoading(False);
    end;
  end).Start;
end;

试试这个,创建这个过程

procedure TFDashboard.fnLoading(isEnabled : Boolean);
begin
  TThread.Synchronize(nil, procedure begin
    AniIndicator1.Visible := isEnabled;
    AniIndicator1.Enabled := isEnabled;
  end);
end;
之后,您可以在TTask内部调用该过程

procedure TFDashboard.FirstShow;
begin
  TTask.Run(procedure begin
    fnLoading(True);
    try

    finally
      fnLoading(False);
    end;
  end).Start;
end;

感谢您的评论。您的代码(与我的第一个版本类似)的问题在于,并非所有synchDB函数都将被执行。有时仅执行1,备忘录1只有一行“完成0”,然后工作线程完成了。问题出在哪里?这也发生在Windows平台上。我发现了问题。synchDB有错误。因此它安静地结束。将尝试..最后异常可以在工作线程中显示错误消息?@Haizhou如果工作线程引发异常但未捕获,线程将简单地终止。如果要对异常执行任何操作,您需要捕获异常。在这种情况下,由于您使用的是
TThread
,因此可以为该线程分配
OnTerminate
处理程序,并检查其
FatalException
属性。您还可以使用此事件停止
TAniIndicator
,因此不需要
tryy
不再。我已经更新了我的示例来说明这一点。你是一个明星,谢谢你的想法。你能给出一个TTHread.OnTerminate编码的简短示例吗?不知道如何实现它。@Haizhou看到我的更新示例谢谢你的评论。你的代码的问题(类似于我的第一个版本)并非所有synchDB函数都将执行。有时仅执行1,Memo1只有一行“完成0”,然后工作线程完成了。问题出在哪里?这也发生在Windows平台上。我发现了问题。synchDB有错误。因此它安静地结束。将尝试..最后异常可以在工作线程中显示错误消息?@Haizhou如果工作线程引发异常但未捕获,线程将简单地终止。如果要对异常执行任何操作,您需要捕获异常。在这种情况下,由于您使用的是
TThread
,因此可以为该线程分配
OnTerminate
处理程序,并检查其
FatalException
属性。您还可以使用此事件停止
TAniIndicator
,因此不需要
tryy
不再。我已经更新了我的示例来说明这一点。你是一个明星,谢谢你的想法。你能给出一个关于TTHread.OnTerminate编码的简短示例吗?不知道如何实现它。@Haizhou看到我更新的示例了吗