Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works
Anything · Lazarus or Delphi
Random projectRandom project

registration-forms-lazarus

Desktop registration system built with Lazarus and Object Pascal, demonstrating form inheritance, polymorphism and reusable validation.

View on GitHub

Member rating

No ratings yet.

Sign in to rate this project.

README

Registration Forms

Aplicação desktop desenvolvida em Lazarus com Free Pascal para demonstrar a criação e reutilização de formulários por meio de herança, polimorfismo e separação de responsabilidades.

O projeto parte de um formulário base de cadastro e utiliza essa estrutura para diferentes tipos de registros, evitando a repetição de componentes e comportamentos comuns.

Além do requisito de herança entre formulários, a aplicação foi expandida com múltiplas telas de cadastro, validações reutilizáveis, criação centralizada de formulários e integração com uma API externa para consulta de CEP.

Funcionalidades

A aplicação possui uma tela principal responsável pela navegação entre 10 tipos de cadastro:

  • Cliente
  • Freelancer
  • Funcionário
  • Fornecedor
  • Empresa
  • Prestador de Serviço
  • Aluno
  • Instrutor
  • Parceiro
  • Representante Comercial

Os formulários compartilham uma estrutura base contendo:

  • Cabeçalho;
  • Área de conteúdo;
  • Botão Salvar;
  • Botão Cancelar;
  • Comportamento comum de validação;
  • Padronização visual.

Também foram implementadas:

  • validação de CPF;
  • validação de CNPJ;
  • validação de CEP;
  • validação de e-mail;
  • validação de valores numéricos positivos;
  • consulta de endereço por CEP;
  • preenchimento automático de endereço;
  • criação centralizada dos formulários;
  • navegação reutilizável.

Tecnologias

  • Lazarus IDE
  • Free Pascal
  • LCL (Lazarus Component Library)
  • HTTP Client
  • JSON
  • ViaCEP
  • Git
  • GitHub

Arquitetura

O projeto foi dividido em responsabilidades específicas para evitar que regras diferentes ficassem concentradas nos formulários.

De forma simplificada:

text
MainForm
   |
   v
FormFactory
   |
   +-------------------------------+
   |                               |
   v                               v
RegistrationForm              Formulários filhos
                                   |
                     +-------------+-------------+
                     |                           |
                     v                           v
              ValidationUtils               CepService
                                                 |
                                                 v
                                              ViaCEP

Cada parte possui uma responsabilidade definida.

MainForm

MainForm é responsável pela navegação da aplicação.

A tela principal não implementa as regras específicas dos cadastros e não precisa conhecer o processo interno de criação de cada formulário.

Os botões utilizam um evento compartilhado e a propriedade Tag para identificar o tipo de formulário que deve ser aberto.

Isso evita a criação de diversos eventos praticamente idênticos.

RegistrationForm

RegistrationForm funciona como formulário base para as telas de cadastro.

Ele concentra os elementos e comportamentos compartilhados, como:

  • estrutura visual;
  • cabeçalho;
  • painel de conteúdo;
  • painel de ações;
  • botão Salvar;
  • botão Cancelar;
  • fluxo comum de validação.

Os demais formulários herdam dessa classe.

Exemplo conceitual:

pascal
TfrmCustomer = class(TRegistrationForm)

Dessa forma, não foi necessário recriar a estrutura comum em cada nova tela.

Herança de formulários

Um dos principais objetivos do projeto foi utilizar herança visual e comportamental.

Foram desenvolvidos 10 formulários derivados da mesma estrutura base:

text
TRegistrationForm
│
├── TfrmCustomer
├── TfrmFreelancer
├── TfrmEmployee
├── TfrmSupplier
├── TfrmCompany
├── TfrmServiceProvider
├── TfrmStudent
├── TfrmInstructor
├── TfrmPartner
└── TfrmSalesRepresentative

Cada formulário adiciona apenas os componentes e regras necessários ao seu próprio contexto.

Isso permite que alterações comuns sejam centralizadas no formulário pai, reduzindo duplicação e facilitando manutenção.

