我正在处理一些特定的TForm事件[CMControlListChanging],并且需要修改那个(插入的)控件,但是当我尝试这样做时,事情变得糟糕,因为显然它并不意味着在VCL操作中这样做。
因此,我需要通过将代码从[CMControlListChanging]处理程序排队,以便稍后调用来推迟控制修改。
当然,我可以做PostMessage的东西,但我想要更通用的方法。
System.Classes单元包含
class procedure Synchronize(ASyncRec:PSynchronizeRecord; QueueEvent:Boolean = False);超载;
可以做的伎俩,但它检查,无论CurrentThread.ThreadID = MainThreadID,如果是,然后调用方法我尝试立即排队。
延迟调用的任何好方法,至少在主线程上?
不确定这是否是您正在寻找的,但如果您使用的是最近的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;
这个怎么样?它不会创建新任务,只是一个新的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)
说明推迟的事件仅在事件结束时运行,以及访问本地变量。
警告:你是否在推迟调用和事件退出之间运行Application.ProcessMessages - 如果你这样做,那么推迟的代码将在那时运行。
从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使用此线程信息来查找正确的排队方法。