队列过程调用相同的[main]线程

时间:2016-08-17 13:00:31

标签: delphi

我正在处理一些特定的TForm事件[ CMControlListChanging ], 并且需要修改那个(插入的)控件,但是当我尝试这样做时,事情变得,因为显然它并不意味着在VCL操作的中间中执行此操作

所以我需要推迟控制修改,通过排队代码远离[ CMControlListChanging ]处理程序,在稍后时间。

当然,我可以做 PostMessage 的东西,但我想要更通用的方法。

System.Classes单元包含

类过程同步(ASyncRec:PSynchronizeRecord; QueueEvent:Boolean = False);过载;

可以做到这一点,但它会检查,是否     CurrentThread.ThreadID = MainThreadID  如果是,则调用方法我尝试立即排队。

延迟调用的任何良好方法,至少在主线程上?

3 个答案:

答案 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方法异步地延迟主线程的调用。

请参见TThread.ForceQueue

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使用此线程信息来查找适当的排队方法。
  •