Polimorfismo e validação

O formulário base declara um método virtual de validação:

pascal
function ValidateData: Boolean; virtual;

Os formulários especializados sobrescrevem esse comportamento:

pascal
function ValidateData: Boolean; override;

O botão Salvar pertence ao formulário base e executa a validação sem precisar saber qual formulário está aberto.

Conceitualmente:

text
Salvar
   |
   v
ValidateData
   |
   +--> Cliente     -> valida dados do cliente
   +--> Fornecedor  -> valida dados do fornecedor
   +--> Funcionário -> valida dados do funcionário
   +--> ...

Essa abordagem permite reutilizar o fluxo comum e especializar somente a regra que realmente muda.

Form Factory

Com o aumento da quantidade de formulários, a criação direta das telas no MainForm começaria a gerar código repetitivo.

Para centralizar essa responsabilidade foi criada a TFormFactory.

Os tipos disponíveis são representados por um enum:

pascal
TRegistrationFormType

A tela principal informa qual cadastro deseja abrir e a Factory determina qual classe deve ser instanciada.

Fluxo:

text
MainForm
   |
   | rftCustomer
   v
TFormFactory
   |
   v
TfrmCustomer.Create

Isso mantém a criação dos formulários em um ponto central e deixa a tela principal focada na navegação.

Navegação

Inicialmente, cada botão poderia possuir seu próprio evento de abertura.

Com 10 formulários isso produziria diversos métodos com praticamente o mesmo comportamento.

A navegação foi então centralizada utilizando um único evento e a propriedade Tag dos botões.

Cada Tag corresponde a um valor de TRegistrationFormType.

O fluxo passa a ser:

text
Botão
  |
  v
Tag
  |
  v
TRegistrationFormType
  |
  v
OpenRegistrationForm
  |
  v
TFormFactory

A solução reduz repetição e facilita a inclusão de novos formulários.

Integração com ViaCEP

O projeto realiza consumo de uma API externa utilizando o serviço ViaCEP.

A integração é utilizada nos cadastros de:

  • Cliente;
  • Fornecedor.

O usuário informa um CEP e solicita a consulta. Quando encontrado, os dados de endereço são preenchidos automaticamente.

Fluxo:

text
CEP informado
     |
     v
CustomerForm / SupplierForm
     |
     v
TCepService
     |
     v
Requisição HTTP
     |
     v
ViaCEP
     |
     v
JSON
     |
     v
TAddress
     |
     v
Preenchimento do formulário

CepService

A comunicação HTTP não foi implementada diretamente nos formulários.

Essa responsabilidade pertence ao TCepService.

Os formulários apenas solicitam:

pascal
Address := TCepService.FindByZipCode(ZipCode);

O serviço fica responsável pela comunicação com a API e pelo tratamento da resposta.

Essa separação evita que detalhes de HTTP e JSON sejam misturados com código da interface gráfica.

Além disso, o mesmo serviço pode ser reutilizado por diferentes formulários.

AddressModel

Os dados retornados pela consulta de CEP são representados por TAddress.

O modelo permite transportar os dados de endereço entre o serviço e a interface sem fazer os formulários trabalharem diretamente com a estrutura JSON retornada pela API.

Entre os dados utilizados estão:

text
CEP
Logradouro
Bairro
Cidade
UF

Validações reutilizáveis

Regras comuns foram centralizadas em TValidationUtils.

Foram implementadas validações para:

text
CPF
CNPJ
CEP
E-mail
Número positivo

Em vez de cada formulário possuir sua própria implementação do algoritmo de CPF, por exemplo, ele apenas solicita:

pascal
TValidationUtils.IsValidCpf(edtCpf.Text)

O mesmo princípio é utilizado para as demais validações.

Isso evita duplicação de regras e mantém os formulários responsáveis principalmente pelo fluxo da interface.

Separação de responsabilidades

Durante o desenvolvimento foi adotada uma separação simples entre as responsabilidades da aplicação.

Interface

