Recent

Author Topic: [Solved]Forms and Units; Form Classes  (Read 17940 times)

cov

  • Full Member
  • ***
  • Posts: 241
[Solved]Forms and Units; Form Classes
« on: April 02, 2013, 08:15:06 am »
When you use the IDE (File->New Form) to create a new form and unit pair, the relationship between the two is defined automatically.

Code: [Select]
type
  TForm2 = class(TForm)
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form2: TForm2;

implementation       

Procedures are automatically:

Code: [Select]
type

  { TForm2 }

  TForm2 = class(TForm)
    procedure FormClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.lfm}

{ TForm2 }

procedure TForm2.FormClick(Sender: TObject);
begin

end; 

However, I'm creating the form dynamically at runtime.

My Unit is built as follows:

Code: [Select]
uses
  Classes, SysUtils,StdCtrls,Grids,Dialogs,Forms,ExtCtrls;

procedure buildBForm;
procedure OkayButtonClick(Sender: TObject);

var
  FormB: TForm;
  Button1,Button2,Button3,Button4: TButton;
  ...

implementation

procedure buildBForm;
begin
  FormB:=TForm.Create(nil);
  with FormB do
  begin
    Left:=442;
    Height:=338;
    Top:=40;
    Width:=676;
    Caption:='Incorporate into Database';
    Font.Name:='MS Sans Serif';
  end;
  Button3:=TButton.Create(FormB);
  with Button3 do
  begin
    Parent:=FormB;
    Left:=320;
    Height:=25;
    Top:=269;
    Width:=75;
    Caption:='Okay';
    Default:=True;
    OnClick:=@OkayButtonClick;
    TabOrder:=0;
  end;
  ...   

What is the correct way to do this?

I'm asking because the Code above does not compile. I get this error at the OnClick:=@OkayButtonClick line.

Quote
Error: Incompatible types: got "<address of procedure(TObject);Register>" expected "<procedure variable type of procedure(TObject) of object;Register>"

I'm assuming this is because I have incorrectly defined the procedure OkayButtonClick(Sender: TObject);
« Last Edit: April 06, 2013, 04:32:47 pm by cov »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Forms and Units; Form Classes
« Reply #1 on: April 02, 2013, 09:44:49 am »
Your variables and procedures should be in the memory of the form. Consider it like, what if you create 2 of these custom forms? Instead of procedure buildBForm; , while it works, it would be better practise to create the components in the form constructor.

Code: [Select]
TFormB = class(TForm)
  Button1, Button2, Button3, Button4: TButton;
  procedure OkayButtonClick(Sender: TObject);
public
  constructor Create;
end;

implementation

constructor TFormB.Create;
begin
  Left:=442;
  Height:=338;
  Top:=40;
  Width:=676;
  Caption:='Incorporate into Database';
  Font.Name:='MS Sans Serif';

  Button3:=TButton.Create(self);
  with Button3 do
  begin
    Parent:=self; // SELF here
    Left:=320;
    Height:=25;
    Top:=269;
    Width:=75;
    Caption:='Okay';
    Default:=True;
    OnClick:=@OkayButtonClick;
    TabOrder:=0;
  end;
end;

procedure TFormB.OkayButtonClick(Sender: TObject);
begin
  //...
end;

Leledumbo

  • Hero Member
  • *****
  • Posts: 8798
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Forms and Units; Form Classes
« Reply #2 on: April 02, 2013, 10:03:26 am »
Quote
Error: Incompatible types: got "<address of procedure(TObject);Register>" expected "<procedure variable type of procedure(TObject) of object;Register>"
Note the bold term above. When a procedure has "of object", it means the procedure must be a method, belonging to a class, not a global procedure.

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #3 on: April 02, 2013, 11:12:12 am »
Note the bold term above. When a procedure has "of object", it means the procedure must be a method, belonging to a class, not a global procedure.

Yes, that's roughly what I thought.

I posed the question about designing form on the mailing list: http://www.mail-archive.com/lazarus@lists.lazarus.freepascal.org/msg36871.html

Basically my project has (had) 6 forms and when I added a seventh, the project refused to accept it.

Juha's last post in this thread: http://www.lazarus.freepascal.org/index.php/topic,20139.msg115782.html#msg115782 implies that it's preferable to create forms on the fly than to use the IDE to construct forms as User137 suggests.


JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4568
  • I like bugs.
Re: Forms and Units; Form Classes
« Reply #4 on: April 02, 2013, 12:57:57 pm »
Juha's last post in this thread: http://www.lazarus.freepascal.org/index.php/topic,20139.msg115782.html#msg115782 implies that it's preferable to create forms on the fly than to use the IDE to construct forms as User137 suggests.

User137 explained a different thing. He should have written "... should be members of the form".

Creating a form when needed and then freeing it has another benefit. You don't need to clean the state of its GUI elements to default values. They have default values always after creation.

Juha
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #5 on: April 02, 2013, 02:36:18 pm »
That's fine; I'm not intending to criticize User137.

