Recent

Author Topic: Creating multiple (maybe hundreds) of almost-identical TForms  (Read 11353 times)

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Creating multiple (maybe hundreds) of almost-identical TForms
« on: September 02, 2014, 12:38:28 pm »
I have a server-client app already working very well and stable (using indy)

Now i want add a new feature to it, but i need create dinamical forms in the server code, almost all them identical to one already designed with the ide.

What it means? I added a new form in the lazarus IDE, lets say it is called 'unitStandard'; it have it own buttons, labels, etc, but at runtime i need a lot of identical forms with just some diferent values to their controls variables (but containing the same controls).

Can it be done? If, so, how?

Thanks in advance
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #1 on: September 02, 2014, 12:42:48 pm »
Code: [Select]
uses uMyForm;

procedure DomyStuff1;
var
  vFrm :TMyForm;
begin
  vFrm := TMyForm.Create(application);
  vFrm.MyButton.Caption := 'This is Stuff1';
  vfrm.Show;
end;

procedure DomyStuff2;
var
  vFrm :TMyForm;
begin
  vFrm := TMyForm.Create(application);
  vFrm.MyButton.Caption := 'This is Stuff 2';
  vfrm.Show;
end;

Keep in mind that it is impossible to add code to the form at runtime but you can set any property or control's property that they are already on the form.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #2 on: September 02, 2014, 01:12:47 pm »
If i assign aplication as owner, those new forms will remain open until the main form is closed, even if they are called from a different form?

How i can assign different values to their position at creation, relative to the mainform? Lets say mainform.left+10, mainform.y+10 ?

Thanks a lot
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #3 on: September 02, 2014, 01:17:40 pm »
Quote
it is impossible to add code to the form at runtime
@taazz: Are you sure that this statement is true? What's wrong with the next code?

Code: [Select]
procedure DomyStuff1;
var
  vFrm :TMyForm;
  vEdit: TEdit;
begin
  vFrm := TMyForm.Create(application);
  vFrm.MyButton.Caption := 'This is Stuff1';

  vEdit := TEdit.Create(vFrm);
  vEdit.Parent := vFrm;
  vEdit.Left := 10;
  vEdit.Text := 10;
  vEdit.Text := 'Something';

  vfrm.Show;
end;
« Last Edit: September 02, 2014, 01:19:18 pm by wp »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #4 on: September 02, 2014, 01:37:00 pm »
Quote
it is impossible to add code to the form at runtime
@taazz: Are you sure that this statement is true? What's wrong with the next code?

Code: [Select]
procedure DomyStuff1;
var
  vFrm :TMyForm;
  vEdit: TEdit;
begin
  vFrm := TMyForm.Create(application);
  vFrm.MyButton.Caption := 'This is Stuff1';

  vEdit := TEdit.Create(vFrm);
  vEdit.Parent := vFrm;
  vEdit.Left := 10;
  vEdit.Text := 10;
  vEdit.Text := 'Something';

  vfrm.Show;
end;

I do not consider creation of a control as "code addition" you dynamically create something that the code is already in the executable. When I said  "code addition" I was refferring to the ability that all dynamic (scripting really) languages (like python, javascript etc) have to be able to build the code to be executed at runtime and use that as variable to an event. If I had to make a distinction between the two I would say that what you describe is "code insertion" in any case I would rather avoid introducing any new acronyms we already have way to many of them.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #5 on: September 02, 2014, 02:50:11 pm »
How i can assign different values to their position at creation, relative to the mainform? Lets say mainform.left+10, mainform.y+10 ?

The following unit shows one way to do this.
Code: [Select]
unit mainIdenticalForms;

{$mode objfpc}{$H+}

interface

uses
  SysUtils, Forms, Controls, StdCtrls, Classes;

type

  { TbaseForm }

  TbaseForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  end;

  procedure CreateBaseFormCopies(nCopies: integer);

var
  baseForm: TbaseForm;

implementation

uses Dialogs;

procedure CreateBaseFormCopies(nCopies: integer);
var
  bf: TbaseForm;
  button: TButton;
  i, j: Integer;
begin
  for j:=0 to nCopies-1 do begin
    bf:=TbaseForm.CreateNew(Application, i);
    i:=j+1;
    bf.Caption:=Format('Form number %d',[i]);
    bf.Left:=baseForm.Left+(i*30);
    bf.Top:=baseForm.Top+(i*30);
    button:=TButton.Create(bf);
    button.Caption:=Format('Button#%d',[i]);
    button.Autosize:=True;
    button.Left:=10;
    button.Top:=10;
    button.Tag:=i;
    button.OnClick:=@baseForm.Button1Click;
    button.Parent:=bf;
    bf.Show;
  end;
end;

{$R *.lfm}

{ TbaseForm }

procedure TbaseForm.Button1Click(Sender: TObject);
begin
  ShowMessageFmt('You clicked Button#%d',[(Sender as TButton).Tag]);
end;

procedure TbaseForm.FormCreate(Sender: TObject);
begin
  CreateBaseFormCopies(5);
end;

end.


torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #6 on: September 02, 2014, 03:33:12 pm »
Great, i already solved this perfectly!!

Thanks a lot!!


And how i could acces each new form? How i could identify each one so i could acces it separately from the main form?
« Last Edit: September 02, 2014, 04:38:53 pm by torbente »
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

