라자루스 다중 폼 활용

1. 이중 폼

Form1(메인 폼) + Form2(팝업 창) 구조로 팝업 기능을 구현합니다

1. 작업 순서

  1. 새 프로젝트를 생성한 뒤 Form1에 Button1을 배치하고 Caption = Open Form2로 수정한 후 OnClick 이벤트를 생성합니다 (디자인 창에서 버튼을 더블클릭하면 클릭 이벤트를 빠르게 만들 수 있습니다);
  2. 상단 메뉴 File → New Form을 클릭해 Form2를 생성합니다;
  3. Form2에 Button1을 추가하고 Caption = Close로 설정한 뒤 OnClick 이벤트를 만듭니다;
  4. 폼 전환 단축키: Shift+F12 폼 목록 호출 / F12 디자인/코드 화면 전환;
  5. 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)

차이점 설명

  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); // 카운트 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 동적 생성

  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 창이 표시될 때

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

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다