How to create a form programmatically with a couple components on it in Delphi

后端 未结 2 711
抹茶落季
抹茶落季 2020-12-28 09:12

I\'m working with Delphi 7 and I\'m trying to create a form programmatically. Here\'s my form class stub:

unit clsTStudentInfoForm;

interface

    uses Form         


        
相关标签:
2条回答
  • 2020-12-28 10:06

    Creating modal forms with controls on the fly is easy:

    procedure CreateGreetingForm;
    var
      frm: TForm;
      lbl: TLabel;
      edt: TEdit;
      btn: TButton;
    begin
    
      frm := TForm.Create(nil);
      try
        lbl := TLabel.Create(frm);
        edt := TEdit.Create(frm);
        btn := TButton.Create(frm);
        frm.BorderStyle := bsDialog;
        frm.Caption := 'Welcome';
        frm.Width := 300;
        frm.Position := poScreenCenter;
    
        lbl.Parent := frm;
        lbl.Top := 8;
        lbl.Left := 8;
        lbl.Caption := 'Please enter your name:';
    
        edt.Parent := frm;
        edt.Top := lbl.Top + lbl.Height + 8;
        edt.Left := 8;
        edt.Width := 200;
    
        btn.Parent := frm;
        btn.Caption := 'OK';
        btn.Default := true;
        btn.ModalResult := mrOk;
        btn.Top := edt.Top + edt.Height + 8;
        btn.Left := edt.Left + edt.Width - btn.Width;
    
        frm.ClientHeight := btn.Top + btn.Height + 8;
        frm.ClientWidth := edt.Left + edt.Width + 8;
    
        if frm.ShowModal = mrOk then
          ShowMessageFmt('Welcome, %s', [edt.Text]);
    
      finally
        frm.Free;
      end;
    
    end;
    
    0 讨论(0)
  • 2020-12-28 10:07

    By default (that is: with all default IDE configuration settings), newly designed forms are automatically created. Only the main form will be shown, and secondary forms can be shown with:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Form2.Show;
      Form3.ShowModal;
    end;
    

    It is good common practice to disable this auto creation option. Go to: Tools > (Environment) Options > (VCL) Designer > Module creation options, and disable/uncheck the Auto create forms & data modules option.

    Instead, create an (already designed) form only when it is needed:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Form: TForm2;
    begin
      Form := TForm2.Create(Self);
      Form.Show;
    end;
    

    This illustrates as well that the global variables for the secondary forms are not needed, and it is good common practice to delete them as soon as possible to prevent wrong usage:

    type
      TForm2 = class(TForm)
      end;
    
    //var
    //  Form2: TForm2;  << Always delete these global variable
    
    implementation
    

    If you do not want to set up such secondary form with the form designer, then you need to create all controls in code at runtime. As follows:

    unit Unit2;
    
    interface
    
    uses
      Classes, Forms, StdCtrls;
    
    type
      TForm2 = class(TForm)
      private
        FButton: TButton;
      public
        constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override;
      end;
    
    implementation
    
    { TForm2 }
    
    constructor TForm2.CreateNew(AOwner: TComponent; Dummy: Integer = 0);
    begin
      inherited CreateNew(AOwner);
      FButton := TButton.Create(Self);
      FButton.SetBounds(10, 10, 60, 24);
      FButton.Caption := 'OK';
      FButton.Parent := Self;
    end;
    
    end.
    

    As you see, I used the CreateNew constructor. This is necessary for T(Custom)Form derivatives:

    Use CreateNew instead of Create to create a form without using the associated .DFM file to initialize it. Always use CreateNew if the TCustomForm descendant is not a TForm object or a descendant of TForm.

    For all other container controls (such as TPanel, TFrame, etc.) you can override the default constructor Create.

    Call this form as follows:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Form: TForm2;
    begin
      Form := TForm2.Create(nil);
      try
        Form.ShowModal;
      finally
        Form.Free;
      end;
    end;
    

    Or:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      FForm := TForm2.CreateNew(Application);
      FForm.Show;
    end;
    

    In this last case, the form is not freed but hidden when it is closed, so you need to store its reference in a private field (FForm) and free it later. Or you can do it automatically:

    unit Unit2;
    
    interface
    
    uses
      Classes, Forms, StdCtrls;
    
    type
      TForm2 = class(TForm)
      private
        FButton: TButton;
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      public
        constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override;
      end;
    
    implementation
    
    { TForm2 }
    
    constructor TForm2.CreateNew(AOwner: TComponent; Dummy: Integer = 0);
    begin
      inherited CreateNew(AOwner);
      OnClose := FormClose;
      FButton := TButton.Create(Self);
      FButton.SetBounds(10, 10, 60, 24);
      FButton.Caption := 'OK';
      FButton.Parent := Self;
    end;
    
    procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caFree;
    end;
    
    end.
    

    Now, you could call it without storing a reference:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      TForm2.CreateNew(Self).Show;
    end;
    

    Whether you pass, Self, Application or nil as owner for the new form depends on when you want to get it automatically destroyed in case you do not free it manually or via the OnClose event. Using

    • Self: will destroy the new form when the calling form is destroyed. This is particularly usefull when the calling form isn't the main form.
    • Application: will destroy the new form when the application ends. This would be my preferred choice.
    • nil: will not destroy the new form and results in a memory leak at application's finish. Though, memory will ultimately be released when Windows kills the process.
    0 讨论(0)
提交回复
热议问题