1. 이중 폼
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.

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)
차이점 설명
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 창이 표시될 때



디버그 포맷만 설정하면 정상적으로 사용할 수 있습니다.