i2programmer
i2programmer

Reputation: 11

TThread Creation of TButton Parented By TPanel

I have a question about Separate TThread creation of a MainThread TButton on a MainThread TPanel. The TPanel must be set as the TButton's Parent.

ButtonVariableName := TButton.Create (
    (Form1.FindComponent('PanelNameString') as TComponent)
   );

ButtonVariableName.Parent := (
    (Form1.FindComponent('PanelNameString') as TWinControl)
  );

is not working...

ButtonVariableName is on MainThread. TButton.Create() is being called on Separate TThread. ButtonVariableName.Parent is also called from Separate TThread.

FindComponent seems to be what is breaking down. When I remove it and place something else there it works. It may be that FindComponent doesn't work when called from Separate TThread but I'm not certain.

Any pointers^? LOL.

-i2programmer

Upvotes: 1

Views: 320

Answers (3)

Herman Sidharta
Herman Sidharta

Reputation: 139

type
  TMyThread = class( TThread )
  private
    FOwner : TComponent;
    procedure DoCreateButton;
  public
    constructor Create(AOwner: TComponent);
    procedure Execute; override;
  end;

.....

{ TMyThread }

constructor TMyThread.Create(AOwner: TComponent);
begin
  inherited Create(True);
  FreeOnTerminate := True;

  FOwner := AOwner;
  Resume;
end;

procedure TMyThread.DoCreateButton;
begin
  with TButton.Create(FOwner) do
  begin
    //Set the button Position 
    Left := 5;
    Top := 5;

    Parent := FOwner as TWinControl;
  end;
end;

procedure TMyThread.Execute;
begin
  Synchronize(DoCreateButton);
end;


{ Form1 }

procedure TForm1.btnExecClick(Sender: TObject);
begin
  TMyThread.Create(Panel1);
end;

Upvotes: 1

Cosmin Prund
Cosmin Prund

Reputation: 25678

This was supposed to be a comment but I want to include some code. First of all you're not supposed to call any VCL from secondary threads, so calling FindComponent is not guaranteed to work. Despite this fact, I doubt this is your problem, because unless you're especially lucky you will not get a race condition so you will not get an error.

You should do two things:

  • Put your code under a simple button on a form, test it, and when you know the code is good, move it to your background thread.
  • Brake up your code a bit so you can see what's failing where. No need to guess if FindComponent is the one that's failing when it's so easy to test and be sure.

Brake up your code like this:

var ParentPanel: TWinControl;
    anControl: TControl;
begin
  Assert(Assigned(Form1)); // Assertions are free, you might as well test everything
  anControl := Form1.FindComponent('YourNameHere'); // casting straight to TWinControl raises an error if the returned control is nil
  Assert(Assigned(anControl)); // Make sure we got something
  ParentPanel := anControl as TWinControl; // raises error if the control is not TWinControl
  ButtonVariableName := TButton.Create(ParentPanel);
  ButtonVariableName.Parent := ParentPanel;
end;

Upvotes: 1

gabr
gabr

Reputation: 26830

You can not use VCL from secondary threads. Use Synchronize or Queue in the secondary thread to execute VCL-related code in the context of the main thread.

Upvotes: 4

Related Questions