I created a thread class in Form1 Unit1.pas. Then in that thread class I also declare a method to update a shape color in that same Unit1.pas's Form1 class. This works fine.
But when I try to do the same in a child form, the shape color is not changing. Anybody know why?
Here is my code in my test application:
Parent unit1.pas is listed below. Parent Form1 only has 2 buttons and 1 shape.
unit Unit1;
{$mode objfpc}{$H }
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls, unit2;
type
{ TMainPortThread }
TMainPortThread = class(TThread)
private
procedure Synchronous;
protected
procedure Execute; override;
public
// constructor Create(CreateSuspended: boolean);
end;
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Label1: TLabel;
Shape1: TShape;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
what:boolean;
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
procedure Delay(AMiliSeconds: DWORD);
var
DW: DWORD;
begin
DW := GetTickCount64;
while (GetTickCount64 < DW AMiliSeconds) and (not Application.Terminated) do
begin
// nothing
end;
end;
{ For Thread }
procedure TMainPortThread.Synchronous;
begin
writeln('Parents Synchronous Method');
if Form1.what then
Form1.Shape1.Brush.Color := clRed
else
Form1.Shape1.Brush.Color := clLime;
end;
procedure TMainPortThread.Execute;
var
i:integer;
begin
while true do begin
Delay(500);
Synchronize(@Synchronous);
Form1.what := not Form1.what;
end;
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
settings : TForm2;
begin
settings := TForm2.Create(Form1);
settings.Show;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
TMainPortThread.Create(false);
end;
end.
The child Unit2.pas and Form2. Form2 only has 1 button and 1 shape.
unit Unit2;
{$mode objfpc}{$H }
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls;
type
{ TMainPortThread }
TSecondPortThread = class(TThread)
private
procedure Synchronous;
protected
procedure Execute; override;
public
// constructor Create(CreateSuspended: boolean);
end;
{ TForm2 }
TForm2 = class(TForm)
Button1: TButton;
Label1: TLabel;
Shape1: TShape;
procedure Button1Click(Sender: TObject);
private
what:boolean;
public
end;
var
Form2: TForm2;
implementation
{$R *.lfm}
procedure Delay(AMiliSeconds: DWORD);
var
DW: DWORD;
begin
DW := GetTickCount64;
while (GetTickCount64 < DW AMiliSeconds) and (not Application.Terminated) do
begin
// nothing
end;
end;
{ For Thread }
procedure TSecondPortThread.Synchronous;
begin
writeln('Child Synchronous Method');
if Form2.what then
Form2.Shape1.Brush.Color := clRed
else
Form2.Shape1.Brush.Color := clLime;
end;
procedure TSecondPortThread.Execute;
var
i:integer;
begin
while true do begin
Delay(500);
Synchronize(@Synchronous);
Form2.what := not Form2.what;
end;
end;
{ TForm2 }
procedure TForm2.Button1Click(Sender: TObject);
begin
TSecondPortThread.Create(false);
end;
end.
In Form1, the shape color alternates between red and green after click the button. Then open Form2 by clicking another button and click the button on Form2, the shape just stay the same color only. I don't get it.
If you want complete project, here it is: https://mega.nz/file/y8oEkbTS#EpsxNL6WhZL5qWvBijqcMD4NsPPn2c70CIsM7jwcHXc
Edit: @Tom gave the correct answer.
Just to add, since I wanted to retain the new form instance creation method, so to do it just remove the autocreate code in project.lpr, then use the actual Form name when creating it at Button1Click. ie Form2.CreateForm(). Do not declare another variable instance of the Form2 in Form1.
CodePudding user response:
In procedure TSecondPortThread.Synchronous;
you are referring to the autocreated form Form2
and its shape. However, even though the Form2
is created, it is never shown.
Instead, in procedure TForm1.Button1Click(Sender: TObject);
you are creating and showing an instance named settings
of type TForm2
. But the settings
form is not known to the blink timer thread.
One correction would be, as the Form2
is autocreated, to simply replace all code in TForm1.Button1Click()
with Form2.Show
.