Responsável por:

  • interação com o usuário;
  • leitura dos campos;
  • exibição de mensagens;
  • apresentação dos dados.

RegistrationForm

Responsável por:

  • comportamento comum dos cadastros;
  • estrutura compartilhada;
  • ações comuns;
  • fluxo de validação.

FormFactory

Responsável por:

  • decidir qual formulário deve ser instanciado;
  • centralizar a criação das telas.

ValidationUtils

Responsável por:

  • regras reutilizáveis de validação.

CepService

Responsável por:

  • comunicação HTTP;
  • consulta de CEP;
  • processamento dos dados da API.

AddressModel

Responsável por:

  • representar os dados de endereço utilizados pela aplicação.

Decisões técnicas

Utilização de um formulário base

Foi escolhido um formulário base porque as telas de cadastro possuem estrutura e comportamentos semelhantes.

Sem herança, elementos como Salvar, Cancelar, cabeçalho e fluxo de validação precisariam ser repetidos em cada tela.

Criação de 10 formulários derivados

Apesar de o requisito inicial poder ser demonstrado com uma quantidade menor de formulários, foram desenvolvidos 10 exemplos para demonstrar de forma mais clara a escalabilidade da solução.

A inclusão de novas telas exige principalmente a implementação das características específicas do novo cadastro, enquanto a estrutura comum continua sendo herdada.

Uso de métodos virtuais

ValidateData foi definido como virtual para permitir que o formulário pai controle o fluxo de salvamento enquanto cada descendente implementa suas próprias regras.

Criação da FormFactory

A Factory foi introduzida depois que vários formulários já existiam.

A decisão surgiu da identificação de repetição no processo de criação e abertura das telas.

Em vez de espalhar chamadas de criação pelo MainForm, essa responsabilidade passou a possuir um ponto central.

Serviço separado para CEP

A integração com ViaCEP foi isolada da interface para evitar que requisições HTTP e processamento JSON fossem implementados dentro dos eventos dos botões.

Isso também permitiu reutilizar a mesma integração nos cadastros de Cliente e Fornecedor.

Centralização das validações

Validações compartilhadas foram retiradas dos formulários e centralizadas em uma classe utilitária.

A decisão evita múltiplas implementações da mesma regra.

Simplicidade

Apesar da aplicação de conceitos como herança, polimorfismo e Factory, foi evitada a criação de abstrações sem necessidade.

O objetivo foi manter o projeto simples, legível e fácil de explicar, utilizando abstrações somente onde havia uma responsabilidade compartilhada ou repetição concreta.

Boas práticas aplicadas

Durante o desenvolvimento foram considerados:

  • nomes de classes e componentes relacionados às suas responsabilidades;
  • separação entre interface, serviço, modelo e validação;
  • reutilização de código;
  • redução de duplicação;
  • métodos pequenos e objetivos;
  • encapsulamento de responsabilidades;
  • herança para comportamentos realmente compartilhados;
  • polimorfismo para comportamentos especializados;
  • tratamento de exceções na integração externa;
  • liberação de formulários utilizando try...finally;
  • validação antes do envio de dados para serviços externos;
  • padronização visual entre formulários;
  • versionamento incremental com Git.

Dificuldades encontradas

Uma das principais dificuldades durante o desenvolvimento esteve relacionada à herança visual do Lazarus.

Algumas propriedades de componentes herdados ficaram registradas nos formulários descendentes, fazendo com que alterações realizadas no formulário pai nem sempre fossem refletidas visualmente da forma esperada no Designer.

Para manter o comportamento compartilhado e evitar ajustes repetidos nos formulários filhos, parte do posicionamento comum foi centralizada no próprio comportamento do formulário base.

Também ocorreram situações em que alterações no Designer não eram imediatamente refletidas como esperado, exigindo revisão dos arquivos .lfm, reconstrução do projeto e reabertura da IDE.

Outra atenção necessária foi manter sincronizados os nomes das classes Pascal e as declarações existentes nos arquivos .lfm, principalmente durante a criação dos formulários herdados.

Essas situações ajudaram a compreender melhor a relação entre:

