lazarus-calculator
A desktop calculator developed with Lazarus and Object Pascal.
- Active · last change 8-12-2026
- ★ 1 on GitHub
README
Calculadora
Calculadora desktop desenvolvida em Object Pascal utilizando a IDE Lazarus.
O projeto foi desenvolvido como parte de um desafio de programação cujo objetivo é implementar uma calculadora funcional capaz de realizar as quatro operações aritméticas fundamentais, aplicando também boas práticas de desenvolvimento de software, como desenvolvimento incremental, separação de responsabilidades, validação, versionamento e organização do código.
Funcionalidades
A calculadora possui suporte a:
- Entrada numérica de
0a9; - Adição;
- Subtração;
- Multiplicação;
- Divisão;
- Execução do cálculo;
- Limpeza e reinicialização da calculadora;
- Validação de divisão por zero;
- Exibição da expressão aritmética;
- Substituição de operadores consecutivos;
- Controle de habilitação do botão de resultado.
Tecnologias utilizadas
- Object Pascal;
- Lazarus IDE;
- Free Pascal Compiler (FPC);
- Git;
- GitHub.
Arquitetura e decisões de projeto
Embora a aplicação possua um escopo relativamente pequeno, sua estrutura foi desenvolvida considerando organização, manutenibilidade e possibilidade de evolução futura.
Separação de responsabilidades
Durante a implementação inicial, as operações aritméticas eram realizadas diretamente pelo formulário principal da aplicação.
Com a evolução do projeto, a lógica responsável pelos cálculos foi extraída para uma unit dedicada chamada CalculationEngine.
A estrutura resultante separa as principais responsabilidades da aplicação:
CalculatorForm
|
|-- Interface com o usuário
|-- Entrada de dados
|-- Estado da calculadora
|-- Validações
|-- Exibição da expressão
|
v
CalculationEngine
|
|-- Execução das operações aritméticasO CalculatorForm permanece responsável pela interação com o usuário e pelo estado da interface, enquanto o CalculationEngine é responsável pela execução das operações matemáticas.
Essa decisão reduz o acoplamento entre a interface gráfica e a lógica de cálculo, além de facilitar futuras alterações e extensões.
Reutilização de eventos
Em vez de criar um evento individual para cada botão numérico, os botões de 0 a 9 compartilham o mesmo manipulador:
NumberButtonClickO componente responsável pelo evento é identificado através do parâmetro Sender.
A mesma estratégia foi aplicada aos operadores aritméticos através de:
OperatorButtonClickDessa forma, evita-se a criação de diversos métodos com comportamentos praticamente idênticos.
Essa decisão reduz duplicação de código e segue o princípio DRY (Don't Repeat Yourself).
Gerenciamento do estado da calculadora
A calculadora precisa manter informações entre diferentes interações do usuário.
Para isso, foram utilizados campos privados como:
FFirstOperand
FOperator
FStartNewInputEsses valores permitem identificar diferentes estados da aplicação, como:
- Entrada do primeiro operando;
- Seleção do operador;
- Entrada do segundo operando;
- Exibição do resultado;
- Início de uma nova operação.
O prefixo F foi utilizado como convenção para representar campos pertencentes à classe do formulário.
Separação entre expressão e resultado
Inicialmente, apenas o valor atual era apresentado no display.
Durante o desenvolvimento foi identificada a necessidade de fornecer ao usuário um retorno visual da operação selecionada.
Para isso, foi adicionado um componente separado para exibir a expressão aritmética.
Por exemplo:
1 + 1 =
2A expressão e o valor numérico foram mantidos em componentes diferentes.
Essa decisão evita misturar textos como:
1 + 1 =com valores que posteriormente precisam ser convertidos para tipos numéricos através de funções como StrToFloat.
Além disso, melhora a experiência do usuário ao manter visível o contexto da operação realizada.
Após o resultado, a expressão permanece visível até que uma nova entrada seja iniciada ou a calculadora seja reinicializada.
Validações
Foram adicionadas validações para impedir estados inválidos durante a utilização da calculadora.
Divisão por zero
Antes de executar uma divisão, o segundo operando é verificado.
Caso seja igual a zero, o cálculo não é enviado para execução e o display apresenta:
ErrorA mensagem foi mantida curta devido ao espaço disponível no display da calculadora.
Após o erro, o estado da aplicação é preparado para permitir uma nova entrada de forma segura.
Botão de resultado
O botão = inicia desabilitado.
Ele é habilitado somente após a seleção de uma operação e volta a ser desabilitado depois da execução do cálculo ou de uma operação inválida.
Isso evita a execução do cálculo quando não existe uma operação válida preparada.
Operadores consecutivos
Também foi considerado o cenário em que o usuário seleciona mais de um operador antes de informar o segundo operando.
Por exemplo:
10 + *Nesse caso, o último operador selecionado substitui o anterior.
Assim:
10 + * 5 =é interpretado como:
10 * 5 =Esse comportamento evita gerar um erro desnecessário e permite que o usuário corrija o operador antes de continuar a operação.
Operação de limpeza
O botão C não foi implementado apenas como uma limpeza visual do display.
Ele realiza uma reinicialização completa do estado da calculadora.
São restaurados:
- Valor apresentado no display;
- Expressão apresentada ao usuário;
- Primeiro operando armazenado;
- Operador selecionado;
- Estado de entrada numérica;
- Estado do botão de resultado.
Essa abordagem impede que informações de uma operação anterior permaneçam armazenadas internamente e interfiram em cálculos posteriores.
Processo de desenvolvimento
O projeto foi desenvolvido de forma incremental.
As funcionalidades foram separadas em diferentes etapas:
Inicialização do projeto
↓
Interface gráfica
↓
Entrada numérica
↓
Seleção dos operadores
↓
Execução dos cálculos
↓
Validação das operações
↓
Reinicialização da calculadora
↓
Refatoração do mecanismo de cálculo
↓
Exibição da expressãoCada alteração relevante foi desenvolvida em uma branch específica e posteriormente integrada à main através de Pull Requests.
Essa estratégia permitiu desenvolver e validar cada comportamento de maneira isolada, além de manter um histórico claro da evolução da aplicação.
Estratégia de versionamento
Foi utilizado Git para controle de versão e GitHub para armazenamento do repositório e integração das alterações.
Os commits seguem uma convenção baseada em Conventional Commits, permitindo identificar facilmente a finalidade de cada alteração.
Alguns dos commits realizados durante o desenvolvimento foram:
chore: initialize Lazarus calculator project
feat: create calculator user interface
feat: implement numeric input handling
feat: implement arithmetic operator selection
feat: implement calculation execution
feat: add calculation validation
feat: implement calculator reset
refactor: extract calculation engine
feat: add arithmetic expression displayOs principais prefixos utilizados foram:
feat: implementação de uma nova funcionalidade;refactor: alteração estrutural sem modificar o comportamento esperado;chore: configuração ou manutenção do projeto;docs: alterações relacionadas à documentação.
Dificuldades encontradas durante o desenvolvimento
Adaptação ao Lazarus
Uma das principais dificuldades foi a utilização da IDE Lazarus e do Object Pascal durante o desenvolvimento do projeto.
Foi necessário compreender conceitos e recursos como:
- Forms;
- Object Inspector;
- Componentes visuais;
- Propriedades dos componentes;
- Eventos;
- Parâmetro
Sender; - Hierarquia entre componentes;
- Units;
- Arquivos
.pase.lfm.
Durante o desenvolvimento, também foram encontrados comportamentos relacionados às propriedades dos componentes.
Por exemplo, quando um componente pai estava com Enabled = False, seus componentes filhos também deixavam de aceitar interação.
A identificação desse comportamento foi importante para compreender melhor a hierarquia dos componentes da interface.
Gerenciamento de eventos
Durante a implementação da entrada numérica, inicialmente foram criados eventos individuais para alguns botões.
Posteriormente, esses eventos foram substituídos por um único manipulador compartilhado.
Após essa alteração, o Lazarus identificou referências antigas no arquivo visual do formulário para métodos que já não existiam.
Foi necessário remover essas referências e associar os botões ao novo evento compartilhado NumberButtonClick.
Essa situação ajudou a compreender a relação entre o código Pascal e as configurações armazenadas pelo Form Designer.
Palavras reservadas do Object Pascal
Durante a extração do CalculationEngine, inicialmente foi utilizado o identificador:
Operatorcomo parâmetro da função responsável pelo cálculo.
Durante a compilação, o Free Pascal apresentou um erro porque operator é uma palavra reservada da linguagem.
O identificador foi substituído por:
OperationEsse problema reforçou a necessidade de considerar características específicas da linguagem mesmo quando um nome parece adequado semanticamente.
Gerenciamento de estado
Outra dificuldade importante foi manter o estado interno da calculadora sincronizado com aquilo que era apresentado ao usuário.
Por exemplo, alterar o display para 0 ao pressionar C não seria suficiente caso o primeiro operando e o operador anterior continuassem armazenados.
O mesmo cuidado foi necessário após:
- Execução de um cálculo;
- Divisão por zero;
- Seleção consecutiva de operadores;
- Exibição de um resultado;
- Início de uma nova entrada.
Essas situações levaram à implementação explícita do gerenciamento de estado através dos campos privados do formulário.
Utilização de Inteligência Artificial
A Inteligência Artificial foi utilizada como ferramenta de apoio durante o desenvolvimento do projeto.
A IA auxiliou principalmente em:
- Compreensão inicial da IDE Lazarus;
- Explicação de conceitos do Object Pascal;
- Sugestões de organização do projeto;
- Convenções de nomenclatura;
- Discussão sobre reutilização de eventos;
- Separação de responsabilidades;
- Identificação de cenários para testes;
- Revisão das decisões de implementação.
As sugestões fornecidas pela IA não foram consideradas automaticamente corretas.
Durante o desenvolvimento, algumas orientações precisaram ser corrigidas ou adaptadas após compilação e testes no ambiente real.
Um exemplo ocorreu durante a criação do CalculationEngine, quando o identificador Operator foi inicialmente utilizado como nome de parâmetro. O compilador identificou que se tratava de uma palavra reservada do Object Pascal, exigindo a alteração para Operation.
Também foram necessárias adaptações relacionadas ao gerenciamento de eventos pelo Form Designer e às propriedades dos componentes da interface.
Por esse motivo, a utilização da IA seguiu um processo de validação:
Sugestão da IA
↓
Implementação
↓
Compilação
↓
Teste manual
↓
Análise do comportamento
↓
Correção ou aprovaçãoDessa forma, a IA foi utilizada como ferramenta de suporte ao desenvolvimento, e não como substituta da análise, compreensão e validação do código.
Critérios considerados durante o desenvolvimento
Durante a implementação foram considerados principalmente:
- Legibilidade do código;
- Nomes claros para componentes e métodos;
- Redução de código duplicado;
- Separação entre interface e lógica de cálculo;
- Controle explícito do estado da aplicação;
- Tratamento de operações inválidas;
- Retorno visual das ações realizadas pelo usuário;
- Desenvolvimento incremental;
- Histórico de versionamento compreensível;
- Facilidade de manutenção;
- Possibilidade de expansão futura;
- Complexidade proporcional ao escopo do projeto.
Uma decisão importante foi evitar adicionar funcionalidades apenas para tornar artificialmente o projeto mais complexo.
A estrutura foi preparada para permitir evolução futura, mas o desenvolvimento foi mantido dentro do escopo necessário para atender ao desafio.
Possíveis evoluções
Embora não façam parte do escopo atual, a estrutura permite futuramente adicionar funcionalidades como:
- Entrada de números decimais;
- Operações com porcentagem;
- Potenciação;
- Raiz quadrada;
- Entrada através do teclado;
- Histórico de cálculos;
- Operações de memória;
- Novas operações matemáticas;
- Testes automatizados.
Essas funcionalidades podem ser adicionadas incrementalmente sem necessidade de reconstruir completamente a aplicação.
Testes
Os testes foram realizados manualmente durante cada etapa do desenvolvimento.
Entre os cenários utilizados estão:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2
10 / 0 = ErrorTambém foram verificados:
- Entrada de números com múltiplos dígitos;
- Tratamento de zeros à esquerda;
- Substituição de operadores consecutivos;
- Limpeza durante uma operação incompleta;
- Limpeza após um cálculo;
- Limpeza após um erro;
- Início de uma nova operação após um resultado;
- Exibição da expressão aritmética;
- Habilitação e desabilitação do botão
=; - Preservação do comportamento após a refatoração do
CalculationEngine.
Após a separação da lógica matemática para o CalculationEngine, os principais cenários foram executados novamente como testes de regressão para garantir que a refatoração não alterasse o comportamento existente.
Conclusão
O desenvolvimento demonstrou que mesmo uma aplicação de pequeno porte pode se beneficiar da aplicação de boas práticas de Engenharia de Software.
Em vez de concentrar toda a implementação diretamente nos eventos individuais dos botões, o projeto foi desenvolvido incrementalmente, utilizando reutilização de eventos, gerenciamento explícito de estado, validações, separação de responsabilidades, versionamento e documentação das decisões tomadas.
A aplicação final atende aos requisitos propostos para a calculadora e mantém uma estrutura organizada, compreensível e preparada para possíveis evoluções futuras.

