Как да създадете формуляр програмно с няколко компонента върху него в Delphi

Работя с Delphi 7 и се опитвам да създам формуляр програмно. Ето моята част от класа на формуляра:

unit clsTStudentInfoForm;

interface

    uses Forms;

    type
        TStudentInfoForm = class (TForm)

        end;

implementation


end.

Също така имам бутон в основния си формуляр (това е просто обикновен формуляр, който трябва да създаде и покаже формуляра по-горе по време на изпълнение) и когато се щракне върху него, той създава и показва формуляра на ученика като модален прозорец. Показва формуляра, но в него няма нищо. Единственото нещо, което можете да направите, е да щракнете върху бутона за затваряне в горния десен ъгъл на прозореца, за да го затворите.

procedure TLibraryForm.btnShowStudentIfoFormClick(Sender: TObject);
var
    f : TStudentInfoForm;
begin
    f := TStudentInfoForm.CreateNew(Self);
    f.ShowModal;
    f.Free;
    f := nil;
end;

въведете описание на изображението тук

Нямам представа как да добавя компоненти към програмно създадена форма (не по време на изпълнение, а към изходния код). Можете ли да ми помогнете да напиша някакъв код, който добавя бутон „Добре“ към формуляра на ученика, както и задава надписа и височината и ширината на формуляра (кодът трябва да бъде написан във файла с формуляра на ученика)?

Всички предложения и примери ще бъдат високо оценени. Благодаря ти.


person Mikhail    schedule 19.04.2013    source източник
comment
За да създадете формуляр с контроли изцяло по време на изпълнение, вижте Dialogs.CreateMessageDialog за пример.   -  person NGLN    schedule 20.04.2013


Отговори (2)


По подразбиране (т.е. с всички настройки за конфигурация на IDE по подразбиране), новоразработените формуляри се създават автоматично. Ще бъде показан само основният формуляр, а вторичните формуляри могат да бъдат показани с:

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

Добра обичайна практика е да деактивирате тази опция за автоматично създаване. Отидете на: Инструменти > (Околна среда) Опции > (VCL) Дизайнер > Опции за създаване на модул и деактивирайте/махнете отметката от опцията Автоматично създаване на формуляри и модули с данни.

Вместо това създайте (вече проектиран) формуляр само когато е необходим:

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

Това също илюстрира, че глобалните променливи за вторичните форми не са необходими и е добра обичайна практика да ги изтриете възможно най-скоро, за да предотвратите неправилна употреба:

type
  TForm2 = class(TForm)
  end;

//var
//  Form2: TForm2;  << Always delete these global variable

implementation

Ако не искате да настроите такъв вторичен формуляр с дизайнера на формуляри, тогава трябва да създадете всички контроли в код по време на изпълнение. Както следва:

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.

Както виждате, използвах конструктора CreateNew. Това е необходимо за T(Custom)Form производни:

Използвайте CreateNew вместо Create, за да създадете формуляр, без да използвате свързания .DFM файл за инициализиране. Винаги използвайте CreateNew, ако наследникът TCustomForm не е обект TForm или наследник на TForm.

За всички други контейнерни контроли (като TPanel, TFrame и т.н.) можете да замените конструктора по подразбиране Create.

Обадете се на този формуляр, както следва:

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;

В този последен случай формулярът не се освобождава, а се скрива, когато се затвори, така че трябва да съхраните препратката му в лично поле (FForm) и да го освободите по-късно. Или можете да го направите автоматично:

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.

Сега можете да го извикате, без да съхранявате препратка:

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

Дали ще преминете Self, Application или nil като собственик на новия формуляр зависи от това кога искате той да бъде унищожен автоматично, в случай че не го освободите ръчно или чрез събитието OnClose. Използвайки

  • Self: ще унищожи новата форма, когато извикващата форма бъде унищожена. Това е особено полезно, когато формата за повикване не е основната форма.
  • Application: ще унищожи новия формуляр, когато приложението приключи. Това би бил моят предпочитан избор.
  • nil: няма да унищожи новия формуляр и води до изтичане на памет при завършване на приложението. Въпреки това паметта в крайна сметка ще бъде освободена, когато Windows убие процеса.
person NGLN    schedule 19.04.2013
comment
Благодаря много. Точно това е предписал лекарят. Но извикването на формуляра по този начин TForm2.CreateNew(Self).Show гарантира ли, че той ще бъде изтрит при затваряне? - person Mikhail; 20.04.2013
comment
@NGLN, хубаво обяснение. Благодаря много, вашият отговор разреши проблема ми. - person ; 02.07.2017
comment
човече, ти ми спести много работа тук, страхотно, наистина страхотно разглеждане - person Wh1T3h4Ck5; 23.04.2020

Създаването на модални форми с контроли в движение е лесно:

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;
person Andreas Rejbrand    schedule 19.04.2013
comment
Готино. Но искам да пакетирам тези контроли във файла на класа на формуляра. - person Mikhail; 20.04.2013
comment
@Mikhail: Тогава го направете в FormCreate за вашето TStudentInfoForm вместо това. Но ако имате файл с клас на формуляр, можете да го оформите визуално и не е необходимо да го правите в код на първо място. - person Ken White; 20.04.2013
comment
@KenWhite: Не го правете в събитието OnCreate на класа. Вместо това накарайте класа да замени своя конструктор. - person Remy Lebeau; 20.04.2013
comment
@Remy: Това не беше моята гледна точка, която явно не сте прочели. :-) Ако искате да поставите контролите на формуляра в неговата декларация, можете също така да използвате .dfm по подразбиране и да го създадете визуално, където можете да го подредите и да свържете манипулатори на събития и да зададете свойства. Но си прав - в нормалния случай конструкторът би бил правилен. Ако го правите само веднъж без видима причина, FormCreate е добре, защото никой друг няма да създава формуляра. Не е като да създавате компонент за повторна употреба; няма нужда да резервирате събитието за друг разработчик. - person Ken White; 20.04.2013