2010-12-07 32 views
2

我有一个程序同时运行多个线程。每个线程连接一个数据库并将数据从一个表传输到另一个表。现在我想为MainForm中的每个线程分配一个面板,这样我可以在连接成功时将面板的颜色更改为绿色,或者在重试次数后断开面板的红色。为每个线程分配面板 - 德尔福

那么我怎么能告诉一个线程哪个面板是它自己的面板呢?

回答

10

当你创建一个线程类,添加一个变量来存储面板ID:

type 
TMyThread = class(TThread) 
public 
    PanelId: integer; 
    constructor Create(APanelId: integer); 
end; 

constructor TMyThread.Create(APanelId: integer); 
begin 
    inherited Create({CreateSuspended=}true); 
    PanelId := APanelId; 
    Suspended := false; 
end; 

对于每一个线程创建面板,并设置它的标记值这个ID:

for i := 1 to MaxThreads do begin 
    threads[i] := TMyThread.Create(i); 
    panels[i] := TPanel.Create(Self); 
    panels[i].Tag := i; 
end; 

当你的线程需要更新面板上的数据,它应发送一个特别定义的消息到主窗体:

const 
    WM_CONNECTED = WM_USER + 1; 
    WM_DISCONNECTED = WM_USER + 2; 

在此消息的wParam传递PanelId:

procedure TMyThread.Connected; 
begin 
    PostMessage(MainForm.Handle, WM_CONNECTED, PanelId, 0); 
end; 

在MainForm的你抓住这个消息,找到面板更新:

TMainForm = class(TForm) 
    {....} 
protected 
    procedure WmConnected(var msg: TMessage); message WM_CONNECTED; 
end; 

{...} 

procedure TMainForm.WmConnected(var msg: TMessage); 
begin 
    panels[msg.wParam].Color := clGreen; 
end; 

同样的,WmDisconnected。

这里最重要的是你不能尝试从主线程以外的线程更新可视化组件。如果您需要更新用户控件,则应将消息发布到主窗体并创建处理程序过程,如本例中所示。这些处理程序过程将被主线程自动调用。

+0

正如我所记得的,Synchronize()是Borland为这种事情设计的。 – 2010-12-07 15:24:08

3

你真的不应该这样做 - UI只应该由主线程更新。

+0

我,我会有一个主窗体数组来关联线程和面板。然后是一个读取线程状态并更新适当面板的计时器。这样线程就可以完成任务,并且可以随时更改UI,而无需执行任何操作。 – mj2008 2010-12-08 10:17:47

1

您不能分配主窗体线程的面板,因为它不是线程安全的以更新它。该线程可以通过Windows消息与应用程序线程(主窗体)交流,或者您必须使用消息队列。 检查OmniThreadLibrary以简化您的工作。