如何在 TThread 中启用 AniIndicator1,而不是在 FMX 的主进程中?
How to enable an AniIndicator1 in a TThread , not in the main process in FMX?
嗨,我有一个基于 FMX 的多设备应用程序。
同步数据库过程需要更长的时间,我需要启用一个 AniIndicator1 来告诉用户等待。
以下代码在n android phone中测试过,有时有效,有时只完成第一个同步DB功能,有时先完成3个然后退出。 sychDB函数有时none发生
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函数放在子线程中,并使用主线程来同步数据库?
尝试了以下代码,但没有按预期工作。
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 线程的访问。
procedure TForm1.BtnSyncDBClick(Sender: TObject);
var
Thread: TThread;
begin
Application.ProcessMessages;
memo3.Lines.Add('Start synchronising...');
AniIndicator1.Visible := True;
AniIndicator1.Enabled := True;
Thread := TThread.CreateAnonymousThread(
procedure
begin
SynchDB_A; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 0');
end
);
SynchDB_B; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 1');
end
);
SynchDB_C; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 2');
end
);
SynchDB_D; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 3');
end
);
end
);
Thread.OnTerminate := SyncDone;
Thread.Start;
end;
procedure TForm1.SyncDone(Sender: TObject);
begin
AniIndicator1.Enabled := False;
AniIndicator1.Visible := False;
if TThread(Sender).FatalException <> nil then
memo3.Lines.Add('Error: ' + Exception(TThread(Sender).FatalException).Message);
end;
您的第二个代码不起作用的原因是主 UI 线程正在阻止执行所有工作,因此在该工作完成之前它无法更新 UI。因此需要在线程中进行非 UI 工作。
为什么要在 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;
嗨,我有一个基于 FMX 的多设备应用程序。
同步数据库过程需要更长的时间,我需要启用一个 AniIndicator1 来告诉用户等待。
以下代码在n android phone中测试过,有时有效,有时只完成第一个同步DB功能,有时先完成3个然后退出。 sychDB函数有时none发生
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函数放在子线程中,并使用主线程来同步数据库?
尝试了以下代码,但没有按预期工作。
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 线程的访问。
procedure TForm1.BtnSyncDBClick(Sender: TObject);
var
Thread: TThread;
begin
Application.ProcessMessages;
memo3.Lines.Add('Start synchronising...');
AniIndicator1.Visible := True;
AniIndicator1.Enabled := True;
Thread := TThread.CreateAnonymousThread(
procedure
begin
SynchDB_A; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 0');
end
);
SynchDB_B; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 1');
end
);
SynchDB_C; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 2');
end
);
SynchDB_D; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 3');
end
);
end
);
Thread.OnTerminate := SyncDone;
Thread.Start;
end;
procedure TForm1.SyncDone(Sender: TObject);
begin
AniIndicator1.Enabled := False;
AniIndicator1.Visible := False;
if TThread(Sender).FatalException <> nil then
memo3.Lines.Add('Error: ' + Exception(TThread(Sender).FatalException).Message);
end;
您的第二个代码不起作用的原因是主 UI 线程正在阻止执行所有工作,因此在该工作完成之前它无法更新 UI。因此需要在线程中进行非 UI 工作。
为什么要在 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;