1. Dois Formulários
Vamos implementar uma janela pop-up com Form1 (formulário principal) + Form2 (janela pop-up)
1. Passo a Passo
- Crie um novo projeto, arraste o Button1 para o Form1, altere
Caption = Open Form2e gere o eventoOnClick(você pode clicar duas vezes no botão diretamente no designer do formulário para criar o evento de clique rapidamente); - Acesse o menu superior
File → New Formpara criar o Form2; - Coloque um Button1 no Form2, defina
Caption = Closee gere seu eventoOnClick; - Atalhos para alternar formulários:
Shift+F12abrir lista de formulários /F12alternar visualização designer e código; - Referenciar Unit2 no Unit1: adicione
Unit2dentro da seçãointerface uses.
Unit1 (Formulário Principal)
Há dois pontos cruciais para atenção: Unit2; // Importar Unit2
O segundo ponto está dentro da função de clique: abrir a segunda janela de forma modal com Form2.ShowModal; // Exibir Form2 de forma modal
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Unit2; // Importar 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; // Exibir Form2 de forma modal
end;
end.
Unit2 (Formulário Filho)
Como adicionar o segundo formulário ao projeto

Após adicionar, uma aba extra aparecerá no editor de código
Uma aba contém o código do formulário principal, a outra guarda o código backend do Form2


Para editar o Form2, selecione a aba Unit2 e pressione F12 para abrir sua janela de designer

Adicione um botão, altere seu texto para Close e implemente a lógica de fechamento como visto nas aulas anteriores. Você pode concluir essa parte por conta própria.
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; // Fechar o Form2 atual
end;
end.

2. Diferenças Centrais entre Show e ShowModal (Exemplo Comparativo)
Modificar a Interface
Adicione dois botões no Form1:
- btnShow:Caption = Show
- btnShowModal:Caption = ShowModal

// Não modal com Show
procedure TForm1.btnShowClick(Sender: TObject);
begin
Form2.Show;
ShowMessage('O Form2 foi aberto, o formulário principal continua interativo');
end;
// Modal com ShowModal
procedure TForm1.btnShowModalClick(Sender: TObject);
begin
Form2.ShowModal;
ShowMessage('Essa mensagem só aparece após fechar o Form2');
end;Code language: JavaScript (javascript)
Explicação das Diferenças
Show(Não modal)
- A execução do código continua imediatamente após abrir o formulário filho;
- O formulário principal pode ser arrastado e outros botões clicados livremente;
- Equivale a
Form2.Visible := True;e traz a janela automaticamente para frente.
ShowModal(Janela Modal Pop-up)
- A execução do código é pausada até que o formulário filho seja fechado;
- O formulário principal é bloqueado e não pode ser manipulado;
- É uma função que retorna
ModalResultpara identificar como a janela foi fechada.
Resumo curto: uma janela modal obriga você a fechar o formulário filho antes de interagir com o principal; a não modal permite usar ambas as janelas ao mesmo tempo.
3. Chamadas Mútuas entre Formulários: Resolver Erro de Referência Circular
Requisito: Form1 abre Form2, Form2 abre Form1
Referenciar mutuamente dentro de interface uses causa erro de unidade circular. Solução: Mover as referências para a seção 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; // Coloque a referência aqui
{$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; // Referências mútuas ficam na implementação
{$R *.lfm}
procedure TForm2.Button1Click(Sender:TObject);
begin
Form1.Show;
end;
end.
4. Passar Valores entre Formulários (Exemplo com Variável Membro Pública)
Funcionalidade: incrementar um contador toda vez que o formulário principal abrir o filho; o formulário filho exibe quantas vezes foi aberto
Declarar variável inteira pública no Unit2
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
Count: Integer; // Variável pública acessível pelo Unit1
end;
Incrementar contador no clique do botão do Unit1
procedure TForm1.Button1Click(Sender: TObject);
begin
Inc(Form2.Count); // Contador +1
Form2.ShowModal;
end;Code language: JavaScript (javascript)
Exibir quantidade de aberturas em pop-up no Unit2
procedure TForm2.Button1Click(Sender: TObject);
begin
ShowMessage('Esse formulário foi aberto '+IntToStr(Count)+' vezes');
end;Code language: JavaScript (javascript)
Recomendação de padrão de código: minimize o uso de variáveis globais/públicas, prefira passar dados via Property.
5. Criar Formulários Dinamicamente
Sem depender da variável Form global gerada automaticamente pelo projeto
Método 1: Criação dinâmica do Form2 já projetado
- Abra o arquivo
Project.lpre exclua a linhaApplication.CreateForm(TForm2, Form2); - Código do botão no Form1:
procedure TForm1.Button1Click(Sender: TObject);
var
frm2: TForm2;
begin
frm2 := TForm2.Create(nil); // Instanciar manualmente
frm2.ShowModal;
FreeAndNil(frm2); // Liberar memória para evitar vazamentos
end;Code language: JavaScript (javascript)
Método 2: Formulário gerado totalmente por código (sem projeto prévio)
Clicar no botão gera uma janela nova completa com botão de fechar embutido
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); // Manipulador de clique para botão dinâmico
public
end;
var Form1: TForm1;
implementation
{$R *.lfm}
procedure TForm1.DynamicBtnClick(Sender: TObject);
begin
ShowMessage('Fechando o formulário criado dinamicamente');
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 := 'Formulário Gerado Dinamicamente';
// Criar botão com proprietário MyForm, destruído automaticamente ao fechar a janela
MyBtn := TButton.Create(MyForm);
MyBtn.SetBounds(10,10,200,30);
MyBtn.Caption := 'Fechar Janela';
MyBtn.Parent := MyForm;
MyBtn.OnClick := @DynamicBtnClick;
MyForm.ShowModal;
FreeAndNil(MyForm);
end;
end.
Aparece a caixa “Choose Debug Information format”



Basta configurar o formato de depuração para funcionar normalmente.