我正在处理一些特定的TForm事件[ CMControlListChanging ], 并且需要修改那个(插入的)控件,但是当我尝试这样做时,事情变得坏,因为显然它并不意味着在VCL操作的中间中执行此操作
所以我需要推迟控制修改,通过排队代码远离[ CMControlListChanging ]处理程序,在稍后时间。
当然,我可以做 PostMessage 的东西,但我想要更通用的方法。
System.Classes单元包含
类过程同步(ASyncRec:PSynchronizeRecord; QueueEvent:Boolean = False);过载;
可以做到这一点,但它会检查,是否 CurrentThread.ThreadID = MainThreadID 如果是,则调用方法我尝试立即排队。
延迟调用的任何良好方法,至少在主线程上?
答案 0 :(得分:4)
不确定这是否是您正在寻找的,但如果您使用的是最近的Delphi版本,这些推迟方法可能会派上用场。在应用可选的非阻塞延迟后,它们在主线程中执行 AProc 。
uses
System.Threading,
System.Classes;
procedure Postpone(AProc: TThreadProcedure; ADelayMS: Cardinal = 0); overload;
begin
TTask.Run(
procedure
begin
if ADelayMS > 0 then begin
TThread.Sleep(ADelayMS);
end;
TThread.Queue(nil, AProc);
end);
end;
procedure Postpone(AProc: TThreadMethod; ADelayMS: Cardinal = 0); overload;
begin
TTask.Run(
procedure
begin
if ADelayMS > 0 then begin
TThread.Sleep(ADelayMS);
end;
TThread.Queue(nil, AProc);
end);
end;
答案 1 :(得分:0)
这个怎么样?它不会创建新任务,而只是创建新的HWND(用于接收消息):
TYPE TDelayedProc = REFERENCE TO PROCEDURE;
TYPE
TPostponeClass = CLASS(TWinControl)
CONSTRUCTOR Create(P : TDelayedProc);
STRICT PRIVATE
Proc : TDelayedProc;
PROCEDURE Run(VAR M : TMessage); MESSAGE WM_USER;
END;
CONSTRUCTOR TPostponeClass.Create(P : TDelayedProc);
BEGIN
INHERITED Create(NIL);
Parent:=Application.MainForm;
Proc:=P;
PostMessage(Handle,WM_USER,0,0)
END;
PROCEDURE TPostponeClass.Run(VAR M : TMessage);
BEGIN
Proc;
Free
END;
PROCEDURE Postpone(Proc : TDelayedProc);
BEGIN
TPostponeClass.Create(Proc)
END;
它甚至可以与匿名方法一起使用,因此您可以推迟执行事件的一部分,并且仍然可以访问局部变量(和实例“ Self”)。
像这样使用它:
PROCEDURE WriteFile(CONST F : TFileName ; CONST STR : STRING);
VAR
TXT : TextFile;
BEGIN
AssignFile(TXT,F);
IF FileExists(F) THEN APPEND(TXT) ELSE REWRITE(TXT);
WRITELN(TXT,STR);
CloseFile(TXT)
END;
PROCEDURE TForm37.Button1Click(Sender: TObject);
CONST
N = 'LOGFILE.TXT';
VAR
LocalVar : INTEGER;
BEGIN
DeleteFile(N);
LocalVar:=20;
Postpone(PROCEDURE
BEGIN
WriteFile(N,'Postponed Code: '+Name+' ('+IntToStr(LocalVar)+')')
END);
WriteFile(N,'Last statement in event: '+Name)
END;
LOGFILE.TXT文件将包含两行:
Last statement in event: Form37
Postponed Code: Form37 (20)
说明延迟事件仅在事件结束时运行,并且可以访问局部变量。
注意事项:您是否在Postpone调用和事件出口之间运行Application.ProcessMessages-如果您这样做,则延迟的代码将在此时运行。
答案 2 :(得分:0)
从Delphi 10.2 Tokyo起,可以使用TThread
方法异步地延迟主线程的调用。
class procedure ForceQueue(const AThread: TThread; const AMethod: TThreadMethod); overload; static; class procedure ForceQueue(const AThread: TThread; const AThreadProc: TThreadProcedure); overload; static;
在主线程中将方法调用的执行排队。
与Queue不同,尽管AMethod指定的方法调用的执行是由主线程调用的,但它被强制排队。
AMethod关联调用者线程:
- 对于静态方法,可以使用AThread参数将AMethod与任何线程关联。
- 如果不需要了解主线程中调用者线程的信息,则可以使用nil / NULL作为AThread参数。
- RemoveQueuedEvents使用此线程信息来查找适当的排队方法。