text
.pas
.lfm
classe do formulário
herança visual
Object Inspector

Uso de Inteligência Artificial

A inteligência artificial foi utilizada como ferramenta de apoio durante o desenvolvimento, principalmente para:

  • planejamento das etapas;
  • discussão de arquitetura;
  • sugestões de nomenclatura;
  • revisão de código;
  • identificação de duplicações;
  • apoio na implementação da integração HTTP;
  • organização do versionamento;
  • análise de erros apresentados pelo compilador.

As sugestões não foram aplicadas de forma automática.

Durante o desenvolvimento ocorreram situações em que soluções sugeridas precisaram ser revisadas porque não correspondiam ao comportamento real do Lazarus, especialmente em questões relacionadas ao Designer e à herança visual.

Nesses casos, o comportamento da aplicação e as mensagens do compilador foram utilizados para identificar a causa real do problema e ajustar a implementação.

A IA foi utilizada como ferramenta auxiliar, enquanto as decisões e validações finais foram realizadas com base no funcionamento do projeto.

Estrutura do projeto

De forma simplificada, o projeto contém:

text
RegistrationForms/
│
├── RegistrationForms.lpr
│
├── MainForm.pas
├── MainForm.lfm
│
├── RegistrationForm.pas
├── RegistrationForm.lfm
│
├── FormFactory.pas
├── ValidationUtils.pas
├── CepService.pas
├── AddressModel.pas
│
├── CustomerForm.pas
├── CustomerForm.lfm
│
├── FreelancerForm.pas
├── FreelancerForm.lfm
│
├── EmployeeForm.pas
├── EmployeeForm.lfm
│
├── SupplierForm.pas
├── SupplierForm.lfm
│
├── CompanyForm.pas
├── CompanyForm.lfm
│
├── ServiceProviderForm.pas
├── ServiceProviderForm.lfm
│
├── StudentForm.pas
├── StudentForm.lfm
│
├── InstructorForm.pas
├── InstructorForm.lfm
│
├── PartnerForm.pas
├── PartnerForm.lfm
│
├── SalesRepresentativeForm.pas
└── SalesRepresentativeForm.lfm

Arquivos gerados automaticamente durante compilação podem variar conforme a configuração do Lazarus e não fazem parte da lógica principal da aplicação.

Como executar

Pré-requisitos

  • Lazarus IDE;
  • Free Pascal Compiler;
  • conexão com a internet para utilizar a consulta de CEP.

Execução

  1. Clone o repositório.
  2. Abra o arquivo do projeto .lpi no Lazarus.
  3. Compile o projeto.
  4. Execute a aplicação.
  5. Escolha um dos tipos de cadastro na tela principal.

Para testar a integração com ViaCEP:

  1. Abra o cadastro de Cliente ou Fornecedor.
  2. Informe um CEP válido.
  3. Clique em Buscar CEP.
  4. Os dados de endereço serão preenchidos com a resposta da API.

Versionamento

O desenvolvimento foi dividido em etapas utilizando branches específicas para cada responsabilidade.

Foram utilizados commits incrementais e Pull Requests para integrar as funcionalidades à branch principal.

Esse fluxo permitiu manter as mudanças isoladas durante o desenvolvimento e registrar a evolução da aplicação.

Considerações finais

O projeto demonstra que herança de formulários pode ser utilizada não apenas para reutilizar componentes visuais, mas também para compartilhar comportamentos.

A partir de um formulário base, foram construídas 10 telas especializadas mantendo uma estrutura comum.

A aplicação também demonstra outros conceitos complementares, como:

  • herança;
  • sobrescrita de métodos;
  • polimorfismo;
  • Factory;
  • reutilização;
  • separação de responsabilidades;
  • validações centralizadas;
  • consumo de API REST;
  • processamento JSON;
  • tratamento de exceções.

A solução foi mantida propositalmente simples: cada abstração foi adicionada para resolver uma responsabilidade ou duplicação identificada durante o desenvolvimento, evitando complexidade desnecessária.