为每个线程 - Delphi分配一个Panel

waf*_*les 2 delphi multithreading object

我有一个同时运行多个线程的程序.每个线程连接一个数据库并将数据从一个表传输到另一个表.现在我想为MainForm中的每个线程分配一个面板,这样如果连接成功,我可以将Panel的颜色更改为绿色,如果在重试次数后它被破坏,我可以将其更改为红色.

那么如何告诉一个线程Panel是哪个Panel呢?

him*_*elf 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;
Run Code Online (Sandbox Code Playgroud)

对于每个线程创建一个面板并将其Tag值设置为此Id:

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

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

const
  WM_CONNECTED = WM_USER + 1;
  WM_DISCONNECTED = WM_USER + 2;
Run Code Online (Sandbox Code Playgroud)

在此消息的wParam中,您传递PanelId:

procedure TMyThread.Connected;
begin
  PostMessage(MainForm.Handle, WM_CONNECTED, PanelId, 0);
end;
Run Code Online (Sandbox Code Playgroud)

在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;
Run Code Online (Sandbox Code Playgroud)

与WmDisconnected相同.

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

  • 是的,但是Synchronize有自己的缺陷.它大致等于SendMessage,这种方法会在任何相对复杂的情况下触发死锁.避免使用SendMessage,避免同步是一条经验法则. (2认同)