一、雙表單
實作彈窗功能,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(主表單)
有兩處重點須注意:Unit2; // 引入 Unit2
第二處則是點擊函式內,以模態視窗方式開啟第二個表單: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 即可開啟 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.

二、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)
差異說明
Show(非模態視窗)
- 開啟子表單後,程式碼會繼續往下執行;
- 主表單可拖曳、點擊其他按鈕;
- 等同
Form2.Visible := True;,並自動置頂顯示。
ShowModal(模態彈窗)
- 程式執行暫停,直到子表單關閉才會繼續;
- 主表單鎖定,無法進行任何操作;
- 屬於函式,可透過回傳
ModalResult判斷視窗關閉方式。
簡單總結:模態模式開啟時,必須先關閉子視窗才能操作主視窗;非模態模式開啟子視窗後,仍可自由操作主視窗。
三、表單互相呼叫:解決循環引用錯誤
需求: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.
四、表單之間傳遞數值(公用成員變數範例)
功能說明:主表單點擊開啟子表單時計數,子表單可查詢累計開啟次數
在 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 進行參數傳遞。
五、動態建立表單
不依賴專案自動產生的全域 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 多表單開發介紹
Previous: Lazarus IDE 編輯器視窗完整介紹