This particular form is actually immanently suitable for creation and disposal at runtime because it is not expected to form a major part of user interaction and should only really be used rarely to add records to a database.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Forms and Units; Form Classes
« Reply #6 on: April 02, 2013, 03:44:10 pm »
...to use the IDE to construct forms as User137 suggests.
Actually i didn't suggest that in my post at all. For code lines it will end up looking almost the same though. Is this what confused you? You have a form class for custom form just like IDE would create. But you don't have a .lfm, and create the components on the fly (in constructor as i suggested).

(But you can also design the forms yourself using IDE, create and free them as needed in application. Just delete it from the list of automatically created forms in project options, and do it in code yourself.)
« Last Edit: April 02, 2013, 03:46:15 pm by User137 »

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #7 on: April 02, 2013, 05:59:57 pm »
Yes, I suppose I am confused.

I'll have to look at your code more closely.

 :)

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #8 on: April 02, 2013, 06:31:51 pm »
I can't get it to work.

Code: [Select]
type

{ TFormB }

TFormB = class(TForm)
  Button1, Button2, Button3, Button4: TButton;
  ComboBox1: TComboBox;
  Label1,Label2: TLabel;
  Panel1: TPanel;
  ListBox1: TListBox;
  AttrGrid: TStringGrid;
  CheckBox1: TCheckBox;
  SelectDirectoryDialog1: TSelectDirectoryDialog;
  procedure LoadDwg;
  procedure OkayButtonClick(Sender: TObject);
  procedure ComboBox1Change(Sender: TObject);
  procedure ListBox1Click(Sender: TObject);
  procedure ListBox1MouseMove(Sender: TObject);
  procedure Button4Click(Sender: TObject);
  procedure Button1Click(Sender: TObject);
  procedure CheckBox1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
    constructor Create;
  end;


implementation

procedure TFormB.Create;
begin
  Left:=442;
  Height:=338;
  Top:=40;
  Width:=676;
  Caption:='Incorporate into Database';
  Font.Name:='MS Sans Serif';
  Button3:=TButton.Create(Self);
  with Button3 do
  begin
    Parent:=Self;
    Left:=320;
    Height:=25;
    Top:=269;
    Width:=75;
    Caption:='Okay';
    Default:=True;
    OnClick:=@OkayButtonClick;
    TabOrder:=0;
  end;             

unit_blocks.pas(46,18) Error: function header doesn't match any method of this class "TFormB.Create;"

:+(

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Forms and Units; Form Classes
« Reply #9 on: April 02, 2013, 06:41:18 pm »
Code: [Select]
...
implementation

procedure TFormB.Create;
begin
  Left:=442;
...
Must be:
Code: [Select]
constructor TFormB.Create;But you should rather override "constructor Create(TheOwner: TComponent);" and also call "inherited Create(Owner);" in the implementation.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #10 on: April 02, 2013, 06:48:09 pm »
Thanks.

Hadn't noticed that.

How do I call my form?

TFormB.Show; -> Error: Only class class methods, class properties and class variables can be accessed in class methods

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Forms and Units; Form Classes
« Reply #11 on: April 02, 2013, 06:57:34 pm »
You have to declare a variable:
Code: [Select]
var FormB: TFormB;and somewhere create it (and show):
Code: [Select]
FormB:=TFormB.Create;
FormB.Show;
and free somewhere too.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #12 on: April 02, 2013, 11:40:12 pm »
Where do I instantiate FormB:=TFormB.Create;

It just says Error: Identifier not found "FormB"

cov

  • Full Member
  • ***
  • Posts: 241
Re: Forms and Units; Form Classes
« Reply #13 on: April 03, 2013, 08:13:27 am »
I cannot instantiate my new form.

FormB: TFormB; is declared on the unit, but there seems to be no way of constructing it.

I have created a procedure 'buildform':
Code: [Select]
type

{ TFormB }

TFormB = class(TForm)
  FormB: TFormB;
  Button1, Button2, Button3, Button4: TButton;

  procedure buildForm;                           
  private
    { private declarations }
  public
    { public declarations }
    constructor Create;
  end;


implementation

constructor TFormB.Create;
begin                       
  ...
end;

procedure TFormB.buildForm;
begin
  FormB:=TFormB.Create;
  FormB.Show;
end;   

I then try to call it from another Unit:

Code: [Select]
unit7.TFormB.buildForm;
Error: Only class class methods, class properties and class variables can be accessed in class methods
« Last Edit: April 03, 2013, 08:16:52 am by cov »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Forms and Units; Form Classes
« Reply #14 on: April 03, 2013, 11:25:51 am »
Is that how variable form1: TForm1; is used on new projects?

Should be:
Code: [Select]
  TFormB = class(TForm)
    Button1, Button2, Button3, Button4: TButton;
  private
  ..
  public
  ..
  end;

var
  FormB: TFormB;

procedure buildFormB;

implementation

procedure buildFormB;
begin
  FormB.Free; // Maybe this here just in case
  FormB:=TFormB.Create;
end;
« Last Edit: April 03, 2013, 11:29:13 am by User137 »

 

TinyPortal © 2005-2018