eny

  • Hero Member
  • *****
  • Posts: 1634
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #7 on: September 02, 2014, 05:29:17 pm »
Collect them in a TList and set the Tag property to each form with a unique value (form 1: tag = 1; form 2: tag = 2 etc. Main form: Tag remains 0).
All posts based on: Win10 (Win64); Lazarus 2.0.10 'stable' (x64) unless specified otherwise...

minesadorada

  • Sr. Member
  • ****
  • Posts: 452
  • Retired
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #8 on: September 02, 2014, 05:42:00 pm »
..or declare an open array of TForm and use SetLength - would that work?
GPL Apps: Health MonitorRetro Ski Run
OnlinePackageManager Components: LazAutoUpdate, LongTimer, PoweredBy, ScrollText, PlaySound, CryptINI

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #9 on: September 03, 2014, 09:09:53 pm »
An array could be a good workaround, nice suggestion, thanks.

I just coded a demo form, and my app opened 5 almost-identical forms. Since it is needed to include some values into each form, i use a couple of TEdits on it, so...

CopyForm. := DemoForm.create (application);
CopyForm.TEditDefaultValue1 := '20';
CopyForm.Visible := true;

TEditDefaultValue1 is different for every copy, and it worked perfect. But all the other variables in unit DemoForm changes everytime each of the copyforms use it, and my app hang out soon.

Is there anyway to assign a group of variables to be used just in the form, but the unit have plenty access to it separately? I need that everyform works as a different unit once created.
« Last Edit: September 03, 2014, 09:12:19 pm by torbente »
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1260
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #10 on: September 03, 2014, 09:28:40 pm »
Quote
Is there anyway to assign a group of variables to be used just in the form, but the unit have plenty access to it separately? I need that everyform works as a different unit once created
Code: [Select]
  TbaseForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  Private
    FVariable: String;  // <-- Declare all your variables in Private. 
                                // Each Form will have their own copy...
  end;

If you're asking what I think you're asking (and I think you are), then the above is the way to declare variables you want to be specific to each instance of the form.
FVariable will only be accessible from methods and functions that are part of the form.  Use FormCreate to initialise them.
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #11 on: September 04, 2014, 03:46:37 am »
Yes, it is what i was looking for. Every new form created have its own set of variables! I really did not know what the private section was for until now and i have some question in case someone could help me (or point me to a good url where i could  read more)

- Are the components also exclusive of each form instance? (components like tStringGrid, TTimer and so on)

- I already try, but variables declared in the private section can not be set  when the form is created?

- Every form created with the IDE must include one unit? Is there any way to desgin a form without a new unit?

Thanks a lot
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #12 on: September 04, 2014, 04:08:48 am »
- Are the components also exclusive of each form instance? (components like tStringGrid, TTimer and so on)
Yes.

- I already try, but variables declared in the private section can not be set  when the form is created?
They are private to the form class. Member methods of the from can change their values. If you need to change their values from outside the form class methods, then declare them in a public section:
Code: [Select]
  TSomeForm = class(TForm)
...
  Public
    SomeVariable: String;
...

- Every form created with the IDE must include one unit? Is there any way to desgin a form without a new unit?
Yes. You can add controls to any form at run-time. But why do you need it?. Anyway, try this:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  aForm: TForm;
  aLabel: TLabel;
  aEdit: TEdit;
begin
  //Create an empty form
  aForm := TForm.Create(nil);

  //Create a label
  aLabel := TLabel.Create(aForm);
  aLabel.Left := 10;
  aLabel.Top := 10;
  aLabel.Caption := 'Hello World';
  aLabel.Parent := aForm;

  //Create an edit
  aEdit := TEdit.Create(aForm);
  aEdit.Left := aLabel.Left + aLabel.Width + 10;
  aEdit.Top := aLabel.Top;
  aEdit.Parent := aForm;

  //Show the form
  aForm.Show;
end;
« Last Edit: September 04, 2014, 04:17:34 am by engkin »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #13 on: September 04, 2014, 04:16:08 am »
Yes, it is what i was looking for. Every new form created have its own set of variables! I really did not know what the private section was for until now and i have some question in case someone could help me (or point me to a good url where i could  read more)

- Are the components also exclusive of each form instance? (components like tStringGrid, TTimer and so on)

- I already try, but variables declared in the private section can not be set  when the form is created?

- Every form created with the IDE must include one unit? Is there any way to desgin a form without a new unit?

Thanks a lot

every variable declared in the form can have different value for every form instance regardless of where they are declared (ee private, protected etc).
take a look on this starter http://wiki.freepascal.org/Object_Oriented_Programming_with_Free_Pascal_and_Lazarus.

1) each form instance has its own component instances too there is no overlapping between the instances.
2) The private section is what the word says private and doesn't allow access from the outside world, you can create a public method that you can call to set the variables from outside.

3) yes every and each form has a single line {$R *.lfm}, this line instracts the ide to load the lfm file of the form where all your settings are saved with out it you have to write everything by hand no object inspector, no form designer, no visual aid at all. Why what is the problem of having one file per form? you are after all creating them dynamically.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Creating multiple (maybe hundreds) of almost-identical TForms
« Reply #14 on: September 08, 2014, 06:42:28 pm »
Ok, i think i have almost everything ready.

One more thing. How i can bringtofront a specific form that already exist?

copyform[number].show;
copyform[number].bringtofront;
copyform[number].visible := true;

All  give me errors SIGSEGV.  :(


Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

 

TinyPortal © 2005-2018