有一个框架(不是表格)和一个线程。如何从线程中引用Frame的控件?例如,我想禁用线程中的按钮。但我没有指向按钮的指针,框架中没有全局变量。
谢谢!
实际上,您根本不应该调用任何方法或修改 VCL 控件的任何属性,或任何对用户可见的内容(应用程序的用户界面,这意味着 VCL 控件通常在 Delphi 中,无论是否在框架中)从后台线程。
但是,您可以使用PostMessage
或TThread.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;
正如非常正确地指出的那样,您不能在后台线程中调用任何可视组件的任何成员。
要从线程代码中禁用按钮,您必须具有对按钮的引用或对可以分配线程对象的事件的引用 - 然后您可以在排队或同步过程中触发线程,如下所示:-
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(或包含按钮的表单),这不一定是好的设计,但它可以工作。