Recent

Author Topic: Child Form Operate Independently From Parent  (Read 5051 times)

bpharri2

  • Newbie
  • Posts: 2
Child Form Operate Independently From Parent
« on: June 22, 2011, 09:51:00 pm »
I am trying to write an application with a main form that, OnCreate, calls another form that display a message while it checks for an internet connection. While this check is being done, I want the main form to continue to be accessible. Unfortunately, I cannot get it to work. I tried multithreading but then form2 displays briefly before disappearing. I know I'm doing something wrong but cannot figure it out.

For ease of figuring this out, I've made some dummy forms for testing. What I want is:
Form1 displays, Form1 opens Form2, Form2 pauses for 10 seconds and then displays a message. While Form2 is paused, I want to be able to still access Form1.

Unit1 (initial view; no multi-threading)
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons;

type

  { TForm1 }

  TForm1 = class(TForm)
    BitBtn2: TBitBtn;
    procedure BitBtn2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.lfm}

{ TForm1 }

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
  ShowMessage('Test 1');
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  MyThread : TMyThread;
begin
  frm2 := TForm2.Create(Application);
  frm2.Show;
end;

end.

Unit2:
Code: [Select]
unit Unit2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons,
  ExtCtrls;

type

  { TForm2 }

  TForm2 = class(TForm)
    BitBtn1: TBitBtn;
    Timer1: TTimer;
    procedure BitBtn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure TestMessage();
    procedure Timer1Timer(Sender: TObject);
  public
    { public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.lfm}

{ TForm2 }

procedure TForm2.BitBtn1Click(Sender: TObject);
begin
  ShowMessage('Test 2');
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  Timer1.Interval := 4000;
  Timer1.Ontimer := @Timer1Timer;
  Timer1.Enabled := True;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  TestMessage();
end;

procedure TForm2.TestMessage();
var x:integer;
begin
   for x:=1 to 10 do
     sleep(1000);
   showmessage('hello');
end;

end.

I then tried multi-threading from examples on the Lazarus Wiki:

Unit1 (multithreading):
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons;

type

  { TForm1 }

  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
    procedure BitBtn2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Unit3;

{$R *.lfm}

{ TForm1 }

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
  ShowMessage('Test 1');
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  MyThread : TMyThread;
begin
  MyThread := TMyThread.Create(True);
  MyThread.Resume;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  MyThread : TMyThread;
begin
  MyThread := TMyThread.Create(True);
  MyThread.Resume;
end;

end.

Unit2 stays the same as above

Unit3
Code: [Select]
unit Unit3;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms;

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  public
    Constructor Create(CreateSuspended : boolean);
  end;

implementation

uses Unit2;

constructor TMyThread.Create(CreateSuspended : boolean);
begin
  FreeOnTerminate := True;
  inherited Create(CreateSuspended);
end;

procedure TMyThread.Execute;
var
  frm2 : TForm2;
begin
  frm2 := TForm2.Create(Application);
  frm2.Show;
end;

end.

eny

  • Hero Member
  • *****
  • Posts: 1658
Re: Child Form Operate Independently From Parent
« Reply #1 on: June 22, 2011, 10:12:08 pm »
Your code is not far off. The one thing that you need to remember is that your main program is executed in 1 thread (the 'main LCL thread'). So if you do anything time consuming then your entire program will slow down or seems to come to a halt. And this is exactly what you have done for form 2: the sleep() in method TestMessage() on Form2 will block your program until all the waiting time has passed.
Also you cannot do anything time consuming on form1 and hope that either form1 or form2 will respond.

The way to do it (and you were almost there):
- in form1: display form 2;
- in form1 create a new thread and in that thread check the connection;
- in form1 periodically check if the thread has finished (e.g. via a timer);
- when the thread has finished do your other processing.

Before staring with threads do read the Wiki article and do some experimenting first. Threads are not extremely complicated, but there are a couple of caveats you need to be aware of (like how to sync with the main thread for instance).
All posts based on: Win11; Lazarus 4_4  (x64) 12-02-2026 (unless specified otherwise...)

bpharri2

  • Newbie
  • Posts: 2
Re: Child Form Operate Independently From Parent
« Reply #2 on: June 24, 2011, 12:26:19 am »
That worked like a charm! Thank you so much.

 

TinyPortal © 2005-2018