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

问题描述 投票:5回答:3

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

因此,我需要通过将代码从[CMControlListChanging]处理程序排队,以便稍后调用来推迟控制修改。

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

System.Classes单元包含

class procedure Synchronize(ASyncRec:PSynchronizeRecord; QueueEvent:Boolean = False);超载;

可以做的伎俩,但它检查,无论CurrentThread.ThreadID = MainThreadID,如果是,然后调用方法我尝试立即排队。

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

delphi
3个回答
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;

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)

说明推迟的事件仅在事件结束时运行,以及访问本地变量。

警告:你是否在推迟调用和事件退出之间运行Application.ProcessMessages - 如果你这样做,那么推迟的代码将在那时运行。


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使用此线程信息来查找正确的排队方法。
© www.soinside.com 2019 - 2024. All rights reserved.