I have a program running several threads simultaneously. Each thread connects a database and transfers data from one table to another. Now I want to assign a panel to each thread in the MainForm so I can change color of the Panel to green if the connection is successful or to red if it's broken after a number of retries.
So how can I tell a thread which Panel is its own Panel?
When you create a thread class, add a variable to store panel 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;
For every thread create a panel and set it's Tag value to this Id:
for i := 1 to MaxThreads do begin
threads[i] := TMyThread.Create(i);
panels[i] := TPanel.Create(Self);
panels[i].Tag := i;
end;
When your thread needs to update data on panel, it should send a specially defined message to the main form:
const
WM_CONNECTED = WM_USER + 1;
WM_DISCONNECTED = WM_USER + 2;
In wParam of this message you pass PanelId:
procedure TMyThread.Connected;
begin
PostMessage(MainForm.Handle, WM_CONNECTED, PanelId, 0);
end;
In MainForm you catch this message, find the panel and update it:
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;
Same with WmDisconnected.
The important thing here is that you CANNOT and NEVER should try to update visual components from threads other than the main thread. If you need to update user controls, you should post messages to the main form and create handler procedures, like in this example. These handler procedures will then be automatically called from the main thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With