2

有一个框架(不是表格)和一个线程。如何从线程中引用Frame的控件?例如,我想禁用线程中的按钮。但我没有指向按钮的指针,框架中没有全局变量。

谢谢!

4

2 回答 2

7

实际上,您根本不应该调用任何方法或修改 VCL 控件的任何属性,或任何对用户可见的内容(应用程序的用户界面,这意味着 VCL 控件通常在 Delphi 中,无论是否在框架中)从后台线程。

但是,您可以使用PostMessageTThread.Synchronize或向主线程发送事件或通知TThread.Queue

与其在线程对象中引用框架或控件,不如将包含框架或其他控件的表单的句柄传递给线程,并使用用户消息(WM_USER+10001 ) 像这样。

我更喜欢 PostMessage 而不是 TTHread.Synchronize 或 Queue,因为它非常简单而且效果很好。这并不是一种跨平台友好的技术,因为它与 Win32 API 相关联。

你应该像这样调用同步:

  TMyThread = class(TThread)
  private
    FFrame: TFrame;
    ...
  public
    constructor Create(AFrame: TFrame); 
    ...
  end;

  constructor TMyThread.Create(AFrame: TFrame);
  begin
    FFrame := AFrame;
    inherited Create;
  end;

  // do not call directly, only using Synchronize
  procedure TMyThread.AMethodWithNoParameters; 
  begin
     FFrame.Button1.Enabled := not FBusy;
  end;

  procedure TMyThread.DoWork; // called from Execute.
  begin
    FBusy := true; 
    Synchronize(AMethodWithNoParameters);
    Sleep(100); //dummy;
    FBusy := false; 
    Synchronize(AMethodWithNoParameters);
  end;
于 2011-08-04T19:43:44.417 回答
2

正如非常正确地指出的那样,您不能在后台线程中调用任何可视组件的任何成员。

要从线程代码中禁用按钮,您必须具有对按钮的引用或对可以分配线程对象的事件的引用 - 然后您可以在排队或同步过程中触发线程,如下所示:-

    type
      test=class(tthread)
         ondisablebutton:tnotifyevent;

{...}

然后,在使用 tthread.synchronize 封装的过程中,您可以调用该事件,不要忘记测试它是否已分配......

procedure test.synchronisedprocedure;
begin
  if assigned(ondisablebutton) then
    ondisablebuttone(self);
end;

当您创建您设计的线程对象时,您必须将 ondisablebutton 分配给包含按钮的表单过程,如下所示: -

procedure form1.threadwantstodisablebutton(sender:tobject);
begin
  button1.enabled:=false;
end;

然后您的线程创建需要额外的一行:-

  mythread:=test.create;
  test.ondisablebutton:=form1.threadwantstodisablebutton;

像这样,显然您必须有权访问您定义和创建线程的 form1(或包含按钮的表单),这不一定是好的设计,但它可以工作。

于 2011-08-04T22:35:56.307 回答