1. 2つのフォーム
ポップアップ機能を実装します。Form1(メインフォーム)+Form2(ポップアップウィンドウ)の構成で作成します
1. 操作手順
- 新規プロジェクトを作成し、Form1にButton1を配置。
Caption = Open Form2に変更し、OnClickイベントを作成します。フォームデザイン画面でボタンをダブルクリックすると素早くクリックイベントを生成可能; - 上部メニュー
File → New FormからForm2を作成; - Form2にButton1を配置し、
Caption = Closeを設定してOnClickイベントを作成; - フォーム切り替えショートカット:
Shift+F12フォーム一覧表示 /F12デザイン画面・ソースコード画面切り替え; - Unit1からUnit2を参照:
interface usesの中にUnit2を追加。
Unit1(メインフォーム)
注意点は2箇所あります。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(サブフォーム)
プロジェクトに2番目のフォームを追加する手順

追加完了後、エディタ上部にタブが1つ増えます
一方がメインウィンドウ、もう一方がForm2のソースコードタブとなります


Form2を編集したい場合はUnit2タブを選択しF12キーを押すと、Form2のデザイン画面が開きます

前回の講義通りにボタンを追加し、キャプションを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にボタンを2つ追加します:
- 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)
違いの解説
Show(非モーダルウィンドウ)
- サブフォームを開いた直後にコード実行が続行;
- メインフォームのドラッグや他ボタンのクリックが自由;
Form2.Visible := True;と同等、自動的に最前面に表示される。
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); // カウントを+1
Form2.ShowModal;
end;Code language: JavaScript (javascript)
Unit2で開いた回数をポップアップ表示
procedure TForm2.Button1Click(Sender: TObject);
begin
ShowMessage('このフォームは '+IntToStr(Count)+' 回開かれています');
end;Code language: JavaScript (javascript)
コーディング規約推奨:グローバル・公開変数は極力使用せず、Propertyプロパティによる値渡しを推奨します。
5. フォームを動的に生成する
プロジェクト自動生成のグローバルForm変数に依存しない実装
方法1:事前デザイン済みForm2を動的生成
Project.lprを開き、Application.CreateForm(TForm2, Form2);の行を削除- 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」のダイアログが表示される場合



デバッグ情報フォーマットを設定するだけで正常に動作します。
Lazarus 複数フォームの使い方解説