Home > Mobile >  Synchronize not updating UI elements in a child form
Synchronize not updating UI elements in a child form

Time:11-23

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.

  • Related