有一个 FRAME (不是表单)和一个帖子。如何从线程中引用Frame的控件?例如,我想从线程中禁用一个按钮。但我没有指向按钮的指针,框架中没有全局变量。
谢谢!
答案 0 :(得分:7)
你实际上不应该调用任何方法或修改VCL控件的任何属性,或者用户可见的任何东西(应用程序的用户界面,这意味着VCL通常在Delphi中控制,无论是在框架中还是不)直接来自后台线程。
然而,您可以使用PostMessage
或TThread.Synchronize
或TThread.Queue
向主要帖子发送活动或通知。
不是在线程对象中引用框架或控件,而是将包含框架或其他控件的窗体的句柄传递给线程,并使用用户消息( WM_USER + 10001),如this.
我更喜欢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;
答案 1 :(得分: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(或包含按钮的表单),你可以在其中定义和创建你的线程,这不一定是好的设计,但它可以工作。