Многоконная разработка в Lazarus

1. Две формы

Реализуем всплывающее окно: Form1 (основная форма) + Form2 (окно попапа)

1. Пошаговая инструкция

  1. Создайте новый проект, перетащите кнопку Button1 на Form1, установите Caption = Open Form2 и создайте событие OnClick (можно быстро создать клик двойным щелчком по кнопке в дизайне формы);
  2. Через верхнее меню File → New Form создайте вторую форму Form2;
  3. Разместите Button1 на Form2, задайте Caption = Close и создайте событие OnClick для неё;
  4. Горячие клавиши для переключения форм: Shift+F12 открыть список форм / F12 переключать вид дизайна и кода;
  5. Подключить Unit2 в Unit1: добавьте строку Unit2 в блок interface uses.

Unit1 (Основная форма)

Есть два важных момента: Unit2; // Подключение модуля Unit2

Второй момент находится внутри обработчика клика — открыть Form2 как модальное окно командой Form2.ShowModal; // Модальный показ Form2

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Unit2; // Подключаем Unit2 

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal; // Модальный показ Form2
end;

end.

Unit2 (Дочерняя форма)

Как добавить вторую форму в проект

После добавления в редакторе появится дополнительная вкладка

Одна вкладка содержит код основной формы, другая — код Form2

Чтобы редактировать Form2, выберите вкладку Unit2 и нажмите F12 — откроется дизайнер формы

Добавьте кнопку, установите надпись Close и реализуйте закрытие окна, как показано в предыдущих уроках. Вы можете сделать это самостоятельно.

unit Unit2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm2 }

  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form2: TForm2;

implementation

{$R *.lfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  Close; // Закрыть текущую Form2
end;

end.

2. Основные различия Show и ShowModal (сравнительный пример)

Изменение интерфейса

Добавьте две кнопки на Form1:

  • btnShow: Caption = Show
  • btnShowModal: Caption = ShowModal
// Немодальный вызов Show
procedure TForm1.btnShowClick(Sender: TObject);
begin
  Form2.Show;
  ShowMessage('Окно Form2 открыто, основная форма доступна для работы');
end;

// Модальный вызов ShowModal
procedure TForm1.btnShowModalClick(Sender: TObject);
begin
  Form2.ShowModal;
  ShowMessage('Это сообщение появится только после закрытия Form2');
end;Code language: JavaScript (javascript)

Объяснение различий

  1. Show (немодальное окно)
  • Код продолжает выполняться сразу после открытия дочерней формы;
  • Основную форму можно перетаскивать и нажимать другие кнопки;
  • Эквивалентно записи Form2.Visible := True;, окно автоматически выводится на передний план.
  1. ShowModal (модальное окно)
  • Выполнение кода приостанавливается до закрытия дочерней формы;
  • Основная форма блокируется, взаимодействие с ней невозможно;
  • Это функция, возвращающая значение ModalResult для определения способа закрытия окна.

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

3. Взаимный вызов форм: исправление ошибки циклической ссылки

Задача: Form1 открывает Form2, Form2 открывает Form1
Взаимное подключение модулей в блоке interface uses вызовет ошибку циклических зависимостей. Решение: перенести подключения в блок implementation

Unit1

unit Unit1;

interface
uses Forms,StdCtrls;

type
  TForm1=class(TForm)
    Button1:TButton;
    procedure Button1Click(Sender:TObject);
  end;
var Form1:TForm1;

implementation
uses Unit2; // Подключение здесь
{$R *.lfm}

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

Unit2

unit Unit2;

interface
uses Forms,StdCtrls;

type
  TForm2=class(TForm)
    Button1:TButton;
    procedure Button1Click(Sender:TObject);
  end;
var Form2:TForm2;

implementation
uses Unit1; // Взаимные ссылки в блоке реализации
{$R *.lfm}

procedure TForm2.Button1Click(Sender:TObject);
begin
  Form1.Show;
end;
end.

4. Передача значений между формами (пример с публичной переменной-членом)

Функционал: при каждом открытии дочерней формы из основной увеличивать счётчик, дочерняя форма показывает общее количество открытий

Объявить публичную целую переменную в Unit2

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
    Count: Integer; // Публичная переменная, доступная из Unit1
  end;

Увеличить счётчик по клику кнопки в Unit1

procedure TForm1.Button1Click(Sender: TObject);
begin
  Inc(Form2.Count); // Увеличить счётчик на единицу
  Form2.ShowModal;
end;Code language: JavaScript (javascript)

Вывести количество открытий в сообщении из Unit2

procedure TForm2.Button1Click(Sender: TObject);
begin
  ShowMessage('Эта форма открыта '+IntToStr(Count)+' раз');
end;Code language: JavaScript (javascript)

Рекомендация по стилю кода: минимизируйте использование глобальных и публичных переменных, предпочитайте передачу данных через свойства Property.

5. Динамическое создание форм

Без использования автоматически генерируемых глобальных переменных форм проекта

Способ 1: Динамическое создание готовой Form2

  1. Откройте файл Project.lpr и удалите строку Application.CreateForm(TForm2, Form2);
  2. Код кнопки на Form1:
procedure TForm1.Button1Click(Sender: TObject);
var
  frm2: TForm2;
begin
  frm2 := TForm2.Create(nil); // Ручное создание экземпляра
  frm2.ShowModal;
  FreeAndNil(frm2); // Освободить память, избежать утечек
end;Code language: JavaScript (javascript)

Способ 2: Полностью генерировать форму кодом (без предварительного дизайна)

По нажатию кнопки создаётся новое окно со встроенной кнопкой закрытия

unit Unit1;

interface

uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure DynamicBtnClick(Sender: TObject); // Обработчик для динамической кнопки
  public
  end;

var Form1: TForm1;

implementation
{$R *.lfm}

procedure TForm1.DynamicBtnClick(Sender: TObject);
begin
  ShowMessage('Закрываем динамически созданное окно');
  TForm(TButton(Sender).Parent).Close;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyForm: TForm;
  MyBtn: TButton;
begin
  MyForm := TForm.Create(nil);
  MyForm.SetBounds(100,100,220,150);
  MyForm.Caption := 'Динамически созданная форма';

  // Создать кнопку, владелец MyForm — кнопка удалится автоматически при закрытии окна
  MyBtn := TButton.Create(MyForm);
  MyBtn.SetBounds(10,10,200,30);
  MyBtn.Caption := 'Закрыть окно';
  MyBtn.Parent := MyForm;
  MyBtn.OnClick := @DynamicBtnClick;

  MyForm.ShowModal;
  FreeAndNil(MyForm);
end;
end.

Появляется окно «Choose Debug Information format»

Достаточно настроить формат отладочной информации, чтобы всё работало корректно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *