https://wiki.freepascal.org/api.php?action=feedcontributions&user=Antoniog&feedformat=atomFree Pascal wiki - User contributions [en]2024-03-28T08:36:53ZUser contributionsMediaWiki 1.35.6https://wiki.freepascal.org/index.php?title=LazUtils&diff=66914LazUtils2013-03-19T12:46:07Z<p>Antoniog: </p>
<hr />
<div>__TOC__<br />
<br />
== TDictionaryStringList ==<br />
<br />
This is an unsorted StringList with a fast lookup feature. Internally it uses a string map container to store the string again. It is then used for InserItem, Contains, IndexOf and Find methods. The extra container does not reserve too much memory because the strings are reference counted and not really copied. All Duplicates property values are fully supported, including dupIgnore and dupError, unlike in unsorted StringList.<br />
<br />
This class is useful only when you must preserve the order in list, but also need to do fast lookups to see if a string exists, or must prevent duplicates.</div>Antonioghttps://wiki.freepascal.org/index.php?title=LazUtils&diff=66913LazUtils2013-03-19T12:44:57Z<p>Antoniog: /* TDictionaryStringList */</p>
<hr />
<div>__TOC__<br />
<br />
== TDictionaryStringList ==<br />
<br />
This is an unsorted StringList with a fast lookup feature. Internally it uses a string map container to store the string again. It is then used for InserItem, Contains, IndexOf and Find methods.<br />
<br />
The extra container does not reserve too much memory because the strings are reference counted and not really copied.<br />
<br />
All Duplicates property values are fully supported, including dupIgnore and dupError, unlike in unsorted StringList.<br />
<br />
This class is useful only when you must preserve the order in list, but also need to do fast lookups to see if a string exists, or must prevent duplicates.</div>Antonioghttps://wiki.freepascal.org/index.php?title=LazUtils&diff=66912LazUtils2013-03-19T12:43:28Z<p>Antoniog: /* TDictionaryStringList */</p>
<hr />
<div>== TDictionaryStringList ==<br />
<br />
This is an unsorted StringList with a fast lookup feature. Internally it uses a string map container to store the string again. It is then used for InserItem, Contains, IndexOf and Find methods.<br />
<br />
The extra container does not reserve too much memory because the strings are reference counted and not really copied.<br />
<br />
All Duplicates property values are fully supported, including dupIgnore and dupError, unlike in unsorted StringList.<br />
<br />
This class is useful only when you must preserve the order in list, but also need to do fast lookups to see if a string exists, or must prevent duplicates.</div>Antonioghttps://wiki.freepascal.org/index.php?title=LazUtils&diff=66911LazUtils2013-03-19T12:41:33Z<p>Antoniog: </p>
<hr />
<div>== TDictionaryStringList ==</div>Antonioghttps://wiki.freepascal.org/index.php?title=LazUtils&diff=66910LazUtils2013-03-19T12:41:07Z<p>Antoniog: </p>
<hr />
<div>== TDictionaryStringList</div>Antonioghttps://wiki.freepascal.org/index.php?title=LazUtils&diff=66909LazUtils2013-03-19T12:37:48Z<p>Antoniog: Created page with "TDictionaryStringList"</p>
<hr />
<div>TDictionaryStringList</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50926Howdy World (Hello World on steroids)/pt2011-06-27T13:21:50Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:<br />
<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note que, na definição de classe acima, todos os controles e procedimentos declarados foram adicionados ao formulário automaticamente. '''''Não faça qualquer modificação manual aí!!''''' A IDE vai ficar nervosa que você o fizer. O lugar para acrescentar variáveis, procedientos e funções personalizadas são as seções ''private'' e ''public''. Como regra geral, variáveis personalizadas são adicionadas à seção ''private''. Procedimentos e funções são acrescentadas à seção ''private'' também, exceto quando outros formulários precisam chamar estes procedimentos ou funções (o que deve acontecer com frequência).<br />
<br />
De volta para o nosso problema de dígitos: precisamos de um procedimento que acrescente dígitos ao display em que os dígitos possam variar.<br />
<br />
* Acrescente o procedimento AddDigit à seção ''private'' do formulário.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Em seguida, o código efetivo para o procedimento AddDigit precisa ser inserido. Novamente a IDE vem em nosso auxílio:<br />
* Posicione o caret na linha AddDigit.<br />
* Pressione a combinação de teclas Ctrl+Shift+C.<br />
A IDE gerará a definição deste novo método e posicionará o cursor de texto dentro do procedimento vazio. Podemos imediatamente começar a digitar.<br />
<br />
* Acrescente o seguinte código ao procedimento AddDigit:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
<br />
Note que a função ''IntToStr()'' traduz o valor numérico, o digito, para um valor de sequência de caracteres de modo que possa ser mostrado no display.<br />
<br />
E para usar este procedimento para todos os dígitos:<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão do dígito '0': isto abrirá o editor no manipulador de eventos para o botão 0.<br />
* Substituia o código no manipulador de eventos por: AddDigit(0). O procedimento se parecerá com isto:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Faça o mesmo para o botão do dígito 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Antes de completar esta sequência para todos os outros botões de dígitos, certifique-se de que ele realmente faz o que queremos.<br />
* Execute o programa (pressione F9).<br />
* Clique nos botões 0 e 1 algumas vezes e veja se ele realmente funciona.<br />
* Finalize o programa.<br />
<br />
''Um bom programador é um programador preguiçoso''<br />
<br />
Agora podemos acrescentar manipuladores de eventos para os botões 2..9. Mas agora novamente temos o mesmo problema de criar código redundante: AddDigit(2), AddDigit(3), etc.<br />
E se houvesse uma maneira de contar os botões separadamente? Felizmente existe.<br />
<br />
Todos os componentes têm uma propriedade de valor inteiro chamada ''Tag'' (lembre-se: um controle é apenas um tipo especial de componente que herda esta propriedade ''Tag''. É uma propriedade que não tem uma função verdadeira. Está lá para usarmos como acharmos melhor. E se cada botão pudesse ter seu valor de dígito armazenado na propriedade ''Tag''...<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Selecione o botão do dígito 1 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor par ''1''.<br />
* Selecione o botão do dígito 2 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor para ''2''.<br />
* Repita isto para os botões dos dígitos 3..9.<br />
<br />
Agora todos os botões de dígitos têm um valor de Tag único. Não modificamos o botão do dígito 0 porque o valor padrão de Tag já é 0.<br />
Agora, para fazer uso deste valor de Tag:<br />
* Abra o formulário.<br />
* Dê um duplo-clique no botão do dígito 0 (isto abrirá o editor no manipulador de eventos para o botão do dígito 0).<br />
* Note que o procedimento ''btnDigit0Click'' tem um parâmetro ''Sender'' de tipo ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
O parâmetro ''Sender'' é na verdade uma referência ao botão que foi pressionado. Através de conversão de tipo, podemos usar o parâmetro como se fosse um TButton.<br />
* Modifique o código assim:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
Não parece que tenhamos feito muito, substituindo uma linha de código por outra. No entanto, Se tivéssemos de adicionar código para os outros dígitos (1..9), ele ficaria exatamente igual. Assim, todos os outros dígitos podem reusar este método!<br />
<br />
Vamos olhar melhor para o Inspetor de Objetos. <br />
* Abra o formulário.<br />
* Selecione o botão do dígito 0 (btnDigit0).<br />
* No Inspetor de Objetos, selecione a aba Events (veja abaixo).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
No Inspetor de Objetos, podemos não somente mudar as propriedades do controle, mas também os manipuladores de eventos. No Inspetor de Objetos podemos ver que, tão logo o botão do dígito 0 for clicado, o método ''btnDigit0Click '' seá chamado (este é o manipulador de eventos ''OnClick'').<br />
<br />
* No formulário: selecione o botão do dígito 2. No Inspetor de Objetos podemos agora ver que não há qualquer manipulador de eventos OnClick para o botão 2.<br />
* Abra a lista dropdown para o evento OnClick e selecione ''btnDigit0Click''.<br />
* Faça o mesmo para todos os outros botões de dígitos 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50783Howdy World (Hello World on steroids)/pt2011-06-19T17:24:13Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:<br />
<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note que, na definição de classe acima, todos os controles e procedimentos declarados foram adicionados ao formulário automaticamente. '''''Não faça qualquer modificação manual aí!!''''' A IDE vai ficar nervosa que você o fizer. O lugar para acrescentar variáveis, procedientos e funções personalizadas são as seções ''private'' e ''public''. Como regra geral, variáveis personalizadas são adicionadas à seção ''private''. Procedimentos e funções são acrescentadas à seção ''private'' também, exceto quando outros formulários precisam chamar estes procedimentos ou funções (o que deve acontecer com frequência).<br />
<br />
De volta para o nosso problema de dígitos: precisamos de um procedimento que acrescente dígitos ao display em que os dígitos possam variar.<br />
<br />
* Acrescente o procedimento AddDigit à seção ''private'' do formulário.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Em seguida, o código efetivo para o procedimento AddDigit precisa ser inserido. Novamente a IDE vem em nosso auxílio:<br />
* Posicione o caret na linha AddDigit.<br />
* Pressione a combinação de teclas Ctrl+Shift+C.<br />
A IDE gerará a definição deste novo método e posicionará o cursor de texto dentro do procedimento vazio. Podemos imediatamente começar a digitar.<br />
<br />
* Acrescente o seguinte código ao procedimento AddDigit:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
<br />
Note que a função ''IntToStr()'' traduz o valor numérico, o digito, para um valor de sequência de caracteres de modo que possa ser mostrado no display.<br />
<br />
E para usar este procedimento para todos os dígitos:<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão do dígito '0': isto abrirá o editor no manipulador de eventos para o botão 0.<br />
* Substituia o código no manipulador de eventos por: AddDigit(0). O procedimento se parecerá com isto:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Faça o mesmo para o botão do dígito 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Antes de completar esta sequência para todos os outros botões de dígitos, certifique-se de que ele realmente faz o que queremos.<br />
* Execute o programa (pressione F9).<br />
* Clique nos botões 0 e 1 algumas vezes e veja se ele realmente funciona.<br />
* Finalize o programa.<br />
<br />
''Um bom programador é um programador preguiçoso''<br />
<br />
Agora podemos acrescentar manipuladores de eventos para os botões 2..9. Mas agora novamente temos o mesmo problema de criar código redundante: AddDigit(2), AddDigit(3), etc.<br />
E se houvesse uma maneira de contar os botões separadamente? Felizmente existe.<br />
<br />
Todos os componentes têm uma propriedade de valor inteiro chamada ''Tag'' (lembre-se: um controle é apenas um tipo especial de componente que herda esta propriedade ''Tag''. É uma propriedade que não tem uma função verdadeira. Está lá para usarmos como acharmos melhor. E se cada botão pudesse ter seu valor de dígito armazenado na propriedade ''Tag''...<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Selecione o botão do dígito 1 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor par ''1''.<br />
* Selecione o botão do dígito 2 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor para ''2''.<br />
* Repita isto para os botões dos dígitos 3..9.<br />
<br />
Agora todos os botões de dígitos têm um valor de Tag único. Não modificamos o botão do dígito 0 porque o valor padrão de Tag já é 0.<br />
Agora, para fazer uso deste valor de Tag:<br />
* Abra o formulário.<br />
* Dê um duplo-clique no botão do dígito 0 (isto abrirá o editor no manipulador de eventos para o botão do dígito 0).<br />
* Note que o procedimento ''btnDigit0Click'' tem um parâmetro ''Sender'' de tipo ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
O parâmetro ''Sender'' é na verdade uma referência ao botão que foi pressionado. Através de conversão de tipo, podemos usar o parâmetro como se fosse um TButton.<br />
* Modifique o código assim:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
Não parece que tenhamos feito muito, substituindo uma linha de código por outra. No entanto, Se tivéssemos de adicionar código para os outros dígitos (1..9), ele ficaria exatamente igual. Assim, todos os outros dígitos podem reusar este método!<br />
<br />
Vamos olhar melhor para o Inspetor de Objetos. <br />
* Abra o formulário.<br />
* Selecione o botão do dígito 0 (btnDigit0).<br />
* No Inspetor de Objetos, selecione a aba Events (veja abaixo).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
No Inspetor de Objetos, podemos não somente mudar as propriedades do controle, mas também os manipuladores de eventos. No Inspetor de Objetos podemos ver que, tão logo o botão do dígito 0 for clicado, o método ''btnDigit0Click '' seá chamado (este é o manipulador de eventos ''OnClick'').<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50757Howdy World (Hello World on steroids)/pt2011-06-17T22:40:54Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:<br />
<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note que, na definição de classe acima, todos os controles e procedimentos declarados foram adicionados ao formulário automaticamente. '''''Não faça qualquer modificação manual aí!!''''' A IDE vai ficar nervosa que você o fizer. O lugar para acrescentar variáveis, procedientos e funções personalizadas são as seções ''private'' e ''public''. Como regra geral, variáveis personalizadas são adicionadas à seção ''private''. Procedimentos e funções são acrescentadas à seção ''private'' também, exceto quando outros formulários precisam chamar estes procedimentos ou funções (o que deve acontecer com frequência).<br />
<br />
De volta para o nosso problema de dígitos: precisamos de um procedimento que acrescente dígitos ao display em que os dígitos possam variar.<br />
<br />
* Acrescente o procedimento AddDigit à seção ''private'' do formulário.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Em seguida, o código efetivo para o procedimento AddDigit precisa ser inserido. Novamente a IDE vem em nosso auxílio:<br />
* Posicione o caret na linha AddDigit.<br />
* Pressione a combinação de teclas Ctrl+Shift+C.<br />
A IDE gerará a definição deste novo método e posicionará o cursor de texto dentro do procedimento vazio. Podemos imediatamente começar a digitar.<br />
<br />
* Acrescente o seguinte código ao procedimento AddDigit:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
<br />
Note que a função ''IntToStr()'' traduz o valor numérico, o digito, para um valor de sequência de caracteres de modo que possa ser mostrado no display.<br />
<br />
E para usar este procedimento para todos os dígitos:<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão do dígito '0': isto abrirá o editor no manipulador de eventos para o botão 0.<br />
* Substituia o código no manipulador de eventos por: AddDigit(0). O procedimento se parecerá com isto:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Faça o mesmo para o botão do dígito 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Antes de completar esta sequência para todos os outros botões de dígitos, certifique-se de que ele realmente faz o que queremos.<br />
* Execute o programa (pressione F9).<br />
* Clique nos botões 0 e 1 algumas vezes e veja se ele realmente funciona.<br />
* Finalize o programa.<br />
<br />
''Um bom programador é um programador preguiçoso''<br />
<br />
Agora podemos acrescentar manipuladores de eventos para os botões 2..9. Mas agora novamente temos o mesmo problema de criar código redundante: AddDigit(2), AddDigit(3), etc.<br />
E se houvesse uma maneira de contar os botões separadamente? Felizmente existe.<br />
<br />
Todos os componentes têm uma propriedade de valor inteiro chamada ''Tag'' (lembre-se: um controle é apenas um tipo especial de componente que herda esta propriedade ''Tag''. É uma propriedade que não tem uma função verdadeira. Está lá para usarmos como acharmos melhor. E se cada botão pudesse ter seu valor de dígito armazenado na propriedade ''Tag''...<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Selecione o botão do dígito 1 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor par ''1''.<br />
* Selecione o botão do dígito 2 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor para ''2''.<br />
* Repita isto para os botões dos dígitos 3..9.<br />
<br />
Agora todos os botões de dígitos têm um valor de Tag único. Não modificamos o botão do dígito 0 porque o valor padrão de Tag já é 0.<br />
Agora, para fazer uso deste valor de Tag:<br />
* Abra o formulário.<br />
* Dê um duplo-clique no botão do dígito 0 (isto abrirá o editor no manipulador de eventos para o botão do dígito 0).<br />
* Note que o procedimento ''btnDigit0Click'' tem um parâmetro ''Sender'' de tipo ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
O parâmetro ''Sender'' é na verdade uma referência ao botão que foi pressionado. Através de conversão de tipo, podemos usar o parâmetro como se fosse um TButton.<br />
* Modifique o código assim:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
Não parece que tenhamos feito muito, substituindo uma linha de código por outra. No entanto, Se tivéssemos de adicionar código para os outros dígitos (1..9), ele ficaria exatamente igual. Assim, todos os outros dígitos podem reusar este método!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50726Howdy World (Hello World on steroids)/pt2011-06-15T21:12:42Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:<br />
<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note que, na definição de classe acima, todos os controles e procedimentos declarados foram adicionados ao formulário automaticamente. '''''Não faça qualquer modificação manual aí!!''''' A IDE vai ficar nervosa que você o fizer. O lugar para acrescentar variáveis, procedientos e funções personalizadas são as seções ''private'' e ''public''. Como regra geral, variáveis personalizadas são adicionadas à seção ''private''. Procedimentos e funções são acrescentadas à seção ''private'' também, exceto quando outros formulários precisam chamar estes procedimentos ou funções (o que deve acontecer com frequência).<br />
<br />
De volta para o nosso problema de dígitos: precisamos de um procedimento que acrescente dígitos ao display em que os dígitos possam variar.<br />
<br />
* Acrescente o procedimento AddDigit à seção ''private'' do formulário.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Em seguida, o código efetivo para o procedimento AddDigit precisa ser inserido. Novamente a IDE vem em nosso auxílio:<br />
* Posicione o caret na linha AddDigit.<br />
* Pressione a combinação de teclas Ctrl+Shift+C.<br />
A IDE gerará a definição deste novo método e posicionará o cursor de texto dentro do procedimento vazio. Podemos imediatamente começar a digitar.<br />
<br />
* Acrescente o seguinte código ao procedimento AddDigit:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
<br />
Note que a função ''IntToStr()'' traduz o valor numérico, o digito, para um valor de sequência de caracteres de modo que possa ser mostrado no display.<br />
<br />
E para usar este procedimento para todos os dígitos:<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão do dígito '0': isto abrirá o editor no manipulador de eventos para o botão 0.<br />
* Substituia o código no manipulador de eventos por: AddDigit(0). O procedimento se parecerá com isto:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Faça o mesmo para o botão do dígito 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Antes de completar esta sequência para todos os outros botões de dígitos, certifique-se de que ele realmente faz o que queremos.<br />
* Execute o programa (pressione F9).<br />
* Clique nos botões 0 e 1 algumas vezes e veja se ele realmente funciona.<br />
* Finalize o programa.<br />
<br />
''Um bom programador é um programador preguiçoso''<br />
<br />
Agora podemos acrescentar manipuladores de eventos para os botões 2..9. Mas agora novamente temos o mesmo problema de criar código redundante: AddDigit(2), AddDigit(3), etc.<br />
E se houvesse uma maneira de contar os botões separadamente? Felizmente existe.<br />
<br />
Todos os componentes têm uma propriedade de valor inteiro chamada ''Tag'' (lembre-se: um controle é apenas um tipo especial de componente que herda esta propriedade ''Tag''. É uma propriedade que não tem uma função verdadeira. Está lá para usarmos como acharmos melhor. E se cada botão pudesse ter seu valor de dígito armazenado na propriedade ''Tag''...<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Selecione o botão do dígito 1 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor par ''1''.<br />
* Selecione o botão do dígito 2 (clique nele uma vez).<br />
* No Inspetor de Objetos, localize a propriedade ''Tag'' e modifique seu valor para ''2''.<br />
* Repita isto para os botões dos dígitos 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50725Howdy World (Hello World on steroids)/pt2011-06-15T20:56:54Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:<br />
<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note que, na definição de classe acima, todos os controles e procedimentos declarados foram adicionados ao formulário automaticamente. '''''Não faça qualquer modificação manual aí!!''''' A IDE vai ficar nervosa que você o fizer. O lugar para acrescentar variáveis, procedientos e funções personalizadas são as seções ''private'' e ''public''. Como regra geral, variáveis personalizadas são adicionadas à seção ''private''. Procedimentos e funções são acrescentadas à seção ''private'' também, exceto quando outros formulários precisam chamar estes procedimentos ou funções (o que deve acontecer com frequência).<br />
<br />
De volta para o nosso problema de dígitos: precisamos de um procedimento que acrescente dígitos ao display em que os dígitos possam variar.<br />
<br />
* Acrescente o procedimento AddDigit à seção ''private'' do formulário.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Em seguida, o código efetivo para o procedimento AddDigit precisa ser inserido. Novamente a IDE vem em nosso auxílio:<br />
* Posicione o caret na linha AddDigit.<br />
* Pressione a combinação de teclas Ctrl+Shift+C.<br />
A IDE gerará a definição deste novo método e posicionará o cursor de texto dentro do procedimento vazio. Podemos imediatamente começar a digitar.<br />
<br />
* Acrescente o seguinte código ao procedimento AddDigit:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
<br />
Note que a função ''IntToStr()'' traduz o valor numérico, o digito, para um valor de sequência de caracteres de modo que possa ser mostrado no display.<br />
<br />
E para usar este procedimento para todos os dígitos:<br />
* Abra o formulário (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão do dígito '0': isto abrirá o editor no manipulador de eventos para o botão 0.<br />
* Substituia o código no manipulador de eventos por: AddDigit(0). O procedimento se parecerá com isto:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50714Howdy World (Hello World on steroids)/pt2011-06-15T18:51:41Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:<br />
<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note que, na definição de classe acima, todos os controles e procedimentos declarados foram adicionados ao formulário automaticamente. '''''Não faça qualquer modificação manual aí!!''''' A IDE vai ficar nervosa que você o fizer. O lugar para acrescentar variáveis, procedientos e funções personalizadas são as seções ''private'' e ''public''. Como regra geral, variáveis personalizadas são adicionadas à seção ''private''. Procedimentos e funções são acrescentadas à seção ''private'' também, exceto quando outros formulários precisam chamar estes procedimentos ou funções (o que deve acontecer com frequência).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50713Howdy World (Hello World on steroids)/pt2011-06-15T18:41:25Z<p>Antoniog: /* Respondendo a eventos */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
* Dê um duplo-clique no botão com o rótulo ''1''.<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.<br />
* Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.<br />
* Clique nos dígitos 0 e 1 algumas vezes e veja o que acontece na tela. Os outros botões ainda não fazem nada obviamente porque os manipuladores de eventos ainda não foram acrescentados.<br />
* Pare o programa de Calculadora.<br />
<br />
É claro que agora é fácil acrescentar manipuladores de eventos para os dígitos 2..9, mas isto vai resultar em muito código redundante. Cada manipulador de eventos faz exatamente a mesma coisa, apenas os dígitos são diferentes. A forma de eliminar esta redundãncia é criar um procedimento que faça o processamento e acrescentar uma variável (os dígitos 0..9) como parâmetro.<br />
<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50712Howdy World (Hello World on steroids)/pt2011-06-15T15:10:59Z<p>Antoniog: /* Responding to events */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Respondendo a eventos==<br />
Uma aplicação GUI muitas vezes é uma aplicação baseada em eventos. Isto significa que a aplicação não faz nada até que digamos a ela o que fazer. Por exemplo, inserindo dados através do teclado, pressionando botões, etc. Uma das coisas que a calculadora precisa fazer é responder a cliques do mouse nos botões 0..9. É nisto que a IDE nos ajuda. Acrescentar um ''manipulador de eventos'' para um botão é fácil.<br />
* Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).<br />
* Dê um duplo-clique no botão com o rótulo ''0'': a IDE automaticamente cria um procedimento que manipulará eventos de cliques do mouse: procedure TForm1.btnDigit0Click(Sender :TObject);<br />
* Digite o seguinte código entre as palavras-chave ''begin'' e ''end'':<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edtDisplay é uma caixa de edição. A forma de modificar o conteúdo de uma caixa de edição é modificando a propriedade ''Text''. A declaração acima acrescenta o número '0' ao texto e isto é visível na tela imediatamente.<br />
<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50628Howdy World (Hello World on steroids)/pt2011-06-12T00:57:38Z<p>Antoniog: /* Botões */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que se ajuste aos botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Lembre-se de salvar e salve com frequência!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50627Howdy World (Hello World on steroids)/pt2011-06-12T00:55:56Z<p>Antoniog: /* Botões */</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
E os botões especiais:<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''+/-''<br />
* Modifique o nome para ''btnPlusMinus''.<br />
* Posicione o botão bem embaixo do botão ''3''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''C''.<br />
* Modifique o nome para ''btnClear''.<br />
* Posicione o botão à direita do botão ''+''.<br />
* Copie e Cole o botão ''+''.<br />
* Modifique o rótulo para ''=''.<br />
* Modifique o nome para ''btnCalculate''.<br />
* Posicione o botão à direita do botão ''/''.<br />
Redimensione o formulário para que caibam todos os botões.<br />
<br />
Isto deve resultar em algo assim:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50620Howdy World (Hello World on steroids)/pt2011-06-11T21:01:13Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. Esta calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).<br />
* Coloque um novo TButton no formulário.<br />
* Modifique a largura para ''32''.<br />
* Modifique a altura para ''30''.<br />
* Modifique a propriedade Caption para ''+''.<br />
* Modifique o nome para ''btnFunction''.<br />
* Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para ''-'', ''*'' e ''/''.<br />
* Alinhe os botões verticalmente, ao lado dos botões dos dígitos.<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50619Howdy World (Hello World on steroids)/pt2011-06-11T20:47:48Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
Isto precisa ser repetido para os dígitos 1..9. A forma mais rápida de fazê-lo é copiando e colando o botão já criado.<br />
* Clique com o botão direito do mouse no botão do dígito ''0'' e selecione Copiar do menu popup.<br />
* Clique com o botão direito do mouse em algum lugar de Panel1 e selelcione Colar. Um segundo botão é adicionado ao painel. A única diferença do primeiro botão é o nome ''btnDigit1''.<br />
* Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para ''1''.<br />
* Repita a ação de Colar mais oito vezes para os botões seguintes.<br />
* Mova os botões no formulário para obter um layout que se pareça com uma calculadora:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50618Howdy World (Hello World on steroids)/pt2011-06-11T19:07:08Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Botões==<br />
Para que serve uma calculadora se não puderem ser inseridos números? Portanto o próximo passo será adicionar botões para os dígitos 0..9. Antes de posicionar os botões para os dígitos, um assim chamado "contêiner" é colocado no formulário. Um TPanel é outro contêiner que podem ser colocados no formulário. Contêineres podem ser colocados dentro de outros, mas isto é para outro tutorial.<br />
<br />
* Na paleta de componentes, selecione um controle TPanel.<br />
* Clique no formulário para criar o painel. Um novo painel está agora visível no formulário com largura, altura e rótulo padronizados. Note que a fonte do painel é herdade do formulário. Este painel será usado para agrupar todos os botões, então algumas propriedades devem ser modificadas.<br />
* Remova o texto ''Panel1'' da propriedade Caption.<br />
* Modifique Align par a ''alClient''.<br />
* Modifique Borderspacing.Around para ''6''.<br />
* Aumente a largura (width) do formulário para ''300'' (primeiro clique no formulário na TreeView do Inspetor de Objetos).<br />
* Aumente a altura (height) do formulário para ''350''.<br />
(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)<br />
<br />
Agora os botões dos dígitos serão adicionados.<br />
* Na paleta de componentes, selecione um controle TButton.<br />
* Clique no formulário para posicioná-lo. O botão é colocado no painel. Isto é visível no Inspetor de Objetos: Button1 é chamado ''filho'' (child) de Panel1. Isto efetivamente significa que, se o painel for movido, todos os controles filhos serão movidos, e quando Panel1 for eliminado, todos os controles-filhos o serão também.<br />
* No Inspetor de Objetos, modifique o valor de Caption para ''0 '' (o número zero).<br />
* Modifique a largura (width) para ''32''.<br />
* Modifique a altura (height) para ''30 ''.<br />
* Modifique o nome (name) para ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50617Howdy World (Hello World on steroids)/pt2011-06-11T18:45:45Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Clique em algum lugar do formulário. Isto desselecionará o controle edDisplay e selecionará o próprio formulário. As propriedades do formulário são agora mostradas no Inspetor de Objetos.<br />
* No Inspetor de Objetos, clique na propriedade Font. A linha da propriedade Font será realçada e um botão com três pontos será mostrado.<br />
* Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.<br />
* Selecione Verdana, Bold, Tamanho 10.<br />
* Pressione OK.<br />
<br />
O título do formulário não é muito significativo. O padrão é 'Form1'.<br />
* No Inspetor de Objetos, clique na propriedade Caption.<br />
* Mude o texto para ''Calculator Demo''.<br />
<br />
O resultado de todas estas ações será um formulário que se parece com este:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Agora é uma boa hora para salvar o formulário.<br />
* Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.<br />
<br />
Lembre-se de salvá-lo e o salve com frequência!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50616Howdy World (Hello World on steroids)/pt2011-06-11T18:29:07Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja esta [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.<br />
* Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).<br />
* Clique em algum lugar no formulário. Isto colocará um controle TEdit no formulário com um nome que é o mesmo nome da classe do componente sem a letra "T" e com um número no final (por exemplo, Edit1). Quando um segunto TEdit for colocado no formulário, será nomeado como Edit2, e assim por diante. Isto se aplica a todos os componentes.<br />
<br />
Agora que o controle está colocado no formulário, ele pode ser personalizado como você precisar. Esta personalização tem lugar no Inspetor de Objetos. Esta é a janela à esquerda da tela, com a lista de propriedades para o controle TEdit que são personalizáveis.<br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
As propriedades determinam a aparência e o comportamento do controle. É fácil modificá-las: apenas clique em uma delas, insira um novo valor e pressione Enter. O efeito no controle é imediatamente visível. As propriedades no Inspetor de Objetos são todas propriedades para um único controle, particularmente o controle que tem o foco ou está selecionado. Portanto, a maneira de modificar propriedades de um controle é primeiramente selecioná-lo e então fazer as modificações no Inspetor de Objetos. Se nenhum controle for selecionado, as propriedades do formulário serão mostradas.<br />
<br />
Faça as seguintes modificações nas propriedades de Edit1:<br />
* Mude o nome para ''edDisplay''.<br />
* Mude Align para ''alTop'' (não confundir com Alignment).<br />
* Mude Alignment para ''alRightJustify'' (não confundir com Align).<br />
* Mude BorderSpacing.Around para ''6''.<br />
* Mude Text para ''0'' (o número zero, não a letra "O").<br />
Estas propriedades são bastante autoxplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.<br />
<br />
Como um toque final, a fonte que é usada para mostrar textos em todos os controles será mudada. A fonte pode ser mudada de duas maneiras: na propriedade Font de edDisplay ou na mesma propriedade do formulário. Mudando a fonte do formulário tem o benefício de que todos os componentes anteriormente criados 'herdarão' a nova fonte, e é aí que nós faremos a nossa modificação.<br />
<br />
* Click somewhere in the middle of the form. This deselects the edDisplay control and selects the form itself. The form’s properties are now displayed in the Object Inspector.<br />
* In the Object Inspector click on the Font property. The Font line is now highlighted and a button with three dots is displayed.<br />
* Click on the button with the three dots. This opens the Font dialog.<br />
* Select Verdana, Bold, Size 10.<br />
* Press OK.<br />
<br />
The Form’s title is not very meaningful. The default text 'Form1' is displayed.<br />
* In the Object Inspector click on the Caption property. <br />
* Change the caption text to ''Calculator Demo''.<br />
<br />
The result of all these actions is a form that looks something like this:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Now is a good time to save the form.<br />
* Select from the menu File/Save or press the key combination Ctrl-S.<br />
<br />
Remember to save and save often!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50615Howdy World (Hello World on steroids)/pt2011-06-11T18:06:13Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja este [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. <br />
Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Select the Standard tab on the component palette. This is the tab that is selected by default.<br />
* Click on the TEdit component (hover above the component icons to get the class type names).<br />
* Click somewhere in the middle of the form. This places a TEdit control on the form that has a name that is the same as the control’s type without the capital 'T' and with a number at the end (e.g. Edit1). When a second TEdit control were to be placed on the form it would be named Edit2. And so forth. This applies to all components.<br />
<br />
Now that the control is placed on the form it can be customized to our needs. This customization takes place in the Object Inspector. That is the window at the left side of the screen with the list of properties for the TEdit control that are customizable. <br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
Properties determine the look and feel and behavior of a control. It’s easy to change a property: just click on one of them, enter a new value and press Enter. The effects on the control are instantly visible. The properties in the Object Inspector are all the properties for ''one'' control. In particular the control that has the focus/is selected. The control that is selected can be recognized by the small black squares that surround the control. So the way to change properties of a control is by first selecting it and then make the changes in the Object Inspector. If no control is selected, the form properties are displayed.<br />
<br />
Make the following changes to the properties of Edit1.<br />
* change Name to ''edDisplay''.<br />
* change Align to ''alTop'' (change Align, not Alignment!).<br />
* change Alignment to ''alRightJustify'' (change Alignment, not Align).<br />
* change BorderSpacing.Around to ''6''.<br />
* change Text to ''0'' (the number zero, not the letter oh).<br />
These properties are pretty self-explanatory. Especially when the above changes are made and the effect is monitored on the form.<br />
<br />
As a finishing touch the Font that is used to display texts on all controls will be changed. The font can be changed in two places: the font property of edDisplay or the form’s font property. Changing the font for the form itself has the benefit that all newly placed controls on the form will 'inherit' the new font. So that is where we are going to make the change.<br />
<br />
* Click somewhere in the middle of the form. This deselects the edDisplay control and selects the form itself. The form’s properties are now displayed in the Object Inspector.<br />
* In the Object Inspector click on the Font property. The Font line is now highlighted and a button with three dots is displayed.<br />
* Click on the button with the three dots. This opens the Font dialog.<br />
* Select Verdana, Bold, Size 10.<br />
* Press OK.<br />
<br />
The Form’s title is not very meaningful. The default text 'Form1' is displayed.<br />
* In the Object Inspector click on the Caption property. <br />
* Change the caption text to ''Calculator Demo''.<br />
<br />
The result of all these actions is a form that looks something like this:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Now is a good time to save the form.<br />
* Select from the menu File/Save or press the key combination Ctrl-S.<br />
<br />
Remember to save and save often!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50614Howdy World (Hello World on steroids)/pt2011-06-11T18:03:57Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
Fazendo isto, a pasta do projeto não será desordenada com a saída gerada pelo compilador. Os arquivos da pasta do projeto são necessárias para construir o programa. Tudo nos diretórios ’’lib’’ e ’’bin’’ podem ser eliminados quando do arquivamento do projeto.<br />
<br />
Agora, como um primeiro teste, o projeto pode ser compilado e executado.<br />
* Pressione F9 (o atalho para compilar, construir e executar o programa). Se tudo sair bem, uma tela em branco será mostrada. Agora sabemos que foi criada uma base sólida sobre a qual podemos começar a construir o programa.<br />
* Finalize a execução clicando no ícone Fechar (isto depende do OS).<br />
<br />
==O primeiro componente==<br />
O Lazarus tem uma assim chamada 'paleta de componentes':<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
Todos os componentes que estão disponíveis para construir uma interface do usuário estão logicamente agrupados nas abas de componentes. O número real de abas depende dos pacotes instalados, mas a paleta básica se parece com a imagem acima. A primeira aba é a Standard, seguida pela Aditional, Common controls, etc.<br />
<br />
Para retornar o nome do tipo de um componente, passe o mouse sobre o ícone do componente e um aviso será mostrado (mais precisamente, o nome de classe do componente). Para uma explanação sobre todos os controles, veja este [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
A primeira coisa que é preciso ser feita para o programa de Calculadora é criar uma área de display, onde estão os números. Para isto, um controle TEdit é usado.<br />
# Nota: os componentes visuais são referidos como Controles. Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.<br />
<br />
Para colocar um controle no formulário, este precisa ter o foco. Pressionar F12 no teclado muda o foco do editor de formulários para o editor de código e vice-versa.<br />
* Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Select the Standard tab on the component palette. This is the tab that is selected by default.<br />
* Click on the TEdit component (hover above the component icons to get the class type names).<br />
* Click somewhere in the middle of the form. This places a TEdit control on the form that has a name that is the same as the control’s type without the capital 'T' and with a number at the end (e.g. Edit1). When a second TEdit control were to be placed on the form it would be named Edit2. And so forth. This applies to all components.<br />
<br />
Now that the control is placed on the form it can be customized to our needs. This customization takes place in the Object Inspector. That is the window at the left side of the screen with the list of properties for the TEdit control that are customizable. <br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
Properties determine the look and feel and behavior of a control. It’s easy to change a property: just click on one of them, enter a new value and press Enter. The effects on the control are instantly visible. The properties in the Object Inspector are all the properties for ''one'' control. In particular the control that has the focus/is selected. The control that is selected can be recognized by the small black squares that surround the control. So the way to change properties of a control is by first selecting it and then make the changes in the Object Inspector. If no control is selected, the form properties are displayed.<br />
<br />
Make the following changes to the properties of Edit1.<br />
* change Name to ''edDisplay''.<br />
* change Align to ''alTop'' (change Align, not Alignment!).<br />
* change Alignment to ''alRightJustify'' (change Alignment, not Align).<br />
* change BorderSpacing.Around to ''6''.<br />
* change Text to ''0'' (the number zero, not the letter oh).<br />
These properties are pretty self-explanatory. Especially when the above changes are made and the effect is monitored on the form.<br />
<br />
As a finishing touch the Font that is used to display texts on all controls will be changed. The font can be changed in two places: the font property of edDisplay or the form’s font property. Changing the font for the form itself has the benefit that all newly placed controls on the form will 'inherit' the new font. So that is where we are going to make the change.<br />
<br />
* Click somewhere in the middle of the form. This deselects the edDisplay control and selects the form itself. The form’s properties are now displayed in the Object Inspector.<br />
* In the Object Inspector click on the Font property. The Font line is now highlighted and a button with three dots is displayed.<br />
* Click on the button with the three dots. This opens the Font dialog.<br />
* Select Verdana, Bold, Size 10.<br />
* Press OK.<br />
<br />
The Form’s title is not very meaningful. The default text 'Form1' is displayed.<br />
* In the Object Inspector click on the Caption property. <br />
* Change the caption text to ''Calculator Demo''.<br />
<br />
The result of all these actions is a form that looks something like this:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Now is a good time to save the form.<br />
* Select from the menu File/Save or press the key combination Ctrl-S.<br />
<br />
Remember to save and save often!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50613Howdy World (Hello World on steroids)/pt2011-06-11T15:16:18Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.<br />
* Do menu, escolha Arquivo/Salvar Tudo.<br />
* Selecione o diretório que foi criado previamente ($HOME/CalculatorDemo).<br />
* Insira um novo nome de projeto: CalculatorDemo.<br />
* Pressione Salvar (ou o que corresponder a isto em seu idioma).<br />
* A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.<br />
* A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.<br />
<br />
Em teoria, o programa que é assim criado é um software válido que pode ser executado. Antes de compilá-lo pela primeira vez, duas modificações são recomendadas: atribuição de novos locais (diretórios) para as unidades de destino e nome do arquivo compilado.<br />
* Do menu, escolha Projeto/Opções de Projeto.<br />
* Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).<br />
* Insira o texto ‘‘bin\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).<br />
* Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).<br />
* Pressione OK.<br />
A imagem abaixo mostra como isto ficaria em uma máquina Windows.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
By doing this the project folder will not be cluttered with output that is generated by the compiler. The files in the project folder are required to (re-) build the program. Everything in the ’’lib’’ and ’’bin’’ directories can be deleted when archiving the project.<br />
<br />
Now as a first test the project can be compiled and run.<br />
* Press F9 (the shortcut for compile, build and run the program)<br />
If all went well a blank window is displayed. Now we know that a solid basis is created on which we can start building the program.<br />
* End the running program by clicking on the Close icon (this depends on the OS).<br />
<br />
==The first component==<br />
Lazarus has a so called ‘component palette’:<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
All components that are available to build a user interface are logically grouped on the component tabs. The actual number of tabs depends on the installed packages. But the basic palette looks something like the above image. The first tab is Standard, followed by Additional, Common Controls etc.<br />
To retrieve the type name of a component, hover with the mouse pointer above the component icon and a hint is displayed that gives the type name (to be more precise: the class type of the component is displayed). For an explanation of all controls look at this [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
The first thing that needs to be done for the Calculator program is to create a display area where the entered numbers are, well, displayed. For this a TEdit control is used.<br />
# Note: the visual components are referred to as Controls. For now the difference between a 'component' and a 'control' is not that relevant. <br />
<br />
To place a control on the form, the form must have the focus. Pressing F12 on the keyboard changes the focus from the form editor to the source code editor and vice versa.<br />
* Press F12 once or twice to get the form window on top (see image below).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Select the Standard tab on the component palette. This is the tab that is selected by default.<br />
* Click on the TEdit component (hover above the component icons to get the class type names).<br />
* Click somewhere in the middle of the form. This places a TEdit control on the form that has a name that is the same as the control’s type without the capital 'T' and with a number at the end (e.g. Edit1). When a second TEdit control were to be placed on the form it would be named Edit2. And so forth. This applies to all components.<br />
<br />
Now that the control is placed on the form it can be customized to our needs. This customization takes place in the Object Inspector. That is the window at the left side of the screen with the list of properties for the TEdit control that are customizable. <br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
Properties determine the look and feel and behavior of a control. It’s easy to change a property: just click on one of them, enter a new value and press Enter. The effects on the control are instantly visible. The properties in the Object Inspector are all the properties for ''one'' control. In particular the control that has the focus/is selected. The control that is selected can be recognized by the small black squares that surround the control. So the way to change properties of a control is by first selecting it and then make the changes in the Object Inspector. If no control is selected, the form properties are displayed.<br />
<br />
Make the following changes to the properties of Edit1.<br />
* change Name to ''edDisplay''.<br />
* change Align to ''alTop'' (change Align, not Alignment!).<br />
* change Alignment to ''alRightJustify'' (change Alignment, not Align).<br />
* change BorderSpacing.Around to ''6''.<br />
* change Text to ''0'' (the number zero, not the letter oh).<br />
These properties are pretty self-explanatory. Especially when the above changes are made and the effect is monitored on the form.<br />
<br />
As a finishing touch the Font that is used to display texts on all controls will be changed. The font can be changed in two places: the font property of edDisplay or the form’s font property. Changing the font for the form itself has the benefit that all newly placed controls on the form will 'inherit' the new font. So that is where we are going to make the change.<br />
<br />
* Click somewhere in the middle of the form. This deselects the edDisplay control and selects the form itself. The form’s properties are now displayed in the Object Inspector.<br />
* In the Object Inspector click on the Font property. The Font line is now highlighted and a button with three dots is displayed.<br />
* Click on the button with the three dots. This opens the Font dialog.<br />
* Select Verdana, Bold, Size 10.<br />
* Press OK.<br />
<br />
The Form’s title is not very meaningful. The default text 'Form1' is displayed.<br />
* In the Object Inspector click on the Caption property. <br />
* Change the caption text to ''Calculator Demo''.<br />
<br />
The result of all these actions is a form that looks something like this:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Now is a good time to save the form.<br />
* Select from the menu File/Save or press the key combination Ctrl-S.<br />
<br />
Remember to save and save often!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50609Howdy World (Hello World on steroids)/pt2011-06-11T14:44:27Z<p>Antoniog: </p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um software funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Leitura recomendada antes de começar: uma introdução abrangente da [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
==Vamos começar==<br />
É melhor criar um diretório separado para cada projeto. Portanto, vamos criar um diretório para salvar o projeto da nossa Calculadora. Este diretório será a raiz de todos os arquivos criados para o projeto.<br />
* Criar um novo diretório para o projeto de demonstração (digamos, $HOME/CalculatorDemo).<br />
(''Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior'')<br />
<br />
Com isto resolvido, é hora de iniciar um novo projeto Lazarus.<br />
* Inicie o Lazarus.<br />
* Escolha Projeto/Novo Projeto… do menu.<br />
* Na caixa de diálogo que é apresentada selecione Aplicação e pressione OK (if the IDE reclama sobre modificações não salvas, pressione Não).<br />
<br />
To make sure that all files of our new project end up in the right directory the project must be saved first.<br />
* From the menu choose File/Save All.<br />
* Select the directory that was created previously ($HOME/CalculatorDemo).<br />
* Enter a new project name: CalculatorDemo<br />
* Press Save (or whatever is the Save button in your own language)<br />
* The IDE wants to save the main form as well: enter ’’ufrmMain’’ as the form's unit name.<br />
* The IDE asks if the filename should be changed to a lowercase name. Confirm this by pressing the button ‘Rename to lowercase’.<br />
<br />
In theory the program that is thus created is a piece of valid software that can be executed. Before compiling it for the first time, two changes are recommended: assigning new locations (directories) for the compiled units and target filename.<br />
* From the menu choose Project/Project Options…<br />
* Select Compiler Options/Paths (click on the node in the treeview)<br />
* Put the text ‘‘bin\’‘ before the target filename (or ‘‘bin/’‘ for a *nix environment)<br />
* Also note the ‘‘lib’‘ prefix for the ‘unit output directory’ (don’t change it).<br />
* Press OK<br />
The image below is how this would look like on a Windows machine.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
By doing this the project folder will not be cluttered with output that is generated by the compiler. The files in the project folder are required to (re-) build the program. Everything in the ’’lib’’ and ’’bin’’ directories can be deleted when archiving the project.<br />
<br />
Now as a first test the project can be compiled and run.<br />
* Press F9 (the shortcut for compile, build and run the program)<br />
If all went well a blank window is displayed. Now we know that a solid basis is created on which we can start building the program.<br />
* End the running program by clicking on the Close icon (this depends on the OS).<br />
<br />
==The first component==<br />
Lazarus has a so called ‘component palette’:<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
All components that are available to build a user interface are logically grouped on the component tabs. The actual number of tabs depends on the installed packages. But the basic palette looks something like the above image. The first tab is Standard, followed by Additional, Common Controls etc.<br />
To retrieve the type name of a component, hover with the mouse pointer above the component icon and a hint is displayed that gives the type name (to be more precise: the class type of the component is displayed). For an explanation of all controls look at this [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
The first thing that needs to be done for the Calculator program is to create a display area where the entered numbers are, well, displayed. For this a TEdit control is used.<br />
# Note: the visual components are referred to as Controls. For now the difference between a 'component' and a 'control' is not that relevant. <br />
<br />
To place a control on the form, the form must have the focus. Pressing F12 on the keyboard changes the focus from the form editor to the source code editor and vice versa.<br />
* Press F12 once or twice to get the form window on top (see image below).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Select the Standard tab on the component palette. This is the tab that is selected by default.<br />
* Click on the TEdit component (hover above the component icons to get the class type names).<br />
* Click somewhere in the middle of the form. This places a TEdit control on the form that has a name that is the same as the control’s type without the capital 'T' and with a number at the end (e.g. Edit1). When a second TEdit control were to be placed on the form it would be named Edit2. And so forth. This applies to all components.<br />
<br />
Now that the control is placed on the form it can be customized to our needs. This customization takes place in the Object Inspector. That is the window at the left side of the screen with the list of properties for the TEdit control that are customizable. <br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
Properties determine the look and feel and behavior of a control. It’s easy to change a property: just click on one of them, enter a new value and press Enter. The effects on the control are instantly visible. The properties in the Object Inspector are all the properties for ''one'' control. In particular the control that has the focus/is selected. The control that is selected can be recognized by the small black squares that surround the control. So the way to change properties of a control is by first selecting it and then make the changes in the Object Inspector. If no control is selected, the form properties are displayed.<br />
<br />
Make the following changes to the properties of Edit1.<br />
* change Name to ''edDisplay''.<br />
* change Align to ''alTop'' (change Align, not Alignment!).<br />
* change Alignment to ''alRightJustify'' (change Alignment, not Align).<br />
* change BorderSpacing.Around to ''6''.<br />
* change Text to ''0'' (the number zero, not the letter oh).<br />
These properties are pretty self-explanatory. Especially when the above changes are made and the effect is monitored on the form.<br />
<br />
As a finishing touch the Font that is used to display texts on all controls will be changed. The font can be changed in two places: the font property of edDisplay or the form’s font property. Changing the font for the form itself has the benefit that all newly placed controls on the form will 'inherit' the new font. So that is where we are going to make the change.<br />
<br />
* Click somewhere in the middle of the form. This deselects the edDisplay control and selects the form itself. The form’s properties are now displayed in the Object Inspector.<br />
* In the Object Inspector click on the Font property. The Font line is now highlighted and a button with three dots is displayed.<br />
* Click on the button with the three dots. This opens the Font dialog.<br />
* Select Verdana, Bold, Size 10.<br />
* Press OK.<br />
<br />
The Form’s title is not very meaningful. The default text 'Form1' is displayed.<br />
* In the Object Inspector click on the Caption property. <br />
* Change the caption text to ''Calculator Demo''.<br />
<br />
The result of all these actions is a form that looks something like this:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Now is a good time to save the form.<br />
* Select from the menu File/Save or press the key combination Ctrl-S.<br />
<br />
Remember to save and save often!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Howdy_World_(Hello_World_on_steroids)/pt&diff=50605Howdy World (Hello World on steroids)/pt2011-06-11T14:22:57Z<p>Antoniog: New page: Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um softwre funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo:...</p>
<hr />
<div>Este capítulo é um tutorial para Lazarus. Ele explica os primeiros passos para obter um softwre funcional e também algumas das melhores práticas. O resultado final (esperado) é duplo: o leitor entende os conceitos básicos para construir um software com Lazarus e obtém um verdadeiro programa funcional. Uma calculadora é algo razoavelmente fácil de implementar e todo mundo entende seus conceitos, sem necessidade de explicações de antemão. A calculadora é limitada a cálculos com números inteiros, mas pode facilmente ser estendida.<br />
<br />
Este tutorial não descreve o processo de instalação do Lazarus. Ele assume que o Lazarus está instalado e pronto para uso (preferivelmente a última versão estável, que no momento é a 0.9.30 com FreePascal 2.4.2). Este tutorial é mais ou menos independente de plataforma. Todos os screenshots foram feitos em Windows XP, portanto com o esquema de cores azul/vermelho/cinza.<br />
<br />
Recommended reading before starting here: a comprehensive introduction of the [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus IDE].<br />
<br />
<br />
==Let’s get started==<br />
It’s best to create a separate directory for every new project. So before getting our feet wet, let’s create a directory to save our Calculator project in (do this with your OS application of choice). This directory will be the root for all files created for the project.<br />
* Create a new directory for the demo project (let’s call it $HOME/CalculatorDemo).<br />
(''Text that describes actions that must be executed is bulleted like the previous line.'')<br />
<br />
With this out of the way it’s time to start a new Lazarus project.<br />
* Start Lazarus.<br />
* From the menu choose Project/New Project…<br />
* In the dialog that is presented select Application and press OK (if the IDE complains about unsaved changes, press No).<br />
<br />
To make sure that all files of our new project end up in the right directory the project must be saved first.<br />
* From the menu choose File/Save All.<br />
* Select the directory that was created previously ($HOME/CalculatorDemo).<br />
* Enter a new project name: CalculatorDemo<br />
* Press Save (or whatever is the Save button in your own language)<br />
* The IDE wants to save the main form as well: enter ’’ufrmMain’’ as the form's unit name.<br />
* The IDE asks if the filename should be changed to a lowercase name. Confirm this by pressing the button ‘Rename to lowercase’.<br />
<br />
In theory the program that is thus created is a piece of valid software that can be executed. Before compiling it for the first time, two changes are recommended: assigning new locations (directories) for the compiled units and target filename.<br />
* From the menu choose Project/Project Options…<br />
* Select Compiler Options/Paths (click on the node in the treeview)<br />
* Put the text ‘‘bin\’‘ before the target filename (or ‘‘bin/’‘ for a *nix environment)<br />
* Also note the ‘‘lib’‘ prefix for the ‘unit output directory’ (don’t change it).<br />
* Press OK<br />
The image below is how this would look like on a Windows machine.<br />
[[Image:tutcal_project_options.png]]<br />
<br />
By doing this the project folder will not be cluttered with output that is generated by the compiler. The files in the project folder are required to (re-) build the program. Everything in the ’’lib’’ and ’’bin’’ directories can be deleted when archiving the project.<br />
<br />
Now as a first test the project can be compiled and run.<br />
* Press F9 (the shortcut for compile, build and run the program)<br />
If all went well a blank window is displayed. Now we know that a solid basis is created on which we can start building the program.<br />
* End the running program by clicking on the Close icon (this depends on the OS).<br />
<br />
==The first component==<br />
Lazarus has a so called ‘component palette’:<br />
<br />
[[Image:tutcal_component_palette.png]]<br />
<br />
All components that are available to build a user interface are logically grouped on the component tabs. The actual number of tabs depends on the installed packages. But the basic palette looks something like the above image. The first tab is Standard, followed by Additional, Common Controls etc.<br />
To retrieve the type name of a component, hover with the mouse pointer above the component icon and a hint is displayed that gives the type name (to be more precise: the class type of the component is displayed). For an explanation of all controls look at this [http://wiki.lazarus.freepascal.org/Lazarus_Tutorial Lazarus introduction]<br />
<br />
The first thing that needs to be done for the Calculator program is to create a display area where the entered numbers are, well, displayed. For this a TEdit control is used.<br />
# Note: the visual components are referred to as Controls. For now the difference between a 'component' and a 'control' is not that relevant. <br />
<br />
To place a control on the form, the form must have the focus. Pressing F12 on the keyboard changes the focus from the form editor to the source code editor and vice versa.<br />
* Press F12 once or twice to get the form window on top (see image below).<br />
[[Image:tutcal_form_on_top.png]]<br />
<br />
* Select the Standard tab on the component palette. This is the tab that is selected by default.<br />
* Click on the TEdit component (hover above the component icons to get the class type names).<br />
* Click somewhere in the middle of the form. This places a TEdit control on the form that has a name that is the same as the control’s type without the capital 'T' and with a number at the end (e.g. Edit1). When a second TEdit control were to be placed on the form it would be named Edit2. And so forth. This applies to all components.<br />
<br />
Now that the control is placed on the form it can be customized to our needs. This customization takes place in the Object Inspector. That is the window at the left side of the screen with the list of properties for the TEdit control that are customizable. <br />
[[Image:tutcal_object_inspector.png]]<br />
<br />
Properties determine the look and feel and behavior of a control. It’s easy to change a property: just click on one of them, enter a new value and press Enter. The effects on the control are instantly visible. The properties in the Object Inspector are all the properties for ''one'' control. In particular the control that has the focus/is selected. The control that is selected can be recognized by the small black squares that surround the control. So the way to change properties of a control is by first selecting it and then make the changes in the Object Inspector. If no control is selected, the form properties are displayed.<br />
<br />
Make the following changes to the properties of Edit1.<br />
* change Name to ''edDisplay''.<br />
* change Align to ''alTop'' (change Align, not Alignment!).<br />
* change Alignment to ''alRightJustify'' (change Alignment, not Align).<br />
* change BorderSpacing.Around to ''6''.<br />
* change Text to ''0'' (the number zero, not the letter oh).<br />
These properties are pretty self-explanatory. Especially when the above changes are made and the effect is monitored on the form.<br />
<br />
As a finishing touch the Font that is used to display texts on all controls will be changed. The font can be changed in two places: the font property of edDisplay or the form’s font property. Changing the font for the form itself has the benefit that all newly placed controls on the form will 'inherit' the new font. So that is where we are going to make the change.<br />
<br />
* Click somewhere in the middle of the form. This deselects the edDisplay control and selects the form itself. The form’s properties are now displayed in the Object Inspector.<br />
* In the Object Inspector click on the Font property. The Font line is now highlighted and a button with three dots is displayed.<br />
* Click on the button with the three dots. This opens the Font dialog.<br />
* Select Verdana, Bold, Size 10.<br />
* Press OK.<br />
<br />
The Form’s title is not very meaningful. The default text 'Form1' is displayed.<br />
* In the Object Inspector click on the Caption property. <br />
* Change the caption text to ''Calculator Demo''.<br />
<br />
The result of all these actions is a form that looks something like this:<br />
[[Image:tutcal_form_with_tedit.png]]<br />
<br />
Now is a good time to save the form.<br />
* Select from the menu File/Save or press the key combination Ctrl-S.<br />
<br />
Remember to save and save often!<br />
<br />
==Buttons==<br />
What use is a calculator if numbers cannot be entered? So the next step is adding buttons for the digits 0..9. Before placing the buttons for the digits, a so called container is placed on the form. A container defines an area on a form where controls can be grouped together. The form is a container. A TPanel is another container that can be placed on a form. Containers can be placed inside other containers, but that’s for another tutorial.<br />
* On the component palette, select the TPanel control.<br />
* Click on the form to place the panel.<br />
A new panel is now visible on the form with a default width, height and caption. Note that the font for the panel caption is inherited from the form. This panel will be used to group all buttons, so a number of properties must be changed. <br />
* Remove the text ''Panel1'' from the caption property.<br />
* Change Align to ''alClient''.<br />
* change Borderspacing.Around to ''6''.<br />
* increase the form’s Width to ''300'' (first click on Form1 in the Object Inspector treeview).<br />
* increase the form’s Height to ''350''.<br />
(Increasing the size of the form gives us some space to move controls around.)<br />
<br />
Now the digit buttons will be added.<br />
* On the component palette, select the TButton control.<br />
* Click on the form, somewhere in the middle, to place the button. The button is placed on the panel. this is visible in the Object Inspector treeview: Button1 is a so called ''child'' of Panel1. This effectively means that when Panel1 is moved, all child controls move with it. And when Panel1 is deleted, all child controls are deleted as well.<br />
* In the Object Inspector change Caption to ''0 '' <br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Name to ''btnDigit0''.<br />
<br />
This must be repeated for the digits 1..9. The quickest way to do this is by copy/pasting the 0-button.<br />
* Right click on the button created above and select Copy from the pop up menu.<br />
* Right click somewhere else on Panel1 and select Paste; a second button is added to the panel. The only difference with the first button is the name ''btnDigit1''.<br />
* change the Caption property in the Object Inspector to ''1 ''<br />
* repeat the Paste action 8 more times for the remaining buttons.<br />
* Move the buttons around on the form to get a lay out that looks like a calculator:<br />
[[Image:tutcal_calculator_digits.png]]<br />
<br />
Next are the four buttons for the mathematical functions (add, subtract etc.).<br />
* Drop a new TButton on the panel.<br />
* Change Width to ''32''.<br />
* Change Height to ''30 ''.<br />
* Change Caption to ''+''<br />
* Change Name to ''btnFunction''.<br />
* Copy/paste this button 3 more times, changing the caption to ''-'', ''*'' and ''/''.<br />
* Align the buttons vertically, right next to the digit buttons<br />
<br />
And the 'special' buttons:<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''+/-''.<br />
* Change Name to ''btnPlusMinus ''.<br />
* Position the button just below button ''3''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''C''.<br />
* Change Name to btnClear.<br />
* Position the button to the right of button ''+''.<br />
* Copy/Paste the ''+'' button.<br />
* Change Caption to ''=''.<br />
* Change Name to ''btnCalculate ''.<br />
* Position the button to the right of button ''/''<br />
Not what all buttons are placed, resize the form to fit the buttons tightly.<br />
<br />
It should look something like this:<br />
<br />
[[Image:tutcal_calculator_gui_ready.png]]<br />
<br />
Remember to save and save often!<br />
<br />
==Responding to events==<br />
A gui application (often) is an event based application. This means that the application does nothing until we tell it to do something. For example by entering data via the keyboard, pressing buttons etc. One of the things the calculator needs to do is responding to mouse clicks on the buttons 0..9. This is where the IDE helps us. Adding a so called ''event handler'' for a button is easy.<br />
* Make sure the form with all buttons is visible (if necessary press F12 once or twice).<br />
* Double click on the button with caption ''0'': the IDE automatically creates a procedure that will handle mouse clicks: procedure TForm1.btnDigit0Click(Sender: TObject);<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '0'</Delphi><br />
edDisplay is an edit box. The way to change the contents of the edit box is by modifying the Text property. The above statement adds the number '0' to the text in the edit box and this is visible on screen immediately.<br />
* Double click on the button with caption ''1''.<br />
* type the following code between begin and end:<br />
<Delphi>edDisplay.Text := edDisplay.Text + '1'</Delphi><br />
<br />
It's a good idea to compile the code from time to time to check for syntax errors.<br />
* Select from the menu: Run/Run (or press F9); the project is compiled and the application starts.<br />
* Click the digits 0 and 1 a couple of times and see what happens on screen. The other buttons do nothing obviously because the event handlers have not yet been added.<br />
* Stop the Calculator Demo program.<br />
<br />
Of course it's now easy to add event handlers for the digits 2..9, but this will result in a lot of redundant code. Every event handler does exactly the same, only the digit is different. The way to remove this redundancy is by creating a procedure that does the processing, and add the variable data (the digits 0..9) as a parameter.<br />
* In the editor locate the lines where class TForm1 is declared. It will look something like this:<br />
<Delphi> { TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
btnDigit0: TButton;<br />
btnDigit1: TButton;<br />
btnDigit2: TButton;<br />
btnDigit3: TButton;<br />
btnDigit4: TButton;<br />
btnDigit5: TButton;<br />
btnDigit6: TButton;<br />
btnDigit7: TButton;<br />
btnDigit8: TButton;<br />
btnDigit9: TButton;<br />
btnFunction: TButton;<br />
btnFunction1: TButton;<br />
btnFunction2: TButton;<br />
btnFunction3: TButton;<br />
btnCalculate: TButton;<br />
btnPlusMinus: TButton;<br />
btnClear: TButton;<br />
edDisplay: TEdit;<br />
Panel1: TPanel;<br />
procedure btnDigit0Click(Sender: TObject);<br />
procedure btnDigit1Click(Sender: TObject);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Note that in the above class definition all controls and procedures are declared that we added to the form via 'pointing-and-clicking'. '''''Do not make any manual changes in there!!''''' The IDE will get nervous when you do. The place to add custom variables, procedures and functions is in the private or public sections. As a general rule all custom variables are added to the the private section. Procedures and functions are added to the private section as well, except when other forms need to call these procedures or functions (which shouldn't happen too often).<br />
<br />
Back to our digits problem: we need a procedure that adds digits to the display, where the digits themselves can vary.<br />
* Add procedure AddDigit to the private section of the form.<br />
<Delphi> private<br />
{ private declarations }<br />
procedure AddDigit(const pDigit: byte);<br />
public<br />
{ public declarations }<br />
end; </Delphi><br />
<br />
Next the actual code of the AddDigit procedure must be entered. Again the IDE comes to the rescue:<br />
* Place the blinking text cursor on the AddDigit line.<br />
* Press key combination Ctrl-Shift-C.<br />
The IDE generates the definition of this new method and places the text cursor inside the empty body. We can immediately start typing.<br />
* Add the following code to the AddDigit procedure body:<br />
<Delphi>edDisplay.Text := edDisplay.Text + IntToStr(pDigit)</Delphi><br />
Note that function ''IntToStr()'' translates a numerical value, the digit, to a string value so it can be added to the display text.<br />
<br />
Now to use this procedure for all digits 0..9:<br />
* Open the form (if necessary press F12 once or twice).<br />
* Double click on digit button 0: this will open the editor in the event handler for button 0.<br />
* Replace the code in the event handler with: AddDigit(0). The procedure will look like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(0)<br />
end;</Delphi><br />
<br />
* Do the same for digit button 1:<br />
<Delphi>procedure TForm1.btnDigit1Click(Sender: TObject);<br />
begin<br />
AddDigit(1)<br />
end;</Delphi><br />
<br />
Before completing this sequence for all other digit buttons, make sure that this actually does what we want.<br />
* Run the program (press F9).<br />
* Click buttons 0 and 1 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
''A good programmer is a lazy programmer''<br />
<br />
Now we can add event handlers to digit buttons 2..9. But then again we have the same problem of creating a lot of redundant code: AddDigit(2), AddDigit(3) etc.<br />
What if there were a way to tell the buttons apart? Luckily there is.<br />
<br />
All components have an integer property called ''Tag'' (remember: a control is just a special kind of component that inherits this Tag property). It is a property that has no actual function. It is there for us to use as we see fit. Now what if each button would have it's digit value stored in the Tag property…<br />
* Open the form (if necessary press F12 once or twice).<br />
* Select digit button 1 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''1''.<br />
* Select digit button 2 (click on it once).<br />
* In the Object Inspector locate the Tag property and change it's value to ''2''.<br />
* Repeat this for digit buttons 3..9.<br />
<br />
Now all digit buttons have a unique Tag value. We didn't change digit button 0 because the default Tag value already is 0.<br />
Now to make use if this Tag value:<br />
* Open the form.<br />
* Double click on digit button 0 (this will open the editor in the event handler of digit button 0). <br />
* Note that procedure ''btnDigit0Click'' has a parameter ''Sender '' of type ''TObject''.<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);</Delphi><br />
The ''Sender '' parameter is actually a reference to the button that was pressed. Via typecasting we can use the parameter as if it was a TButton. <br />
* Change the code like this:<br />
<Delphi>procedure TForm1.btnDigit0Click(Sender: TObject);<br />
begin<br />
AddDigit(TButton(Sender).Tag)<br />
end;</Delphi><br />
<br />
It doesn't look like we have accomplished much, replacing one line of code with another. However if we were to add the code for the other digits (1..9) it would look ''exactly'' the same. So all other digits can reuse this particular method!<br />
<br />
Let's have a closer look at the Object Inspector. <br />
* Open the form.<br />
* Select digit button 0 (btnDigit0).<br />
* In the Object Inspector select tab Events (see below).<br />
<br />
<br />
[[Image:tutcal_oi_events.png]]<br />
<br />
<br />
In the object inspector we can not only change the properties of a control but also the event handlers. In the Object Inspector we can see that as soon as digit button 0 is clicked, method ''btnDigit0Click '' is called (this is the ''OnClick'' event handler).<br />
<br />
* On the form: select digit button 2. In the Object Inspector we can now see that there is no OnClick event handler for button 2.<br />
* Open the drop down list for the OnClick event and select ''btnDigit0Click''.<br />
* Do this for all other digit buttons 3..9.<br />
<br />
Now all buttons share one common procedure that does exactly what we want except for digit button 1. Remember that for digit button 1 we created an event handler '' btnDigit1Click'' that we don't really need anymore.<br />
* On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is ''btnDigit1Click''.<br />
* Open the drop down list for the OnClick event and select btnDigit0Click.<br />
<br />
Now all buttons share the same event handler to add digits to the display box.<br />
<br />
* Run the program (press F9).<br />
* Click all buttons 0..9 a couple of times and see that it actually works.<br />
* End the program.<br />
<br />
<br />
For the digit buttons one final thing needs to be done: event handler ''btnDigit1Click'' still exists but is not used anymore and should be deleted. The safest way to do this (for now) is to let the IDE handle it. For this to work the option ''Auto remove empty methods'' must be enabled.<br />
* In the menu select Environment/Options.<br />
* Click on Editor/Completion and Hints.<br />
* Enable the option 'Auto remove empty methods' (see image below).<br />
* Press OK.<br />
<br />
[[Image:tutcal_auto_remove.png]]<br />
<br />
From now on all empty methods are automatically deleted as soon as the source file is saved.<br />
<br />
* Locate method ''procedure TForm1.btnDigit1Click(Sender: TObject) ''<br />
* Delete the line 'AddDigit(1)'<br />
* Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.<br />
<br />
==Tuning==<br />
So far so good: the calculator program compiles, runs and responds to clicks on digit buttons 0..9. But it doesn't behave exactly as we want: there's always this annoying zero at the beginning of the number and the number of allowed digits is too large.<br />
<br />
===Removing leading zeroes===<br />
Normally an integer number that's bigger (or smaller) than zero does not start with a leading zero. So our calculator should compensate for this. Luckily this is easy to implement. Remember that we have one and only one method that handles the addition of digits: AddDigit. This is the place to add logic to suppress the leading zero.<br />
<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;</Delphi><br />
<br />
===Limit the number of digits===<br />
This demo calculator cannot handle numbers that are too large. So we need to limit the number of digits that can be entered. Again the logical place to do this is the AddDigit method:<br />
* Locate method ''procedure TForm1.AddDigit(const pDigit: byte)''<br />
* Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end; </Delphi><br />
<br />
==Operations==<br />
Now it's time to look at the actual operations we want to implement: adding, subtracting, multiplying and dividing. The way the user is going to use the calculator goes something like this:<br />
#The user enters a number<br />
#The user presses a function button (e.g. '+')<br />
#The user enters a second number<br />
#The user presses '=' <br />
#The program responds with the addition of the first and second number<br />
<br />
As soon as the user presses the '=' button the program has to know three things:<br />
#What was the operation?<br />
#What was the first number?<br />
#What was the second number?<br />
<br />
===What was the operation?===<br />
Somehow we need to register that a certain operation type was selected. And for that we need to know what operation types are available. One way to implement this is to create an enumeration type (or user defined scalar type) that contains all valid operations.<br />
* In the Source Editor, find the location where the form is declared.<br />
* Just above the form add the type declaration ''TOperationType'' for all supported operations:<br />
<Delphi> type<br />
<br />
{ All supported operations for our calculator }<br />
TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)</Delphi><br />
<br />
* To temporarily store the operation, a variable is added to the private section of the form's class declaration.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the first number?===<br />
To temporarily store the first number that was entered we need a variable.<br />
* Add a variable to the form's private section.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
procedure AddDigit(const pDigit: byte);</Delphi><br />
<br />
===What was the second number?===<br />
* Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.<br />
<br />
== What's on your mind==<br />
Now it's time to implement the actions for the function buttons: add, subtract, multiply and divide. Let's start with the '+' button. As mentioned in one of the previous sections: when the '+' button is pressed, we need to store the first number and the operation type. So that's what we are going to do.<br />
* Open the form.<br />
* Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.<br />
<br />
Hold on! Before adding all the code here and doing the same for the three other operation buttons, remember what was said when the digit buttons 0..9 were added: do not add redundant code! It's reasonable to assume that the code for the other three operation buttons will be the same as for the '+' button, except for the operation itself. So let's save ourselves some work.<br />
* Locate the form's private section and add a new procedure: StoreOperation.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Place the blinking text cursor on the newly inserted line.<br />
* Press Ctrl-Shift-C (you know the drill by now…).<br />
<br />
The StoreOperation procedure must do two things: store the operation and store the number that was entered in the display, so it can be used afterwards.<br />
* Add the following code to the newly created procedure:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
<br />
Ok, now back to the '+' button:<br />
* Open the form.<br />
* Double click on button '+'.<br />
* Add the following code: StoreOperation(otPlus); <br />
* Open the form.<br />
* Double click on button '-'.<br />
* Add the following code: StoreOperation(otMinus);<br />
* Open the form.<br />
* Double click on button '*'.<br />
* Add the following code: StoreOperation(otMultiply);<br />
* Open the form.<br />
* Double click on button '/'.<br />
* Add the following code: StoreOperation(otDivide);<br />
<br />
Now test the program and see what happens:<br />
* Run the program (press F9)<br />
* Enter a number (e.g. 21267)<br />
* Press the '+' button<br />
* Enter the second number (e.g. 31170)<br />
<br />
What happens is that after pressing the '+' button, or any other operation button for that matter, the display is not cleared. We must find a way to make sure that the display is cleared, as soon as an operation button is pressed. Because we have used procedures to group similar actions, this again is an easy change.<br />
* Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);</Delphi><br />
* Position the blinking text cursor on the line StoreOperation.<br />
* Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.<br />
* In the StoreOperation procedure we must update the doClearDisplay variable, so we know that the display must be cleared as soon as a new number is entered. Change the code to this:<br />
<Delphi>procedure TForm1.StoreOperation(const pOperation: TOperationType);<br />
begin<br />
// Store the operation so it can be used later<br />
SelectedOperation := pOperation;<br />
<br />
// Store the number that was entered by the user<br />
FirstNumber := StrToInt(edDisplay.Text);<br />
<br />
// The display must start with a new number<br />
doClearDisplay := true;<br />
end;</Delphi><br />
* And where better to clear the display than in the AddDigit procedure? Change the code to:<br />
<Delphi>procedure TForm1.AddDigit(const pDigit: byte);<br />
begin<br />
// Must the display be cleared first?<br />
if doClearDisplay then<br />
begin<br />
edDisplay.Text := '0'; // Reset the display to zero<br />
doClearDisplay := false; // Once is enough...<br />
end;<br />
<br />
// Limit the number of digits<br />
if length(edDisplay.Text) < 8 then<br />
begin<br />
// Suppress leading zeroes when adding digits<br />
if edDisplay.Text = '0' then<br />
edDisplay.Text := IntToStr(pDigit)<br />
else<br />
edDisplay.Text := edDisplay.Text + IntToStr(pDigit)<br />
end;<br />
end;</Delphi><br />
<br />
Now let's see what happens:<br />
<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* End the program.<br />
<br />
We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.<br />
<br />
==Doing the math==<br />
Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.<br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the procedure:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
var result: longint;<br />
begin<br />
case SelectedOperation of<br />
otPlus: begin<br />
// Retrieve the second number<br />
SecondNumber := StrToInt(edDisplay.Text);<br />
// Do the math<br />
result := FirstNumber + SecondNumber;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);<br />
end;<br />
end;<br />
end;</Delphi><br />
The above code is pretty straightforward: if the user presses the '+' button, the first and second number are added up and the result is stored in the edit control on screen.<br />
<br />
We now have a working calculator (that can only add two numbers):<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press '+'<br />
* Enter another number.<br />
* Press '=' : the sum of the two numbers is displayed.<br />
* End the program.<br />
<br />
We now could add the 3 missing operations ('-', '*' and '/'). But hold on, there is room for improvement. Let's have a look at the following statement:<br />
<Delphi>SecondNumber := StrToInt(edDisplay.Text);</Delphi><br />
We have seen such a statement before: the StoreOperation procedure contains something similar:<br />
<Delphi>FirstNumber := StrToInt(edDisplay.Text);</Delphi><br />
Calculating the number the user entered now happens in two different locations. We do not want to repeat ourselves so it's a good idea to create a new function that does the calculation.<br />
<br />
* Locate the form's private section and add a new function: GetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;</Delphi><br />
* Position the blinking text cursor on the line GetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add this code to extract the value that is in the display field:<br />
<Delphi>function TForm1.GetDisplayValue: longint;<br />
begin<br />
result := StrToInt(edDisplay.Text);<br />
end;</Delphi><br />
* Locate the statement: FirstNumber := StrToInt(edDisplay.Text);<br />
* Change it to: FirstNumber := GetDisplayValue;<br />
<br />
So much for refactoring, back to the calculations. <br />
* Locate the statement: SecondNumber := StrToInt(edDisplay.Text);<br />
* Change it to: SecondNumber := GetDisplayValue;<br />
Now look at the following statements:<br />
<Delphi> // Retrieve the second number<br />
SecondNumber := GetDisplayValue;<br />
// Do the math<br />
result := FirstNumber + SecondNumber;</Delphi><br />
Variable ''SecondNumber'' is used to store the value in the display box. However it is not really necessary. The above code can be simplified:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;</Delphi><br />
<br />
Now look at the following statements:<br />
<Delphi> // Do the math<br />
result := FirstNumber + GetDisplayValue;<br />
// Display the resulting value<br />
edDisplay.Text := IntToStr(result);</Delphi><br />
The same now applies to the ''result'' variable. The above code can be simplified to:<br />
<Delphi> // Display the resulting value<br />
edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);</Delphi><br />
<br />
Now we can add the 3 remaining operations. <br />
* Open the form.<br />
* Double click on button '=' (the event handler is created).<br />
* Change the code:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
We now have a working calculator for all 4 operations:<br />
* Run the program (press F9).<br />
* Enter a number.<br />
* Press an operation button.<br />
* Enter another number.<br />
* Press '=' : the result is displayed.<br />
* End the program.<br />
<br />
==Intermezzo==<br />
After all this work we now have a useable calculator. But some things are not quite right. The obvious thing to try is dividing a number by zero. And the buttons 'C' and '+/-' don't work yet. These things will be addressed in the next section. <br />
<br />
First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):<br />
* Locate the form's private section and add a new procedure: SetDisplayValue.<br />
<Delphi> private<br />
{ private declarations }<br />
SelectedOperation: TOperationType;<br />
FirstNumber: longint;<br />
SecondNumber: longint;<br />
doClearDisplay: boolean;<br />
procedure AddDigit(const pDigit: byte);<br />
procedure StoreOperation(const pOperation: TOperationType);<br />
function GetDisplayValue: longint;<br />
procedure SetDisplayValue(const pValue: longint);</Delphi><br />
* Position the blinking text cursor on the line SetDisplayValue.<br />
* Press Ctrl-Shift-C.<br />
* Add the code below to give the display a new value, as the procedure name suggests:<br />
<Delphi>procedure TForm1.SetDisplayValue(const pValue: longint);<br />
begin<br />
edDisplay.Text := IntToStr(pValue);<br />
end;</Delphi><br />
<br />
The above code should look pretty familiar. Have a look at the procedure that does all calculations:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);<br />
otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);<br />
otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);<br />
otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
This procedure can now be simplified.<br />
* Change the code to:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);<br />
end;<br />
end;</Delphi><br />
<br />
==Loose ends==<br />
There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.<br />
<br />
===The +/- button===<br />
* Open the form.<br />
* Double click on button '+/-' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnPlusMinusClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0 - GetDisplayValue);<br />
end;</Delphi><br />
See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.<br />
<br />
Try it by running the program and press the '+/-' button.<br />
<br />
===The Clear button===<br />
* Open the form.<br />
* Double click on button 'C' (the event handler is created).<br />
* Add the following code:<br />
<Delphi>procedure TForm1.btnClearClick(Sender: TObject);<br />
begin<br />
SetDisplayValue(0); // Start from scratch<br />
SelectedOperation := otNone; // No operation selected yet<br />
doClearDisplay := false; // The display is already cleared<br />
end;</Delphi><br />
The above code is pretty self-explanatory: the display is cleared (the first line), we 'forget' about any pending operation by clearing the SelectedOperation variable and there is no need to clear the display when adding new digits, because it was already cleared by the first statement.<br />
<br />
===Divide by zero===<br />
Let's go crazy: run the application and try to divide 10 by 0. This will make the application crash horribly. We have to make sure that this will not happen. The place to check this of course is the place where all calculations are performed (TForm1.btnCalculateClick).<br />
* Open the form.<br />
* Double click on button '='.<br />
* Update the otDivide section:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
end;</Delphi><br />
<br />
Things noteworthy:<br />
#''MessageDlg'' is a function for displaying a short warning/error/informative message to the user. ''ShowMessage'' can also be used. It is a bit easier to use but cannot display warning/error icons.<br />
#''btnClearClick(nil)'': as soon as an error condition occurs we must reset the calculator. That's basically the same as pressing the 'C' button. We simulate pressing the 'C' button by directly calling the event handler.<br />
<br />
===Overflows===<br />
* Start the calculator<br />
* Enter 99999999 as the first number (8 digits)<br />
* Press button '*'<br />
* Enter 99999999 as the second number<br />
* Press button '='<br />
<br />
Now two things could have happened: <br />
#The application gives an incorrect result (something like 1674919425).<br />
# The application raises an error.<br />
<br />
If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:<br />
* Select from the menu Project/Project Options…<br />
* Select in the treeview Compiler Options/Code Generation.<br />
* Tick the box ''Overflow (-Co)'' (see image below).<br />
* Click OK.<br />
<br />
[[Image:tutcal_compiler_overflow.png]]<br />
<br />
Now run the program again and see what happens with overflows.<br />
<br />
<br />
If it was the second (and expected) option then this means we have to add exception handling to our little calculator. Exception handling is used to prevent an application from crashing when errors occur. In our case we want to handle the arithmetic overflow error that might occur. Because all calculations are done in one place, it's easy to catch any overflow errors.<br />
<br />
* Open the form.<br />
* Double click on button '='.<br />
* Change the code in the procedure to this:<br />
<Delphi>procedure TForm1.btnCalculateClick(Sender: TObject);<br />
begin<br />
// Catch any overflow errors<br />
try<br />
case SelectedOperation of<br />
otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);<br />
otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);<br />
otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);<br />
otDivide : if GetDisplayValue <> 0 then<br />
SetDisplayValue(FirstNumber div GetDisplayValue)<br />
else<br />
begin<br />
// Display an error message to the user<br />
MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);<br />
// Reset the calculator to start with a clean slate<br />
btnClearClick(nil);<br />
end<br />
end;<br />
except<br />
on E: EIntOverflow do<br />
begin<br />
// Display an error message<br />
MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);<br />
// Reset the calculator<br />
btnClearClick(nil);<br />
end<br />
end<br />
end;</Delphi><br />
<br />
Note that even with the exception handling in place, the application will still halt when run from inside the IDE. However the application is only paused and still active. Press F9 to continue. This will display another pop up window, a debugger notification window. Press Continue. Now our own exception handler will kick in with the expected message.<br />
If you were to run the application stand alone (i.e. outside the IDE) then you would only see the message box that we added to the exception handler.<br />
<br />
==Final tweaks==<br />
Remember that at a certain point a variable called ''SecondNumber'' was introduced. If you choose Run/Build All from the menu, then after building the application the compiler will display a message in the Messages window that this particular variable is never used. If you click on the message text the IDE opens the exact location in the editor where the variable is declared.<br />
* Click on message ''Note: Private field "TForm1.SecondNumber" is never used''.<br />
* Delete longint variable ''SecondNumber''.<br />
<br />
<br />
As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).<br />
<br />
[[Image:tutcal_calculator_focus.png]]<br />
<br />
This is counter intuitive because a user should not be able to enter anything in that box. Even worse as soon as she would type something in there that is not a number, our calculator would crash! So it's better not to give access to the that control at all. We are going to fix that.<br />
* Open the form.<br />
* Select the display control (click on edDisplay).<br />
* In the Object Inspector change ReadOnly to ''True'' (if the Events tab is still visible, select the Properties tab first to gain access to all properties). From now on it's impossible to enter any data manually.<br />
* Change TabStop to ''False''. Now it's impossible to get to the display field via the keyboard and the display field will not be highlighted anymore.<br />
<br />
Run the program to see the result of these changes.<br />
<br />
<br />
(Under construction: OO-ify the program)<br />
<br />
[[Category:Tutorials]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Projects_using_Free_Pascal&diff=49401Projects using Free Pascal2011-04-13T17:30:08Z<p>Antoniog: /* LazPad */</p>
<hr />
<div>{{Projects using Lazarus}}<br />
<br />
==See also==<br />
<br />
* [[Lazarus Application Gallery]] <br />
* [[Components and Code examples]]<br />
* [[Operating Systems written in FPC]]<br />
* [[Using the Lazarus-ccr SVN repository]]<br />
<br />
== Components and Libraries ==<br />
<br />
=== 5dpo ===<br />
[[5dpo]] Component Library is a set of components developed by the [http://www.fe.up.pt/~robosoc 5dpo Robotic Soccer Team]. It provides a visual serial port (TSdpoSerial) implementation of [[Projects_using_Lazarus#Synaser|Synaser]], an IEEE1394 camera (TSdpoVideo1394) component, an [http://linux-uvc.berlios.de/ UVC video] driver component (TSdpoVideo4L2) for webcams, a Gtk fast painting form (TSdpoFastForm) and a Joystick (TSdpoJoystick) component.<br />
<br />
=== Audorra ===<br />
[http://audorra.sourceforge.net Audorra] is a digital audio library for Delphi and Freepascal. Using a flexible plugin architecture, it allows you to exchange the audio backend (e.g. WaveOut, OpenAL), add protocol classes (e.g. file, http) and decoders. <br />
<br />
=== BrasLib ===<br />
[http://br.groups.yahoo.com/group/BrasLib-devel/ BrasLib] is a new report component for Lazarus under development by brazilian programmers. <br />
<br />
=== CUPS for lazarus ===<br />
Olivier Guilbaud [http://cups4lazarus.sourceforge.net/ CUPS for lazarus project] is developing the bindings for pascal to use the CUPS (Common UNIX Printing System) libraries. With some dialogs for select printer, setup printer, setup printer jobs.<br />
<br />
Note: This package is deprecated, Cups for Lazarus is now integrated in Printers4Lazarus package which is included with Lazarus. --[[User:Jesusrmx|jesusrmx]] 20:10, 26 June 2006 (CEST)<br />
<br />
===DXScene===<br />
[http://www.ksdev.com DXScene] DXScene is a 3D hardware accelerated graphics library. It increases the speed of the development of all graphical applications. It provides: a 3D and 2D graphical editor integrated in IDE, 3D shapes and transformation, 2D graphical objects, simplify animation, advanced windows and controls, maximum performance, skinning engine, bitmap effects, 3DS file converter. DXScene can be used as development tool for standard, multimedia, SCADA, GIS, CAD and KIOSK applications. It support Windows, Mac OS X and Linux. For more info see [http://www.ksdev.com www.ksdev.com].<br />
<br />
===FlashEngine===<br />
[http://www.ksdev.com FlashEngine] FlashEngine is a set of components for Delphi, C++ Builder and Lazarus which add extra features to Adobe Flash (ActiveX or Netscape plugin)- such as loading from any sources, grab real 32-RGBA frames, real transparency playing. It supports Windows and Mac OS X. For more info see [http://www.ksdev.com www.ksdev.com].<br />
<br />
=== GTK2forpascal ===<br />
Mattias Gaertner's [http://sourceforge.net/projects/gtk2forpascal/ gtk2forpascal project] is developing the bindings for pascal to use the gtk2 libraries (gimp tool kit). Supported Languages are [[Free Pascal]] and Kylix and the bindings are intended to work under Linux, FreeBSD and Win32. These bindings are now also part of the packages supplied with fpc.<br />
<br />
=== Habari ActiveMQ Client / Habari OpenMQ Client ===<br />
[http://www.mikejustin.com/ Habari ActiveMQ Client] is a library (and components) for Delphi(tm) 6 to 2009 and Free Pascal which provides easy access to [http://activemq.apache.org/ Apache ActiveMQ], the most popular and powerful open source Message Broker.<br />
With Habari ActiveMQ Client, applications can connect to Apache ActiveMQ servers, subscribe to queues and topics, send and receive messages and objects, and work with transactions. The library follows the specification of the [http://en.wikipedia.org/wiki/Java_Message_Service JMS API] for Message Oriented Middleware. The communication layer supports Synapse and Internet Direct (Indy) for Lazarus.<br />
<br />
[http://www.mikejustin.com/ Habari OpenMQ Client] is a library for Delphi(tm) 6 to 2009 and Free Pascal which provides easy access to the [https://mq.dev.java.net/about.html Open Message Queue (OpenMQ)] Message Broker, a very compact, fast and easy to use message queue system. OpenMQ is part of the GlassFish(tm) application server for the Java(tm) platform. The library follows the specification of the [http://en.wikipedia.org/wiki/Java_Message_Service JMS] API for Message Oriented Middleware. The communication layer supports Synapse and Internet Direct (Indy) for Lazarus.<br />
<br />
=== Indy for lazarus ===<br />
Begun only a short while ago, this project has as an ambition to port the 119 Indy components from Delphi/Kylix to FPC/Lazarus.<br />
See [http://indy4lazarus.sourceforge.net/ Indy for Lazarus project] and a <br />
[http://indy4lazarus.sourceforge.net/images/img1_1.jpg screenshot].<br />
<br />
=== LazReport ===<br />
LazReport is a group of components to add reporting capabilities to applications, it uses a visual designer to create banded reports and includes a report engine with interpreter to run user scripts and a report previewer, report designer can be invoked at runtime.<br />
<br />
LazReport is based on FreeReport 2.32 and thanks to Fast Reports Inc. it's available under modified LGPL, the same license as the Lazarus LCL.<br />
<br />
'''Note.''' Since Lazarus 0.9.23 revision 11950, LazReport source code is<br />
already included in Lazarus/components/lazreport directory.<br />
<br />
=== Man Frames ===<br />
<br />
[http://www.liberlog.fr/Man-Frames-Framework Man Frames] is some Management components for tables. Some data or property forms can manage quickly data. A prepared software with user Management and Functions management permits to create quickly a Management software. It depends on [http://www.liberlog.fr/Extended-Components Extended] components which are data components. [http://www.liberlog.fr/XML-Frames-engine Another project] permits to create a Management software from LEONARDI files. On WINDOWS and LINUX. Free components with LGPL license.<br />
<br />
=== KGrid ===<br />
<br />
[http://www.tkweb.eu/en/delphicomp/kgrid.html KGrid] - Powerfull grid/data aware grid solution for Delphi and Lazarus. Freeware with source.<br />
<br />
=== Synapse ===<br />
The [http://www.ararat.cz/synapse/ Synapse Project] by Lukas Gebauer provides a serial port and synchronous TCP/IP Library.<br />
<br />
=== Synaser ===<br />
Library for serial communication (Linux, Windows) from author of Synapse.<br />
homepage: http://www.ararat.cz/synapse/ (same as Synapse)<br />
<br />
=== The Icebox ===<br />
A lot of useful Lazarus/FPC related information and components can be found on Tony Maro's [http://tony.maro.net/ Icebox site]. His TMPack, Checkbook Tracker and RDP Frontend application are all excellent examples of the quality components and applications that Lazarus is capable of producing.<br />
<br />
=== The Light Pascal Toolkit (LPTK) ===<br />
The goal of the [http://lptk.sourceforge.net/ Light Pascal Toolkit] Project is to create a free object pascal toolkit for linux and windows GUI development. It looks pretty interesting... check out the [http://lptk.sourceforge.net/screenshots.php screenshots]!<br />
<br />
===VGScene===<br />
[http://www.ksdev.com VGScene] VGScene speeds the development of all graphical application, providing: a graphical editor integrated in IDE, graphical objects, simplify animation, advanced windows and controls, maximum performance, skinning engine, bitmap effects. VGScene can be used as development tools for standard, multimedia, SCADA, GIS, CAD and KIOSK applications. Support Windows, Mac OS X and Linux. For more info see [http://www.ksdev.com www.ksdev.com].<br />
<br />
===ZenGL===<br />
<br />
[http://www.zengl.org ZenGL] is an open source library with tools, which helps to develop games and interactive application for different platforms.<br />
<br />
== Multimedia ==<br />
<br />
=== Audio X ===<br />
[http://www.ullihome.de Audio X] is an media management tool, that organizes and sorts your media without a database so everything is ever actual. A lot of audio formats are useable directly but you can also organize your LP or CD collection with it, it stores the data in XML Files so they are viewable also with a webbrowser ... <br />
<br />
=== Cactus Jukebox ===<br />
Cactus is an audio player that comes with a database to organize your mp3 file collection. Take a look at [http://cactus.hey-you-freaks.de Cactus Homepage]. It's plattform independent and currently available for linux and win32. <br />
<br />
Since actual v0.3 it supports managing and uploading files on a mobile player.<br />
<br />
=== gdvdslides ===<br />
[http://rimrocksoftware.com/node/2 gdvdslides] is a Linux graphical user interface for the command line program dvd-slideshow, which allows you to create a video from a set of video clips, JPEG image files and audio files. gdvdslides supports slide transitions, title slides, background images and multiple audio tracks. It also allows cropping, Ken Burns effect and scrolling slide effects. gdvdslides comes with complete documentation and tutorial.<br />
<br />
=== GLScript ===<br />
GLScript A simple, free, open-source scripting language for developing 3D games and animations. It can be found here: [http://glscript.sourceforge.net GLScript's homepage]. (GL stands for Graphics Library, I.E. Graphics Library Scripting) There are currently plans to have a code-converter to make scripts compilable with lazarus/fpc and other languages to make a standalone executable from your creation.<br />
<br />
=== KSP Sound Player ===<br />
[https://code.google.com/p/kspnew/ KSP] - Easy in use yet powerful audio player supporting multiple file formats and features like dynamic playlists, bookmarking or network streaming. It also used to be hosted in [http://ksplayer.com this site].<br />
<br />
=== OggBase ===<br />
[http://sourceforge.net/projects/oggbase/ OggBase] is a Free Pascal/Lazarus program for managing your Ogg-Vorbis files in a Database.<br />
<br />
=== LazPaint ===<br />
Image manipulation application. <br />
[http://sourceforge.net/projects/lazpaint/ LazPaint]<br />
<br />
=== PicturesToExe Mac OS X Slideshows ===<br />
[http://www.wnsoft.com WnSoft] is using Lazarus IDE to develop FPC-based slideshow viewer for Mac OS X, and planned PicturesToExe for OSX.<br />
<br />
=== WinFF ===<br />
[http://www.winff.org WinFF] is a GUI for the command line video converter, FFMPEG. It will convert most any video file that FFmpeg will convert. WinFF does multiple files in multiple formats at one time. You can for example convert mpeg's, flv's, and mov's, all into avi's all at once. WinFF is available for Windows 95, 98 , ME, NT, XP, VISTA, and Debian, Ubuntu, Redhat based GNU/Linux distributions.<br />
<br />
== Games ==<br />
<br />
=== 30 Seconds Free Software ===<br />
[http://code.google.com/p/30seconds 30 Seconds] is software package that creates cards for the [http://en.wikipedia.org/wiki/30_Seconds_(game) 30 Seconds] board game. It also has a playing interface if you want to play on your laptop / PC (and hopefully soon WinCE devices). <br />
<br />
=== Daring Apprentice ===<br />
[http://daringapprentice.wikispaces.com Daring Apprentice] is a 3d [http://www.wizards.com/magic/ Magic: The Gathering] tabletop. It uses GLScene, and lNet.<br />
<br />
=== Game Maker ===<br />
[http://www.yoyogames.com/gamemaker Game Maker] allows you to make computer games using easy to learn drag-and-drop actions. You can create professional looking games within very little time. You can make games with backgrounds, animated graphics, music and sound effects, and even 3D games! And when you've become more experienced, there is a built-in programming language, which gives you the full flexibility of creating games with Game Maker. What is best, is the fact that Game Maker can be used free of charge.<br />
<br />
Originally written in Delphi, Lazarus/Free Pascal was used to port it from Win32 to Mac OS X and could be used in future for Linux and other platforms.<br />
<br />
=== Kambi VRML game engine ===<br />
<br />
[http://vrmlengine.sourceforge.net/ Kambi VRML game engine] is a 3D open-source game engine. The engine was developed from the beginning using FreePascal (we have also Lazarus components) in nice and clean ObjectPascal code. We support many 3D model formats, including [http://vrmlengine.sourceforge.net/vrml_x3d.php VRML/X3D], hence the engine name. Some finished programs: [http://vrmlengine.sourceforge.net/view3dscene.php view3dscene - 3D model viewer, VRML/X3D browser] and [http://vrmlengine.sourceforge.net/castle.php castle - FPS game in a dark fantasy world].<br />
<br />
=== 'Pnigin' project (a 'Pengo' Remake) ===<br />
The 'Pnigin' project is an advanced remake of the 80's arcade classic 'Pengo' .<br />
<br />
The project was made from scratch, using all original artwork and music. The project used Delphi 5 personal, Lazarus and Free Pascal for development.<br />
<br />
As the project is currently in a beta stage, there is no working demo yet. It is expected that a playable demo is released in summer 2008.<br />
<br />
See the Gong-Proces site [[http://www.naton.org]] for more information regarding the project.<br />
<br />
== Web ==<br />
<br />
=== ExtPascal ===<br />
An Ext JS wrapper. [http://extpascal.googlecode.com ExtPascal] lets you use the ExtJS from Object Pascal commands issued by the server. That brings the structure and strict syntax of the Object Pascal for programming the web browser.<br />
<br />
== Education and Scientific ==<br />
<br />
=== ApertaQuem ===<br />
[http://wp.me/pWoqh-3s ApertaQuem] Electronic ballot box for mock elections. Is available to create any candidate with photo from the webcam or file. Exclusive use for school environments. [http://sourceforge.net/projects/apertaquem/ Sourceforge page] <br />
<br />
=== ApertaLetra ===<br />
[http://wp.me/pWoqh-28 ApertaLetra] A text editor colorful and cheerful, where available, without leaving the context of software: formatting, new / open / save, cut / copy / paste and print. [http://sourceforge.net/projects/apletra Sourceforge page]<br />
<br />
=== Jubarte ===<br />
[http://jubartecalc.googlepages.com/ Jubarte] aims to create a complete application suite to calculate and analyse the viability of telecommunication links. Jubarte is able to calculate links using Radio, Optical Fiber and Satellites, in the newer versions capabilities to calculate auxiliary systems is being added. Jubarte is being developped in Lazarus enviroment and exist binaries for Windows, Linux and OSX.<br />
<br />
=== Master Maths ===<br />
[http://www.mastermaths.co.za Master Maths] specialises in computer based training and maths. The 3rd incarnation of our flagship product is developed using Lazarus, Firebird, [http://tiopf.sourceforge.net/ tiOPF v2] and the [http://opensoft.homeip.net/fpgui/ fpGUI Toolkit]. The product has two parts. A GUI Administration application and a CGI Learner Browser (used to view and mark the teaching modules). The Learner Browser uses Macromedia Flash extensively. The complete product runs under Linux and Windows.<br />
<br />
=== Morse Machine ===<br />
[http://downloads.tech-pro.net/morse-machine_tpmm01.html Morse Machine] is an implementation of "A Fully Automatic Morse Code Teaching Machine" first described in a May 1977 QST article of the same name by Ward Cunningham using Lazarus. The program teaches Morse code by sending a character and waiting for you to type what you heard on the keyboard. It grades your score and adds new characters when it sees that you are ready. The program is released under the GNU GPL version 2. Due to its use of the sound card, this implementation is for the Windows platform.<br />
<br />
=== MRIcron ===<br />
[http://www.mricro.com/mricron/ MRIcron] is an opensource project that allows users to visualize and volume render medical images (MRI, CT, PET). It includes tools for lesion mapping, non parametric statistical analysis ([http://www.mricro.com/npm/ npm]), and conversion from the medical DICOM format to the scientific NIfTI format ([http://www.mricro.com/mricron/dcm2nii.html dcm2nii]). It is available for Windows, Linux and Mac OS X.<br />
<br />
=== OctaveGUI ===<br />
[http://code.google.com/p/octave-gui/ OctaveGUI] is a(nother) GUI frontend for GNU Octave.<br />
<br />
=== SignWriter ===<br />
SignWriter is an Ancient Egyptian Hieroglyphic Word Processor and Language tool. It is designed for creating and editing texts stored in MdC format and would be of interest to students, professionals, and anyone with an interest in the Ancient Egyptian Language.<br />
homepage: http://signwriter.scribeacademy.com/<br />
<br />
=== Skychart / Cartes du Ciel ===<br />
[http://www.ap-i.net/skychart Skychart] is a free software to draw a map of the night sky for the amateur astronomer from a bunch of stars and nebulae catalogs. It shows the position of the planets, simulates an eclipse and more. <br />
<br />
=== SPINA ===<br />
[http://spina.medical-cybernetics.de/en/ SPINA] is software for determining constant structure-parameters of endocrine feedback control systems from hormone levels obtained in vivo. The first version of this cybernetic approach allows for evualuating the functional status of the thyroid gland.<br />
<br />
=== Virtual Moon Atlas ===<br />
[http://ap-i.net/avl/en/start Virtual Moon Atlas] is software for lunar observation and study. It use GLscene to give a realistic view of the Moon at any given location and time. The computation are done with the JPL ephemeris for extensive precision. It include the most complete lunar formation database and picture library. The binary distribution is available for Windows, Mac and Linux.<br />
<br />
=== Xoctave===<br />
[http://xoctave.webs.com/ Xoctave] is an Human interface to GNU Octave. Xoctave encapsulates GNU Octave using pipes and provides extra useful tools to make GNU Octave more easier. XOctave is written in Pascal using Lazarus front-end and Free Pascal (aka FPK Pascal) libraries, uses<br />
synedit for syntax highlighting, and uses the Lazarus Component Library (LCL) is a set of visual and non-visual component classes over a Widget toolkit-dependent layer with multi-language support (English-Turkish)<br />
<br />
=== Manuscript4u ===<br />
[https://sites.google.com/site/manuscript4u/home Manuscript4u] is a GNU/GPL open source project to read and search on the Bible that includes Gematria (Bible Numerics). The Bible files can be downloaded from the UnboundBible site in many languages and converted to the format used by the program with an included conversion program. Currently the binary is available for Linux only. Multi-language support.<br />
<br />
== Management, Accounting and other Business Software ==<br />
<br />
=== Gestinux ===<br />
[https://sourceforge.net/projects/gestinux/ Gestinux] is a small accounting software, to enter moves and import in various formats, to reconcile, and to print usual reports. It is in english and in french, and can easily be translated to other languages. It is possible to setup specific reports for various countries. It runs on Linux and Windows, using MySql.<br />
<br />
=== OutKafe ===<br />
[http://www.outkastsolutions.co.za/outkast/index.php?option=com_openwiki&Itemid=45&id=outkafe OutKafe] is a next-generation free and open source cybercafe management suite. It currently is running hundreds of cybercafe's at businesses, schools and other establishments around the world.<br />
<br />
=== RiXtoR ===<br />
[http://www.freewebs.com/bpsoftware/RiXtoR/rixtor.htm RiXtoR] is a Point of Sale program specially designed for restaurants, working on both Windows and GNU/Linux Systems<br />
<br />
=== SilentCoder's Site ===<br />
DireqCafe A complete and full full featured internet cafe solution for LTSP and a number of other useful lazarus programs can be found on A.J. Venter's site: [http://www.silentcoder.co.za silentcoder.co.za].<br />
<br />
=== TruckBites ===<br />
Business management software for independent trucking companies and owner/operators (for the USA.) Written under contract by [[user:Tonymaro | Tony Maro]] for both Linux and Windows for "Partners in Trucking, LLC".<br />
http://www.truckbites.com<br />
Still under development, anticipated release in the next few months.<br />
<br />
=== TurboCash ===<br />
[http://www.turbocash.net/wiki/index.php?title=Developer:Lazarus Open Source Accounting software]<br />
<br />
== Utilities and Miscelaneous ==<br />
<br />
=== Becape ===<br />
[https://sourceforge.net/projects/becape/ Becape] is a open source backup tool aimed to personal/desktop usage. It does incremental backups and stores the backup info in a sqlite database allowing to restore the exact state of the backed files at a chosen date. It's fully written in Lazarus/Free Pascal.<br />
<br />
=== BeniBela's tools/components ===<br />
On [http://www.benibela.de BeniBela online] I published some components for Lazarus and tools based on them/it. <br />
<br />
They include: A treelistview control which is a mix between a treeview and a listview, a diagram unit which displays diagrams based on a model/view concept and a templated based html parser which matches the structure of the parsed file to the one of a previously created template.<br />
<br />
The tools only works on Windows, and are an API Manager to control the Win32-API and a sun simulator which changes the settings of the graphic card to match the natural sun light<br />
<br />
=== dbmaker ===<br />
[http://www.rgsoftware.de dbmaker] is a database application using TDbf and LazReport. Its user interface language is german.<br />
<br />
=== Dedalu ===<br />
A collection of small and simple projects developed in Lazarus by Giuseppe Ridinò (aka Pepecito). They are games, editors, utilities, etc.<br><br />
Homepage: http://dedalu.sourceforge.net/<br />
<br />
=== Double Commander ===<br />
Double Commander is a cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas. Homepage: http://sourceforge.net/projects/doublecmd/<br />
<br />
=== ExPress ===<br />
A GUI wrapper for UPX (Ultimate Packer for eXecutables). Download it [http://code.google.com/p/express-gui here].<br />
<br />
=== ExVan ===<br />
[http://www.cforce.gr/sales.htm ExVan] a WinCE/Win32 mobile invoicing program with batch data transfer for Greek ERP systems or standalone use.<br />
<br />
=== fenixsql ===<br />
[http://fblib.altervista.org fenixsql] is a simple admin tool for firebird sql database<br />
<br />
=== Fit Easily ===<br />
[http://fiteasily.com Fit Easily] is an online service for building the model of some experimental data, fitting its parameters and storing the results together with the data. Both of the cgi and the core was coded with Lazarus.<br />
<br />
=== Free Pascal Operating System ===<br />
<br />
Interested in developing an OS with Free Pascal? This project can be used as a starting point (though incomplete and YOU ARE WELCOME to complete it :-)). Download it [http://code.google.com/p/fpos here](http://code.google.com/p/fpos).<br />
<br />
Another interesting project developed with Free Pascal called TORO can be found at: [http://toro.sourceforge.net TORO:] (http://toro.sourceforge.net).<br />
<br />
=== CQRLOG ===<br />
[http://www.sourceforge.net/projects/cqrlog/ CQRLOG] is an advanced ham radio logger based on Firebird database. Provides radio control based on hamlib libraries (currently support of 140+ radio types and models), DX cluster connection, QRZ callbook (web version), a grayliner, ON6DP QSL manager database support and a most accurate country resolution algorithm based on country tables developed by OK1RR. CQRlog is strongly focused on easy operation and maintenance.<br />
<br />
=== GTK-Fireadmin ===<br />
A GTK based Firebird Administration tool using Firebird Objects and Lazarus Components is available [http://sourceforge.net/projects/gtkfireadmin/ here].<br />
<br />
=== Heat Wizard ===<br />
[http://heatwizard.berlios.de/Heat_Wizard.html Heat Wizard] is a command line and GUI tool for the conversion of the voltage of a thermocouple to a temperature and vice versa (for Win32, Mac OS X, and Linux).<br />
<br />
=== ISA Digital Osciloscope ===<br />
A graphical interface for a digital osciloscope. The osciloscope itself is an ISA card with a probe to measure waves. It works on both Windows and Linux. There is some information on how it is being built on [[Hardware Access]]. The full documentation (in English and Portuguese), screenshots and the source code of project can be downloaded [http://eletronicalivre.incubadora.fapesp.br/portal/english/oscilloscope/ here].<br />
<br />
=== Kamouflage ===<br />
[http://wiki.lazarus.freepascal.org/User:Beli0135 Kamouflage] - Camouflage files into images<br />
<br />
=== LazFileSplitter ===<br />
[http://br.geocities.com/antoniog123456/ LazFileSplitter] is a utility to split and merge big files.<br />
<br />
<br />
<br />
=== LazVisual ===<br />
[http://br.geocities.com/antoniog123456/ LazVisual] is an external tool to include resources on executable file and set application icon.<br />
<br />
=== Mep LA ===<br />
[http://software.viamep.com/mepla/ Mep LA] is a simple and fast text editor. Key features: working with txt and html/php files, replacement and some customizable scripts with shortcuts. You can configure replacement and run it with a click or keyboard combination.<br />
<br />
=== PasDoc ===<br />
<br />
[http://pasdoc.sourceforge.net/ PasDoc] is an open-source documentation generator for ObjectPascal source code. It reads documentation from comments in your source code (an option to read it from an external file is also available), and generates nice docs in HTML, LaTeX or other formats. We have a console program, and a cross-platform GUI version using Lazarus.<br />
<br />
=== PasMonTray ===<br />
<br />
[http://pasmontray.sourceforge.net/ PasMonTray] is an open-source CPU and memory usage monitor that sits in the system tray. Uses [[TrayIcon]] and various Win32 api calls.<br />
<br />
=== Project PouchHiker ===<br />
PouchHiker is written in Lazarus, using KOL-CE and lNet.<br />
PouchHiker lets you connect and participate in the gps-carpool network (www.gps-carpool.net).<br />
See www.pouchhiker.com for download and description.<br />
<br />
=== Project Theseus ===<br />
Tom Lisjac's [http://theseus.sourceforge.net Project Theseus] is using Lazarus and FPC for creating a rapid deployment and distribution system for Linux called [http://theseus.sourceforge.net/index.php?wiki=EpikBuilder Epik-Builder]. [http://theseus.sourceforge.net/index.php?wiki=EpikStopwatch EpikStopwatch] and [http://theseus.sourceforge.net/index.php?wiki=EpikBrowser EpikBrowser] are also Lazarus based projects that are currently under development. <br />
<br />
=== QFront ===<br />
[http://www.ullihome.de QFront] is a platform independent Frontend for the CPU Emulator QEmu<br />
<br />
=== SFS Technology ===<br />
Linux technology to solve the dependencies problems on a Debian/Ubuntu/Linux Tiger operating system. <br />
For more infos see:<br />
[http://code.google.com/p/sfs-technology/ SFS-Technology]<br />
<br />
=== Seksi Commander ===<br />
GPL File manager for Linux developed in Lazarus and Free Pascal.<br />
Integrated bin, text, hex viewer (own component) and editor based on SynEdit.<br />
Home Page: http://radekc.regnet.cz/<br />
<br />
=== Shell for Gammu (Mobile Phone Tool) ===<br />
The [http://www.petersieg.de/gammush Gammush Site] offers hardcopies and downloads for this<br />
Application. Gammush is a shell for gammu.exe. It allows to backup/restore your phone data,<br />
get, edit , put logos, set date+time, send sms messages etc.<br />
<br />
=== Siages ===<br />
[http://siages.solis.coop.br/ Siages] is an ERP application made with Lazarus.<br />
<br />
=== SMTPUtils ===<br />
[http://smtputils.sourceforge.net/ SMTPUtils] A tool to tunning your SMTP server against the Open relay, Spam, Virus, to measure the performance, verify it in the black lists (DNSBL) and more.<br />
<br />
=== Transmission Remote GUI ===<br />
[http://code.google.com/p/transmisson-remote-gui/ Transmission Remote GUI] is a feature rich cross platform front-end to remotely control a Transmission Bit-Torrent client daemon via its RPC protocol. Transmission Remote GUI is faster and has more functionality than the build-in Transmission web interface.<br />
<br />
=== Virtual Magnifying Glass ===<br />
[http://magnifier.sourceforge.net/ Virtual Magnifying Glass] is designed for visually-impaired and others who need to magnify a part of the screen. Unlike most similar programs it does not open a separate window for the magnification but instead puts a movable magnifying glass on screen. The project was converted from Visual Studio .NET to Lazarus and now offers a Linux version. Mac OS X and Pocket PC versions are planned.<br />
<br />
=== Wi(n)XtaP ===<br />
[http://www.freewebs.com/bpsoftware/ Wi(n)Xtap] (formed by the words Windows XP Vista) was a program created for early versions of Lazarus. This program allowed the creation of the .manifest file so to set up a graphical theme to your application and it allowed the user to define a customized icon. This program is useless since 0.9.24 because those features have been implemented into the IDE itself. Stable releases of Wi(n)XtaP where the 4.0 beta, 5.0, 6.0 and the latest 6.1 (fixes of 6.0). Further plans to expand its capabilities are temporally blocked.<br />
<br />
=== WikiHelp ===<br />
[http://www.ullihome.de WikiHelp] is an small Tool that generates HTML Pages from an Wiki. It downloads the content Automatically and convert the WikiText Pages into HTML. Most WikiText Features are useable including Images,tables and so on.<br />
<br />
'''If your Lazarus project should be listed here, please edit this page and add it!'''<br />
<br />
[[Category:Promotion]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=paszlib&diff=47255paszlib2011-01-14T15:21:01Z<p>Antoniog: /* Unzip files */</p>
<hr />
<div>{{paszlib}}<br />
<br />
'''paszlib''' is a Pascal conversion (thus without dependancies) of the standard zlib library, implemented by Jacques Nomssi Nzali (his old homepage is dead, see a continuation of the project [http://sageshome.net/oss/paszlib-sg.php here]) It is used in the FCL to implement the TCompressionStream class. The main unit of this package is '''paszlib'''. there are other, auxiliary units, but the only unit that needs to be included in a typical program is this one. (View interface) <br />
<br />
==TZipper==<br />
<br />
===Using the latest TZipper===<br />
<br />
In FPC 2.3.1 there are many fixes which make TZipper much better. To be able to use them until the next FPC is released with those fixes one should follow the following steps:<br />
<br />
1 - Download zipper.pp, and only this file, from: http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/paszlib/src/<br />
<br />
2 - Rename the file to a unique name, to avoid conflict with the fpc unit, like myzipper.pp and also change the name inside the source file.<br />
<br />
3 - Add the file to your project and use the TZipper from there.<br />
<br />
===Examples===<br />
<br />
====Zip files====<br />
<br />
Create zip file named as parameter 1 from files entered as rest parameters.<br />
<br />
<delphi>uses<br />
Zipper;<br />
var<br />
Zipper: TZipper;<br />
begin<br />
try<br />
Zipper := TZipper.Create;<br />
Zipper.FileName := ParamStr(1);<br />
for I := 2 to ParamCount do<br />
Zipper.Entries.AddFileEntry(ParamStr(I), ParamStr(I));<br />
Zipper.ZipAllFiles;<br />
finally<br />
Zipper.Free;<br />
end;<br />
end.</delphi><br />
<br />
====Unzip files====<br />
<br />
Unzip all files contained in archive with name given by ZipFilePath to directory entered as UnzippedFolderName.<br />
<br />
<delphi>uses<br />
Zipper;<br />
var<br />
UnZipper: TUnZipper;<br />
begin<br />
UnZipper := TUnZipper.Create;<br />
try <br />
UnZipper.FileName := ZipFilePath;<br />
UnZipper.OutputPath := UnzippedFolderName;<br />
UnZipper.Examine;<br />
UnZipper.UnZipAllFiles;<br />
finally<br />
UnZipper.Free;<br />
end;<br />
end.</delphi><br />
<br />
More examples can be found in FPC source directory [http://svn.freepascal.org/svn/fpc/trunk/packages/paszlib/examples/]<br />
<br />
<br />
Go to back [[Package_List|Packages List]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=paszlib&diff=47253paszlib2011-01-14T15:18:31Z<p>Antoniog: /* Unzip files */</p>
<hr />
<div>{{paszlib}}<br />
<br />
'''paszlib''' is a Pascal conversion (thus without dependancies) of the standard zlib library, implemented by Jacques Nomssi Nzali (his old homepage is dead, see a continuation of the project [http://sageshome.net/oss/paszlib-sg.php here]) It is used in the FCL to implement the TCompressionStream class. The main unit of this package is '''paszlib'''. there are other, auxiliary units, but the only unit that needs to be included in a typical program is this one. (View interface) <br />
<br />
==TZipper==<br />
<br />
===Using the latest TZipper===<br />
<br />
In FPC 2.3.1 there are many fixes which make TZipper much better. To be able to use them until the next FPC is released with those fixes one should follow the following steps:<br />
<br />
1 - Download zipper.pp, and only this file, from: http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/paszlib/src/<br />
<br />
2 - Rename the file to a unique name, to avoid conflict with the fpc unit, like myzipper.pp and also change the name inside the source file.<br />
<br />
3 - Add the file to your project and use the TZipper from there.<br />
<br />
===Examples===<br />
<br />
====Zip files====<br />
<br />
Create zip file named as parameter 1 from files entered as rest parameters.<br />
<br />
<delphi>uses<br />
Zipper;<br />
var<br />
Zipper: TZipper;<br />
begin<br />
try<br />
Zipper := TZipper.Create;<br />
Zipper.FileName := ParamStr(1);<br />
for I := 2 to ParamCount do<br />
Zipper.Entries.AddFileEntry(ParamStr(I), ParamStr(I));<br />
Zipper.ZipAllFiles;<br />
finally<br />
Zipper.Free;<br />
end;<br />
end.</delphi><br />
<br />
====Unzip files====<br />
<br />
Unzip all files contained in archive with name given by first parameter to directory entered as second parameter.<br />
<br />
<delphi>uses<br />
Zipper;<br />
var<br />
UnZipper: TUnZipper;<br />
begin<br />
UnZipper := TUnZipper.Create;<br />
try <br />
UnZipper.FileName := ParamStr(1);<br />
UnZipper.OutputPath := ParamStr(2);<br />
UnZipper.Examine;<br />
UnZipper.UnZipAllFiles;<br />
finally<br />
UnZipper.Free;<br />
end;<br />
end.</delphi><br />
<br />
More examples can be found in FPC source directory [http://svn.freepascal.org/svn/fpc/trunk/packages/paszlib/examples/]<br />
<br />
<br />
Go to back [[Package_List|Packages List]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=paszlib&diff=47234paszlib2011-01-14T14:41:00Z<p>Antoniog: /* Unzip files */</p>
<hr />
<div>{{paszlib}}<br />
<br />
'''paszlib''' is a Pascal conversion (thus without dependancies) of the standard zlib library, implemented by Jacques Nomssi Nzali (his old homepage is dead, see a continuation of the project [http://sageshome.net/oss/paszlib-sg.php here]) It is used in the FCL to implement the TCompressionStream class. The main unit of this package is '''paszlib'''. there are other, auxiliary units, but the only unit that needs to be included in a typical program is this one. (View interface) <br />
<br />
==TZipper==<br />
<br />
===Using the latest TZipper===<br />
<br />
In FPC 2.3.1 there are many fixes which make TZipper much better. To be able to use them until the next FPC is released with those fixes one should follow the following steps:<br />
<br />
1 - Download zipper.pp, and only this file, from: http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/paszlib/src/<br />
<br />
2 - Rename the file to a unique name, to avoid conflict with the fpc unit, like myzipper.pp and also change the name inside the source file.<br />
<br />
3 - Add the file to your project and use the TZipper from there.<br />
<br />
===Examples===<br />
<br />
====Zip files====<br />
<br />
Create zip file named as parameter 1 from files entered as rest parameters.<br />
<br />
<delphi>uses<br />
Zipper;<br />
var<br />
Zipper: TZipper;<br />
begin<br />
try<br />
Zipper := TZipper.Create;<br />
Zipper.FileName := ParamStr(1);<br />
for I := 2 to ParamCount do<br />
Zipper.Entries.AddFileEntry(ParamStr(I), ParamStr(I));<br />
Zipper.ZipAllFiles;<br />
finally<br />
Zipper.Free;<br />
end;<br />
end.</delphi><br />
<br />
====Unzip files====<br />
<br />
Unzip all files contained in archive with name given by first parameter to directory entered as second parameter.<br />
<br />
<delphi>uses<br />
Zipper;<br />
var<br />
UnZipper: TUnZipper;<br />
begin<br />
try<br />
UnZipper := TUnZipper.Create;<br />
UnZipper.FileName := ParamStr(1);<br />
UnZipper.OutputPath := ParamStr(2);<br />
UnZipper.Examine;<br />
UnZipper.UnZipAllFiles;<br />
finally<br />
UnZipper.Free;<br />
end;<br />
end.</delphi><br />
<br />
More examples can be found in FPC source directory [http://svn.freepascal.org/svn/fpc/trunk/packages/paszlib/examples/]<br />
<br />
<br />
Go to back [[Package_List|Packages List]]</div>Antonioghttps://wiki.freepascal.org/index.php?title=Talk:Main_Page/pt&diff=25846Talk:Main Page/pt2007-12-26T19:37:47Z<p>Antoniog: /* LazarusBrasil.org */</p>
<hr />
<div>==LazarusBrasil.org==<br />
A LazarusBrasil.org fica [http://www.lazarusbrasil.org/index.php aqui].<br />
<br />
==Fórum de Lazarus em português==<br />
[http://br.groups.yahoo.com/group/lazarus-brasil/ Fórum (1)].<br />
<br />
[http://br.groups.yahoo.com/group/freepascal/ Fórum (2)].<br />
<br />
[http://lazaruspascal.codigolivre.org.br/portal.php Fórum (3)].<br />
<br />
==Hora no Brasil:==<br />
<br />
Brasília = UTC - 03:00<br />
<br />
O Horário de Verão começa no terceiro Domingo de Outubro às 02:00:00 e termina no segundo Domingo de Fevereiro às 02:00:00<br />
<br />
==O português é falado também nas seguintes localidades:==<br />
===África:===<br />
*Angola<br />
*Cabo-Verde<br />
*Guiné-Bissau<br />
*Moçambique<br />
*São-Tomé e Príncipe<br />
<br />
===Ásia===<br />
*Goa, Damão e Diu (oeste da Índia)<br />
*Macau (China)<br />
*Sri Lanka (localidades)<br />
<br />
====Pacífico:====<br />
*Java (Indonésia)<br />
*Málaca (Malásia)<br />
*Timor-Leste (Indonésia)</div>Antonioghttps://wiki.freepascal.org/index.php?title=TAChart/pt&diff=25525TAChart/pt2007-12-02T14:16:04Z<p>Antoniog: </p>
<hr />
<div>{{TAChart}}<br />
<br />
=== About ===<br />
O TAChart é um componente para representar gáficos parcialmente compatível com oTeeChart.<br />
Esta versão contem código desenvolvido por Philippe Martinole para o TeleAuto e bastantes modificações introduzidas por Luís Rodrigues durante a conversão da aplicação EPANET para o Lazarus.<br />
<br />
As caracteristicas principais são:<br />
* Gráficos de Queijo<br />
* Gráficos de Barras<br />
* Gráficos de Área<br />
* Gráficos de Linha (pode funcionar como Pontos)<br />
* Número Ilimitado de gráficos<br />
* Número ilimitado de pontos<br />
* Legenda<br />
* Título<br />
* Rodapé<br />
* Axis labels<br />
* Zoom Interactivo<br />
* Reticule or vertical reticule with point measure<br />
* Mirror on X axis<br />
* Auto or manual graph limits<br />
* Smart marks drawing<br />
* Vertical and horizontal line graph type<br />
* Facilmente extensível<br />
<br />
=== Captura de Ecrã ===<br />
<br />
Isto é um captura de ecrã da aplicação de teste a mostrar um gráfico de área, um de linha e um de pizza.<br />
<br />
<center>[[Image:Tachart.png]]</center><br />
<br />
=== Author ===<br />
[[User:LFRodrigues|Luís Rodrigues]] <br />
<br />
[[User:Marty|Philippe Martinole]] <br />
<br />
<br />
=== Download ===<br />
A versão estável mais recente faz parte do repositório SVN do Lazarus (O componente está na aba "Adicional")<br />
<br />
O código antigo desenvolvido pelo Philippe está aqui: [http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=177586 Lazarus CCR Files page].<br />
<br />
=== Modificações ===<br />
* 27/08/2007 - Correcções e Inverted Axis (por Helio Rocha-Pinto)<br />
* 12/03/2007 - Correcções e ShowInLegend<br />
* 01/01/2007 - Versão Inicial<br />
<br />
=== Utilização ===<br />
Veja o examplo incluído no código fonte do Lazarus em (Directório de Instalação)/components/tachart/demo/</div>Antonioghttps://wiki.freepascal.org/index.php?title=TAChart/pt&diff=25524TAChart/pt2007-12-02T14:14:59Z<p>Antoniog: /* About */</p>
<hr />
<div>{{TAChart}}<br />
<br />
=== About ===<br />
O TAChart é um componente para representar gáficos parcialmente compatível com oTeeChart.<br />
Esta versão contem código desenvolvido por Philippe Martinole para o TeleAuto e bastantes modificações introduzidas por Luís Rodrigues durante a conversão da aplicação EPANET para o Lazarus.<br />
<br />
As caracteristicas principais são:<br />
* Gráficos de Queijo<br />
* Gráficos de Barras<br />
* Gráficos de Área<br />
* Gráficos de Linha (pode funcionar como Pontos)<br />
* Número Ilimitado de gráficos<br />
* Número ilimitado de pontos<br />
* Legenda<br />
* Título<br />
* Rodapé<br />
* Axis labels<br />
* Zoom Interactivo<br />
* Reticule or vertical reticule with point measure<br />
* Mirror on X axis<br />
* Auto or manual graph limits<br />
* Smart marks drawing<br />
* Vertical and horizontal line graph type<br />
* Facilmente extensível<br />
<br />
=== Captura de Ecrã ===<br />
<br />
Isto é um captura de ecrã da aplicação de teste a mostrar um gráfico de área, um de linha e um de pizza.<br />
<br />
<center>[[Image:Tachart.png]]</center><br />
<br />
=== Author ===<br />
[[User:LFRodrigues|Luís Rodrigues]] <br />
<br />
[[User:Marty|Philippe Martinole]] <br />
<br />
<br />
=== Download ===<br />
A versão estável mais recente faz parte do repositório SVN do Lazarus (O component está na aba "Adicional")<br />
<br />
O código antigo desenvolvido pelo Philippe está aqui: [http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=177586 Lazarus CCR Files page].<br />
<br />
=== Modificaçõs ===<br />
* 27/08/2007 - Correcções e Inverted Axis (por Helio Rocha-Pinto)<br />
* 12/03/2007 - Correcções e ShowInLegend<br />
* 01/01/2007 - Versão Inicial<br />
<br />
=== Utilização ===<br />
Veja o examplo incluido no código fonte do Lazarus em (Directorio de Instalação)/components/tachart/demo/</div>Antonioghttps://wiki.freepascal.org/index.php?title=FPDoc_Editor/pt&diff=25270FPDoc Editor/pt2007-11-22T01:35:18Z<p>Antoniog: New page: {{LazDoc}} == Introdução == O LazDoc é um editor/visualizador integrado para Lazarus. Itens descritos aqui e que usam o LazDoc requer que você esteja familiarizado com o FPDoc. Para m...</p>
<hr />
<div>{{LazDoc}}<br />
<br />
== Introdução ==<br />
O LazDoc é um editor/visualizador integrado para Lazarus. Itens descritos aqui e que usam o LazDoc requer que você esteja familiarizado com o FPDoc. Para mais informações veja: [http://lazarus-ccr.sourceforge.net/fpcdoc/fpdoc/fpdoc.html Free Pascal manual da ferramenta de documentação ]<br />
<br />
== Onde achar o LazDoc? ==<br />
O LazDoc é integrado à IDE do Lazarus. Ele está no menu Exibir.<br />
<br />
== Uso ==<br />
Usar o LazDoc é muito simples.<br />
<br />
1. Set the search path for LazDoc in the Project | Project Options dialog, under the LazDoc tabpage.<br />
<br />
2. Open or select a file for which documentation exists. <br />
<br />
3. Open the LazDoc editor. You can find it under the menu View.<br />
<br />
4. Place and move the cursor. After placing the cursor on the source editor, you will notice that the caption of the LazDoc form changes. The caption shows the source element selected and the filename of the documentation file. By selecting the appropriate page in LazDoc you can edit a specific documentation tag. Of course it is also possible to use LazDoc only as a viewer.<br />
<br />
== Future plans ==<br />
The todo list currently contains the following items, in no particular order:<br />
<br />
* Make LazDoc create new elements in documentation<br />
* Make LazDoc create new documentation files<br />
* Add documentation tags "topic" to LazDoc<br />
* Add more source elements to be interpreted by LazDoc using exisiting codetools (now procedure/function/constructor/destructor are supported)<br />
* Add LazDoc to IDE settings (showing and position in IDE) <br />
* Use IPC for communication<br />
* Make LazDoc work on keydown in sourceeditor (broken)<br />
* Make LazDoc a WYSIWYG editor, comparable to a richtext editor. <br />
* Add a HTML viewer; LazDoc will generate the documentation automatically<br />
<br />
== DONE ==<br />
* Adding a small toolbar makes it possible to use the available makeup tags.<br />
* Add documentation tags "seealso" to LazDoc<br />
* Make it work for fpc sources (rtl files already exist)<br />
* Add settings to environment menu<br />
* Make it work on project files also<br />
* Propose to expand documentation tags with: "todo" and "notes" (no need for that, as there are alternatives)<br />
* Reduce overhead even further<br />
* Find inherited entries. For example TControl.Align of TButton.Align.<br />
* Optimization: inherited Entries are parsed on idle.<br />
* Optimization: xml files are cached, and only parsed once or if they changed on disk</div>Antonioghttps://wiki.freepascal.org/index.php?title=OnGuard/pt&diff=25034OnGuard/pt2007-11-06T16:15:02Z<p>Antoniog: New page: {{OnGuard}} === Sobre === FPOnGuard é portado do Turbo Power OnGuard. OnGuard é uma biblioteca para criar versões demo das suas aplicaçõe Borland Delphi & Kylix & Free Pascal+Lazaru...</p>
<hr />
<div>{{OnGuard}}<br />
<br />
=== Sobre ===<br />
FPOnGuard é portado do Turbo Power OnGuard.<br />
OnGuard é uma biblioteca para criar versões demo das suas aplicaçõe Borland Delphi &<br />
Kylix & Free Pascal+Lazarus. Crie versões demo que sejam limitadas em tempo,<br />
limitada em características, limitadas a um cert número de execuções ou a um certo número de execuções simultâneas em rede.<br />
<br />
Você pode também proteger executáveis de modificações ou de malware e hackers. Ele funciona para Windows e Linux. <br />
<br />
Esta é uma publicação somente-código. Inclui pacote para o instalador Lazarus 0.9.16 e deve executar bem em versões posteriores também.<br />
<br />
The download contains the component package for Lazarus + documentation (pdf and hlp file) and probably all original examples ported to Lazarus.<br />
<br />
This component is now designed for cross-platform applications (Windows and Linux-like).Pure Object Pascal. However some parts are heavy system dependant.<br />
<br />
=== TODO ===<br />
<br />
* Test network usage code (NAF file is not locked?)<br />
* Better machine ID (based on CPU and HDD physical serial numbers for example)<br />
* Merge it with HASP USB keys support and others (plugin system?)<br />
<br />
<br />
<br />
=== License ===<br />
[http://www.mozilla.org/MPL/MPL-1.1.html MPL 1.1]<br />
<br />
=== Download ===<br />
You can download it <br />
[http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=194373&release_id=425234 here].<br />
<br />
=== Change Log ===<br />
* Version 1.0 2006/06/16<br />
<br />
<br />
=== Dependencies / System Requirements ===<br />
* None<br />
<br />
Status: Beta<br />
<br />
Issues: <br />
Needs testing on Windows.<br />
Needs testing on Linux.<br />
Mostly working ;-)<br />
Probably not compatible with original OnGuard due to changes (removed asm code replaced with pascal not strictly the same)<br />
<br />
=== Installation ===<br />
* Create the directory lazarus\components\tponguard<br />
* Ungzip+untar files into the directory<br />
* Open lazarus<br />
* Open the package tponguard.lpk with Component/Open package file (.lpk)<br />
* (Click on Compile only if you don't want to install the component into the IDE)<br />
* Click on Install<br />
<br />
=== Usage ===<br />
Read the manual. It's very detailed and contains a lot of samples.</div>Antonioghttps://wiki.freepascal.org/index.php?title=IDE_Window:_Code_Explorer/pt&diff=24967IDE Window: Code Explorer/pt2007-10-29T21:47:42Z<p>Antoniog: </p>
<hr />
<div>{{Code Explorer}}<br />
<br />
O Explorador de Código mostra um arquivo Pascal como duas árvores. Existem duas páginas, '''Code''' and '''Directives'''. A página ''Code'' mostra a estrutura Pascal - types, variables, constants, classes, etc. A página ''Directives'' mostra a estrutura das diretivas do compilador - $IFDEFs, $DEFINEs, $INCLUDEs, etc.<br />
<br />
Double click on the nodes to jump to the corresponding position in the source.<br />
<br />
Hint: The code explorer is a floating window. That means you can leave it open and switch freely between other floating windows like the source editor or the object inspector.<br />
<br />
== Refresh ==<br />
<br />
Click on this button to update parse the current unit in the source editor and rebuild the tree in the code explorer.<br />
<br />
== Options ==<br />
<br />
Open the dialog to setup the options of the code explorer.<br />
<br />
== Filter (text field above treeview) ==<br />
<br />
For example 'to' will show all identifiers containing 'to'. Like 'Button', 'IntToStr'.</div>Antonioghttps://wiki.freepascal.org/index.php?title=IDE_Window:_Code_Explorer/pt&diff=24966IDE Window: Code Explorer/pt2007-10-29T21:46:32Z<p>Antoniog: New page: {{Code Explorer}} O code explorer mostra um arquio Pascal como duas árvores. Existem duas páginas, '''Code''' and '''Directives'''. A página ''Code'' mostra a estrutura Pascal - types,...</p>
<hr />
<div>{{Code Explorer}}<br />
<br />
O code explorer mostra um arquio Pascal como duas árvores. Existem duas páginas, '''Code''' and '''Directives'''. A página ''Code'' mostra a estrutura Pascal - types, variables, constants, classes, etc. A página ''Directives'' mostra a estrutura das diretivas do compilador - $IFDEFs, $DEFINEs, $INCLUDEs, etc.<br />
<br />
Double click on the nodes to jump to the corresponding position in the source.<br />
<br />
Hint: The code explorer is a floating window. That means you can leave it open and switch freely between other floating windows like the source editor or the object inspector.<br />
<br />
== Refresh ==<br />
<br />
Click on this button to update parse the current unit in the source editor and rebuild the tree in the code explorer.<br />
<br />
== Options ==<br />
<br />
Open the dialog to setup the options of the code explorer.<br />
<br />
== Filter (text field above treeview) ==<br />
<br />
For example 'to' will show all identifiers containing 'to'. Like 'Button', 'IntToStr'.</div>Antonioghttps://wiki.freepascal.org/index.php?title=Talk:Main_Page/pt&diff=24965Talk:Main Page/pt2007-10-29T16:46:46Z<p>Antoniog: /* Fórum de Lazarus em português */</p>
<hr />
<div>==LazarusBrasil.org==<br />
A LazarusBrasil.org fica [http://lazarusbrasil.org.googlepages.com/home aqui].<br />
<br />
==Fórum de Lazarus em português==<br />
[http://br.groups.yahoo.com/group/lazarus-brasil/ Fórum (1)].<br />
<br />
[http://br.groups.yahoo.com/group/freepascal/ Fórum (2)].<br />
<br />
[http://lazaruspascal.codigolivre.org.br/portal.php Fórum (3)].<br />
<br />
==Hora no Brasil:==<br />
<br />
Brasília = UTC - 03:00<br />
<br />
O Horário de Verão começa no terceiro Domingo de Outubro às 02:00:00 e termina no segundo Domingo de Fevereiro às 02:00:00<br />
<br />
==O português é falado também nas seguintes localidades:==<br />
===África:===<br />
*Angola<br />
*Cabo-Verde<br />
*Guiné-Bissau<br />
*Moçambique<br />
*São-Tomé e Príncipe<br />
<br />
===Ásia===<br />
*Goa, Damão e Diu (oeste da Índia)<br />
*Macau (China)<br />
*Sri Lanka (localidades)<br />
<br />
====Pacífico:====<br />
*Java (Indonésia)<br />
*Málaca (Malásia)<br />
*Timor-Leste (Indonésia)</div>Antonioghttps://wiki.freepascal.org/index.php?title=Talk:Main_Page/pt&diff=24964Talk:Main Page/pt2007-10-29T16:44:15Z<p>Antoniog: /* Fórum de Lazarus em português */</p>
<hr />
<div>==LazarusBrasil.org==<br />
A LazarusBrasil.org fica [http://lazarusbrasil.org.googlepages.com/home aqui].<br />
<br />
==Fórum de Lazarus em português==<br />
[http://br.groups.yahoo.com/group/lazarus-brasil/ Fórum (1)].<br />
<br />
[http://br.groups.yahoo.com/group/freepascal/ Fóum (2)].<br />
<br />
[http://lazaruspascal.codigolivre.org.br/portal.php Fórum (3)].<br />
<br />
==Hora no Brasil:==<br />
<br />
Brasília = UTC - 03:00<br />
<br />
O Horário de Verão começa no terceiro Domingo de Outubro às 02:00:00 e termina no segundo Domingo de Fevereiro às 02:00:00<br />
<br />
==O português é falado também nas seguintes localidades:==<br />
===África:===<br />
*Angola<br />
*Cabo-Verde<br />
*Guiné-Bissau<br />
*Moçambique<br />
*São-Tomé e Príncipe<br />
<br />
===Ásia===<br />
*Goa, Damão e Diu (oeste da Índia)<br />
*Macau (China)<br />
*Sri Lanka (localidades)<br />
<br />
====Pacífico:====<br />
*Java (Indonésia)<br />
*Málaca (Malásia)<br />
*Timor-Leste (Indonésia)</div>Antonioghttps://wiki.freepascal.org/index.php?title=PascalMagick/pt&diff=24815PascalMagick/pt2007-10-22T16:23:28Z<p>Antoniog: /* About */</p>
<hr />
<div>{{PascalMagick}}<br />
<br />
=== Sobre ===<br />
<br />
==== Sobre o ImageMagick ====<br />
<br />
<br />
[http://www.imagemagick.org ImageMagick] é uma suite aberta desenvolvida para criar, editar e compor imagens de bitmap. Ele tem suporte a uma grande variedade de formatos (mais de 90) inclusive GIF, JPEG, JPEG-2000, PNG, PDF, PhotoCD, TIFF e DPX. As imagens podem ser cortadas, as cores podem ser mudadas, vários efeitos podem ser aplicados, as imagens podem ser giradas ou combinadas e texto, linhas, polígonos, elipses e curvas Bézier podem ser adicionadas às imagens, esticadas ou giradas.<br />
<br />
The suite runs on all major operating systems and it can also be used from the command line and it´s command line tools package is one of Linux standard packages, being distributed with many distributions.<br />
<br />
Features and Capabilities:<br />
<br />
* Convert an image from one format to another (e.g. PNG to JPEG)<br />
* Resize, rotate, sharpen, color reduce, or add special effects to an image<br />
* Create a montage of image thumbnails<br />
* Create a transparent image suitable for use on the Web<br />
* Turn a group of images into a GIF animation sequence<br />
* Create a composite image by combining several separate image<br />
* Draw shapes or text on an image<br />
* Decorate an image with a border or frame<br />
* Describe the format and characteristics of an image<br />
<br />
==== ImageMagick Book ====<br />
<br />
[http://www.packtpub.com/imagemagick/book ImageMagick Tricks] This fast paced and practical tutorial is packed with examples of photo manipulations, logo creation, animations, and complete web projects. With this book up your sleeve, you'll be creating spellbinding images from code in no time.<br />
<br />
==== About MagickWand ====<br />
<br />
<br />
The [http://www.imagemagick.org/script/magick-wand.php MagickWand API] is the recommended interface by the ImageMagick team. It is an easy to use programming interface for using the suite. <br />
<br />
==== About MagickCore ====<br />
<br />
The MagickCore API is a low-level interface for ImageMagick.<br />
<br />
==== About PascalMagick ====<br />
<br />
This port is a translation of the c header files for both MagickWand and Magick Core.<br />
<br />
=== Screenshot ===<br />
<br />
<br />
=== Authors ===<br />
<br />
[[User:Sekelsenmat|Felipe Monteiro de Carvalho]]<br />
<br />
[[User:Arcnor|Ángel Eduardo García]]<br />
<br />
=== License ===<br />
<br />
BSD-style and compatible with the GPL.<br />
<br />
You can read the Licence [http://www.imagemagick.org/script/license.php here].<br />
<br />
=== Download ===<br />
<br />
PascalMagick 0.4 is available here: http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=174103&release_id=431432<br />
<br />
Status: Magick Wand headers are complete and working on both Windows and Linux.<br />
<br />
=== Installation ===<br />
<br />
The current version of PascalMagick works on Windows and Linux. Beta testers are necessary for the Mac OS X version.<br />
<br />
To start with, install ImageMagick binaries from the official website: http://www.imagemagick.org/script/binary-releases.php<br />
<br />
Now download and unzip PascalMagick package (Instructions on the Download section above).<br />
<br />
To check that everything is working, open the PascalMagick/wand/wanddemo.lpi project. Now go to the Project --> "Compiler Options dialog" and change the "Other Units" field to point to "../magick", so it can find the PascalMagick/magick/ImageMagick.pas file. After this you can compile and run the test program.<br />
<br />
If the program is working, it will load the image.png image located on the same directory as he is, resize it and then save it as a jpg called image.jpg.<br />
<br />
One Extra step is necessary on Linux: Rename the image.PNG to image.png due to case issues.<br />
<br />
=== Demonstration program 1 ===<br />
<br />
<pre><br />
{<br />
Demonstration program for the ImageMagick Library<br />
<br />
This program was converted from c by: Felipe Monteiro de Carvalho<br />
<br />
Usage: Just execute the program. It will resize the image.png image<br />
on it´s directory to fit (106, 80) and convert it to a jpg.<br />
<br />
Dez/2005<br />
}<br />
{Version 0.1}<br />
program wanddemo;<br />
<br />
{$mode objfpc}{$H+}<br />
<br />
uses SysUtils, magick_wand, ImageMagick;<br />
<br />
procedure ThrowWandException(wand: PMagickWand);<br />
var<br />
description: PChar;<br />
severity: ExceptionType;<br />
begin<br />
description := MagickGetException(wand, @severity);<br />
WriteLn(Format('An error ocurred. Description: %s', [description]));<br />
description := MagickRelinquishMemory(description);<br />
Abort;<br />
end;<br />
<br />
var<br />
status: MagickBooleanType;<br />
wand: PMagickWand;<br />
begin<br />
{ Read an image. }<br />
<br />
MagickWandGenesis;<br />
<br />
wand := NewMagickWand;<br />
<br />
try<br />
status := MagickReadImage(wand, 'image.png');<br />
if (status = MagickFalse) then ThrowWandException(wand);<br />
<br />
{ Turn the images into a thumbnail sequence. }<br />
<br />
MagickResetIterator(wand);<br />
<br />
while (MagickNextImage(wand) <> MagickFalse) do<br />
MagickResizeImage(wand, 106, 80, LanczosFilter, 1.0);<br />
<br />
{ Write the image as MIFF and destroy it. }<br />
<br />
status := MagickWriteImages(wand, 'image.jpg', MagickTrue);<br />
if (status = MagickFalse) then ThrowWandException(wand);<br />
<br />
finally<br />
wand := DestroyMagickWand(wand);<br />
<br />
MagickWandTerminus;<br />
end;<br />
end.<br />
</pre><br />
<br />
<br />
=== Subversion ===<br />
<br />
You can download the subversion version of this project using this command:<br />
<br />
svn checkout http://svn.freepascal.org/svn/fpc/trunk/packages/base/imagemagick imagemagick<br />
<br />
You can also download the full fpc 2.1.1 repository and it will be included.<br />
<br />
=== Bug Reporting/Feature Request ===<br />
<br />
Tests are necessary to verify if the bindings work with all versions of ImageMagick.<br />
<br />
You can post Bug Reports / Feature Requests here:<br />
<br />
----<br />
'''Bug 1'''<br />
<br />
There is an error in pixel_iterator.inc<br />
The correct declaration is<br />
function NewPixelIterator(wand: PMagickWand): PPixelIterator; cdecl; external WandExport;<br />
<br />
also the following declarations should be added<br />
function PixelGetNextIteratorRow(iterator: PPixeliterator; var wandCount : Cardinal) : PPPixelWand; cdecl; external WandExport;<br />
<br />
function PixelGetPreviousIteratorRow(iterator: PPixeliterator; var wandCount : Cardinal) : PPPixelWand; cdecl; external WandExport;<br />
<br />
Cheers,<br />
Todd.<br />
<br />
'''Status''': Fixed on 0.3<br />
<br />
----<br />
'''Bug 2'''<br />
<br />
There is a problem in "magick_wand.pas" and "ImageMagick.pas": the compiler option "{$PACKRECORDS C}" must be in the "{$ifdef FPC}[...]{$endif}". Otherwise the units do not compile with Delphi (Delphi 7 in my case).<br />
<br />
Best wishes, Marc Geldon ([http://www.proitsystems.de PRO IT SYSTEMS])<br />
<br />
----<br />
'''Bug 3'''<br />
<br />
your definition of "MagickGetImagePage" in magick_image.inc:<br />
<br />
<pre>function MagickGetImagePage(wand: PMagickWand; width, height: PCardinal; x, y: Integer): MagickBooleanType; cdecl; external WandExport;</pre><br />
<br />
correct definition (x and y are "PInteger"!):<br />
<br />
<pre>function MagickGetImagePage(wand: PMagickWand; width, height: PCardinal; x, y: PInteger): MagickBooleanType; cdecl; external WandExport;</pre><br />
<br />
Best wishes, Marc Geldon ([http://www.proitsystems.de PRO IT SYSTEMS])<br />
<br />
----<br />
'''Bug 4'''<br />
<br />
ImageMagick 6.2.7 (don't know exactly what version) introduced a few changes in MagickWand record and others. Also, a few variable definitions were incorrectly declared, and some function imports missed the "cdecl", so they didn't work (like NewMagickWand()). I've fixed all this issues. Can I upload the changes somewhere?<br />
<br />
Best regards, Arcnor<br />
<br />
: Hello, you can send it to me, and I´ll apply the changes. My e-mail is felipemonteiro.carvalho@gmail.com By the way, did you correct bugs 2 and 3 also? thanks a lot --[[User:Sekelsenmat|Sekelsenmat]] 05:07, 8 June 2006 (CEST)<br />
<br />
----<br />
'''Bug 5'''<br />
<br />
MagickNewImage parameters convention is cdecl.<br />
<br />
Correct definition of MagickNewImage in magick_image.inc:<br />
<br />
<pre>function MagickNewImage(wand: PMagickWand; const columns, rows: Cardinal;<br />
const background: PPixelWand): MagickBooleanType; cdecl; external WandExport;</pre><br />
<br />
----<br />
'''Bug 6'''<br />
<br />
MagickCompositeImage : Composite_wand is a PMagickWand constant.<br />
<br />
Correct definition of MagickCompositeImage in magick_image.inc:<br />
<br />
<pre>function MagickCompositeImage(wand: PMagickWand; const composite_wand: PMagickWand; <br />
const compose: CompositeOperator; const x, y: Integer): MagickBooleanType; cdecl; external WandExport;</pre><br />
<br />
<br />
--[[User:RuBBeR|RuBBeR]] 18:03, 3 July 2006 (CEST)<br />
<br />
<br />
'''Status: Bugs 2-6 fixed on v0.4. Thanks to all ([[User:Arcnor|Arcnor]])<br />
<br />
=== Change Log ===<br />
<br />
*12.07.06 PascalMagick version 0.4 released<br />
# Last bugs fixed<br />
*24.05.06 PascalMagick version 0.3 released<br />
# Minor fixes on the bindings<br />
*10.04.06 PascalMagick version 0.2 released<br />
# MagickWand API fully translated<br />
# Added a second demonstration program<br />
*27.12.05 PascalMagick version 0.1 released<br />
# About 80% of the MagickWand API is translated<br />
# The basic demonstration program is working well<br />
# Only the very minimum necessary MagickCode headers were translated<br />
*14.12.05 Began working on a pascal port for the c headers<br />
<br />
=== Help ===<br />
<br />
Please send help requests to the Lazarus Forum or the Lazarus mailling list.</div>Antonioghttps://wiki.freepascal.org/index.php?title=LCL_Key_Handling/pt&diff=24814LCL Key Handling/pt2007-10-21T20:32:22Z<p>Antoniog: /* Pressionando uma tecla (KeyDown) */</p>
<hr />
<div>{{LCL Key Handling}}<br />
<br />
== Pressionando uma tecla (KeyDown) ==<br />
<br />
Quando um widgetset recebe um evento Key Press ele precisa fazer o seguinte: antes de deixar o widget "nativo" manipular a tecla, enviar CN_KEYDOWN/CN_SYSKEYDOWN à LCL (CN_SYSKEYDOWN quando a tecla Alt está pressionada), que chama DoKeyDownBeforeInterface consistindo de:<br />
<br />
# chamar Application.NotifyKeyDownBeforeHandler (invokes before handlers)<br />
# get parent form, if it has keypreview, call it's DoKeyDownBeforeInterface<br />
# let the associated dragobject handle the key<br />
# call KeyDownBeforeInterface (if control does not have csNoStdEvents in ControlStyle):<br />
## call KeyDown:<br />
### call OnKeyDown handler if any<br />
<br />
When unhandled, that is, Message.Result = 0, it lets the widget handle the key, and if the widget has not done anything useful, then send a LM_KEYDOWN/LM_SYSKEYDOWN message to the LCL, which calls DoRemainingKeyDown consisting of:<br />
<br />
# if a popupmenu is assigned, check it for shortcuts (whether it is popped up or not)<br />
# get parent form, let it handle possible shortcut (TCustomForm.IsShortcut):<br />
## if form has OnShortcut event assigned, call it<br />
## if form has Menu assigned, check it for shortcuts:<br />
##* iterate through all menu items for this menu, check shortcuts, ".Click" the item<br />
##* set the menu's ShortcutHandled property to false in the menu item's OnClick handler, if you did not handle the shortcut and want to let the key processing continue<br />
## check the action lists for shortcuts, .Execute matching actions<br />
# let the application handle a shortcut (Application.IsShortcut):<br />
## if application has OnShortcut assigned, call it<br />
## if there is a modal form active, let it handle a shortcut (see above, TCustomForm.IsShortcut)<br />
## else if there is a focused form (Screen.ActiveCustomForm), let it handle a shortcut<br />
## else if there is a main form (Application.MainForm), let it handle a shortcut<br />
# if there is a Parent, iteratively call Parent.ChildKey to handle key message<br />
#* use it to handle key shortcuts in a certain "area", for example a panel<br />
#* TWinControl will call it's Parent's ChildKey; that's the "iteratively"<br />
# call ControlKeyDown, which in TWinControl, calls Application.ControlKeyDown:<br />
## handle tab navigation for controls<br />
#* if your custom control does something special with tab, override and inhibit, for example TCustomMemo<br />
# call KeyDownAfterInterface; TWinControl does nothing here<br />
# let Application call KeyDownAfter handlers<br />
<br />
Note that result (returning 1 or 0 in Message.Result) matters sometimes: windows for example will only send a WM_CHAR message for a key when a WM_KEYDOWN message that key has returned 0.<br />
<br />
== Key pressed, characters sent (KeyPress) ==<br />
<br />
The widgetset can either send CN_CHAR message, or call the IntfUtf8KeyPress method. CN_CHAR does not support UTF-8 characters, so that is why a IntfUtf8KeyPress exists. CN_CHAR handling consists of:<br />
<br />
# if widgetset (interface) does not send utf8 key presses, then call IntfUtf8KeyPress<br />
# call DoKeyPress:<br />
## get parent form, and if it has KeyPreview call it's DoKeyPress<br />
## call KeyPress (if control does not have csNoStdEvents in ControlStyle):<br />
### call OnKeyPress handler if any<br />
<br />
IntfUtf8KeyPress (DoUtf8KeyPress) handling consists of:<br />
<br />
# get parent form, and if it has KeyPreview call it's DoUtf8KeyPress<br />
# call Utf8KeyPress (if control does not have csNoStdEvents in ControlStyle):<br />
## call OnUtf8KeyPress handler if any<br />
<br />
When unhandled, that is, Message.Result = 0, it lets the widget handle the key, and if the widget has not done anything useful, then send a LM_CHAR/LM_SYSCHAR message to the LCL, which calls SendDialogChar consisting of:<br />
<br />
# get parent form and if found call it's .DialogChar:<br />
## TWinControl broadcasts DialogChar to all it's children<br />
##* use it to implement accelerator shortcuts for controls "near" (on the same form) as the focused control<br />
##* example: TCustomLabel uses it to Focus the assigned .FocusControl when alt+accelerator is pressed<br />
<br />
<br />
== Releasing the key (KeyUp) ==<br />
<br />
Releasing a key is very much, in the order of events happening, alike pressing a key, but some functions are missing. Again the widgetset will send a CN_KEYUP/CN_SYSKEYUP to the LCL before letting the widget handle the key, which will call DoKeyUpBeforeInterface consisting of:<br />
<br />
# get parent form, if it has keypreview, call it's DoKeyUpBeforeInterface<br />
# let the associated dragobject handle the key<br />
# call KeyUpBeforeInterface (if control does not have csNoStdEvents in ControlStyle):<br />
## call KeyUp:<br />
### call OnKeyUp handler if any<br />
<br />
When unhandled, that is, Message.Result = 0, it lets the widget handle the key, and if the widget has not done anything useful, then send a LM_KEYUP/LM_SYSKEYUP message to the LCL, which calls DoRemainingKeyUp consisting of:<br />
<br />
# call ControlKeyUp, which in TWinControl, calls Application.ControlKeyDown:<br />
## handle Enter and Escape keys for forms<br />
#* if your custom control does something special with enter and escape, override and inhibit<br />
# call KeyUpAfterInterface; TWinControl does nothing here<br />
<br />
== What should be sent via KeyPress ==<br />
While KeyDown and KeyUp messages should always be sent, determining when something should be sent via CN_(SYS)CHAR/LM_(SYS)CHAR and IntfUTF8KeyPress is not so obvious.<br />
<br />
The general rule is: ''if a key represents a character (something visual), that character must be sent''.<br />
<br />
However, what are the keys that represent a character?<br />
Since LCL should be Delphi compatible, and since Delphi is based on Microsoft Windows, KeyDown/Char/KeyUp messages should be sent according to the way that WM_KEYDOWN, WM_CHAR, WM_KEYUP messages are sent by Windows.<br />
<br />
This behaviour is sometimes a bit strange (e.g: TAB only generates WM_KEYDOWN/WM_KEYUP, while BACKSPACE generates WM_KEYDOWN/WM_CHAR/WM_KEYUP) but that's it.<br />
<br />
'''Note''': In KeyDown/KeyUp messages, the virtual key code must be passed (that is, a VK_ constant), while In xx_(SYS)CHAR messages the ascii character (or the UTF8 character for IntfUTF8KeyPress) must be sent.<br />
That is, for ESC key you put VK_ESCAPE key code in KeyDown/KeyUp messages, and $1B in xx_(SYS)CHAR messages and in IntfUTF8KeyPress.<br />
<br />
=== Keys that generate KeyDown/Char/KeyUp ===<br />
* 'Simple' letters (a..z)<br />
* Numbers<br />
* Esc<br />
* Backspace<br />
* Space<br />
* Return<br />
* Return on numeric keypad<br />
* Numeric keypad operators (Add, Subtract, Multiply, Divide)<br />
* Numbers on numeric keypad<br />
* Decimal separator on numeric keypad<br />
''(See later [[#Notes_on_numeric_keypad|Notes on numeric keypad]])''<br />
<br />
=== Keys that generate KeyDown/KeyUp only ===<br />
* Function keys (F1-F12)<br />
* Print Screen<br />
* Scroll Lock<br />
* Pause<br />
* Shift<br />
* Caps Lock<br />
* Tab<br />
* Control<br />
* Windows Logo Key <br />
* Alt and AltGr<br />
* Windows 'Application Key'<br />
* Insert<br />
* Delete<br />
* Home<br />
* End<br />
* Page Up<br />
* Page Down<br />
* Arrow Keys (Up, Down, Left, Right)<br />
* Num Lock<br />
<br />
=== Notes on numeric keypad ===<br />
Usually, numbers and decimal separator on numeric keypad can only be detected when Num Lock is on. Otherwise, they send keycodes as if user pressed arrow keys (or keys like Ins, Del, Home and so on).<br />
Return and operators aren't affected by Num Lock.<br />
<br />
Usually when Num Lock is off, pressing numbers on numeric keypad it's the same as pressing arrow keys (so 8 generates VK_UP, 7 generates VK_HOME and so on) and you can't determine if the user pressed the "real" arrow key or a key on the keypad. In general, you shouldn't care about it.</div>Antonioghttps://wiki.freepascal.org/index.php?title=LCL_Key_Handling/pt&diff=24813LCL Key Handling/pt2007-10-21T20:29:11Z<p>Antoniog: </p>
<hr />
<div>{{LCL Key Handling}}<br />
<br />
== Pressionando uma tecla (KeyDown) ==<br />
<br />
Quando um widgetset recebe um evento Key Press ele precisa fazer o seguinte: antes de deixar o widget "nativo" manipular a tecla, enviar CN_KEYDOWN/CN_SYSKEYDOWN à LCL (CN_SYSKEYDOWN when alt key is down), que chama DoKeyDownBeforeInterface consistindo de:<br />
<br />
# chamar Application.NotifyKeyDownBeforeHandler (invokes before handlers)<br />
# get parent form, if it has keypreview, call it's DoKeyDownBeforeInterface<br />
# let the associated dragobject handle the key<br />
# call KeyDownBeforeInterface (if control does not have csNoStdEvents in ControlStyle):<br />
## call KeyDown:<br />
### call OnKeyDown handler if any<br />
<br />
When unhandled, that is, Message.Result = 0, it lets the widget handle the key, and if the widget has not done anything useful, then send a LM_KEYDOWN/LM_SYSKEYDOWN message to the LCL, which calls DoRemainingKeyDown consisting of:<br />
<br />
# if a popupmenu is assigned, check it for shortcuts (whether it is popped up or not)<br />
# get parent form, let it handle possible shortcut (TCustomForm.IsShortcut):<br />
## if form has OnShortcut event assigned, call it<br />
## if form has Menu assigned, check it for shortcuts:<br />
##* iterate through all menu items for this menu, check shortcuts, ".Click" the item<br />
##* set the menu's ShortcutHandled property to false in the menu item's OnClick handler, if you did not handle the shortcut and want to let the key processing continue<br />
## check the action lists for shortcuts, .Execute matching actions<br />
# let the application handle a shortcut (Application.IsShortcut):<br />
## if application has OnShortcut assigned, call it<br />
## if there is a modal form active, let it handle a shortcut (see above, TCustomForm.IsShortcut)<br />
## else if there is a focused form (Screen.ActiveCustomForm), let it handle a shortcut<br />
## else if there is a main form (Application.MainForm), let it handle a shortcut<br />
# if there is a Parent, iteratively call Parent.ChildKey to handle key message<br />
#* use it to handle key shortcuts in a certain "area", for example a panel<br />
#* TWinControl will call it's Parent's ChildKey; that's the "iteratively"<br />
# call ControlKeyDown, which in TWinControl, calls Application.ControlKeyDown:<br />
## handle tab navigation for controls<br />
#* if your custom control does something special with tab, override and inhibit, for example TCustomMemo<br />
# call KeyDownAfterInterface; TWinControl does nothing here<br />
# let Application call KeyDownAfter handlers<br />
<br />
Note that result (returning 1 or 0 in Message.Result) matters sometimes: windows for example will only send a WM_CHAR message for a key when a WM_KEYDOWN message that key has returned 0.<br />
<br />
== Key pressed, characters sent (KeyPress) ==<br />
<br />
The widgetset can either send CN_CHAR message, or call the IntfUtf8KeyPress method. CN_CHAR does not support UTF-8 characters, so that is why a IntfUtf8KeyPress exists. CN_CHAR handling consists of:<br />
<br />
# if widgetset (interface) does not send utf8 key presses, then call IntfUtf8KeyPress<br />
# call DoKeyPress:<br />
## get parent form, and if it has KeyPreview call it's DoKeyPress<br />
## call KeyPress (if control does not have csNoStdEvents in ControlStyle):<br />
### call OnKeyPress handler if any<br />
<br />
IntfUtf8KeyPress (DoUtf8KeyPress) handling consists of:<br />
<br />
# get parent form, and if it has KeyPreview call it's DoUtf8KeyPress<br />
# call Utf8KeyPress (if control does not have csNoStdEvents in ControlStyle):<br />
## call OnUtf8KeyPress handler if any<br />
<br />
When unhandled, that is, Message.Result = 0, it lets the widget handle the key, and if the widget has not done anything useful, then send a LM_CHAR/LM_SYSCHAR message to the LCL, which calls SendDialogChar consisting of:<br />
<br />
# get parent form and if found call it's .DialogChar:<br />
## TWinControl broadcasts DialogChar to all it's children<br />
##* use it to implement accelerator shortcuts for controls "near" (on the same form) as the focused control<br />
##* example: TCustomLabel uses it to Focus the assigned .FocusControl when alt+accelerator is pressed<br />
<br />
<br />
== Releasing the key (KeyUp) ==<br />
<br />
Releasing a key is very much, in the order of events happening, alike pressing a key, but some functions are missing. Again the widgetset will send a CN_KEYUP/CN_SYSKEYUP to the LCL before letting the widget handle the key, which will call DoKeyUpBeforeInterface consisting of:<br />
<br />
# get parent form, if it has keypreview, call it's DoKeyUpBeforeInterface<br />
# let the associated dragobject handle the key<br />
# call KeyUpBeforeInterface (if control does not have csNoStdEvents in ControlStyle):<br />
## call KeyUp:<br />
### call OnKeyUp handler if any<br />
<br />
When unhandled, that is, Message.Result = 0, it lets the widget handle the key, and if the widget has not done anything useful, then send a LM_KEYUP/LM_SYSKEYUP message to the LCL, which calls DoRemainingKeyUp consisting of:<br />
<br />
# call ControlKeyUp, which in TWinControl, calls Application.ControlKeyDown:<br />
## handle Enter and Escape keys for forms<br />
#* if your custom control does something special with enter and escape, override and inhibit<br />
# call KeyUpAfterInterface; TWinControl does nothing here<br />
<br />
== What should be sent via KeyPress ==<br />
While KeyDown and KeyUp messages should always be sent, determining when something should be sent via CN_(SYS)CHAR/LM_(SYS)CHAR and IntfUTF8KeyPress is not so obvious.<br />
<br />
The general rule is: ''if a key represents a character (something visual), that character must be sent''.<br />
<br />
However, what are the keys that represent a character?<br />
Since LCL should be Delphi compatible, and since Delphi is based on Microsoft Windows, KeyDown/Char/KeyUp messages should be sent according to the way that WM_KEYDOWN, WM_CHAR, WM_KEYUP messages are sent by Windows.<br />
<br />
This behaviour is sometimes a bit strange (e.g: TAB only generates WM_KEYDOWN/WM_KEYUP, while BACKSPACE generates WM_KEYDOWN/WM_CHAR/WM_KEYUP) but that's it.<br />
<br />
'''Note''': In KeyDown/KeyUp messages, the virtual key code must be passed (that is, a VK_ constant), while In xx_(SYS)CHAR messages the ascii character (or the UTF8 character for IntfUTF8KeyPress) must be sent.<br />
That is, for ESC key you put VK_ESCAPE key code in KeyDown/KeyUp messages, and $1B in xx_(SYS)CHAR messages and in IntfUTF8KeyPress.<br />
<br />
=== Keys that generate KeyDown/Char/KeyUp ===<br />
* 'Simple' letters (a..z)<br />
* Numbers<br />
* Esc<br />
* Backspace<br />
* Space<br />
* Return<br />
* Return on numeric keypad<br />
* Numeric keypad operators (Add, Subtract, Multiply, Divide)<br />
* Numbers on numeric keypad<br />
* Decimal separator on numeric keypad<br />
''(See later [[#Notes_on_numeric_keypad|Notes on numeric keypad]])''<br />
<br />
=== Keys that generate KeyDown/KeyUp only ===<br />
* Function keys (F1-F12)<br />
* Print Screen<br />
* Scroll Lock<br />
* Pause<br />
* Shift<br />
* Caps Lock<br />
* Tab<br />
* Control<br />
* Windows Logo Key <br />
* Alt and AltGr<br />
* Windows 'Application Key'<br />
* Insert<br />
* Delete<br />
* Home<br />
* End<br />
* Page Up<br />
* Page Down<br />
* Arrow Keys (Up, Down, Left, Right)<br />
* Num Lock<br />
<br />
=== Notes on numeric keypad ===<br />
Usually, numbers and decimal separator on numeric keypad can only be detected when Num Lock is on. Otherwise, they send keycodes as if user pressed arrow keys (or keys like Ins, Del, Home and so on).<br />
Return and operators aren't affected by Num Lock.<br />
<br />
Usually when Num Lock is off, pressing numbers on numeric keypad it's the same as pressing arrow keys (so 8 generates VK_UP, 7 generates VK_HOME and so on) and you can't determine if the user pressed the "real" arrow key or a key on the keypad. In general, you shouldn't care about it.</div>Antonioghttps://wiki.freepascal.org/index.php?title=LCL_Key_Handling/pt&diff=24812LCL Key Handling/pt2007-10-21T20:23:52Z<p>Antoniog: Removing all content from page</p>
<hr />
<div></div>Antonioghttps://wiki.freepascal.org/index.php?title=LCL_Key_Handling/pt&diff=24811LCL Key Handling/pt2007-10-21T20:22:33Z<p>Antoniog: New page: <small> English (en) '''Français (fr)''' '''Japanese (ja)''' '''Portuguese (pb)''' </small></p>
<hr />
<div><small><br />
[[LCL Key Handling | English (en)]]<br />
[[LCL Key Handling/fr|'''Français (fr)''']]<br />
[[LCL Key Handling/ja|'''Japanese (ja)''']]<br />
[[LCL Key Handling/pt|'''Portuguese (pb)''']]<br />
</small></div>Antonioghttps://wiki.freepascal.org/index.php?title=How_to_setup_a_FPC_and_Lazarus_Ubuntu_repository/pt&diff=24766How to setup a FPC and Lazarus Ubuntu repository/pt2007-10-19T14:39:37Z<p>Antoniog: New page: {{How to setup a FPC and Lazarus Ubuntu repository}} == O que é um repositório? == Um repositório Ubuntu é um diretório. Ele pode ser guardado num disco local ou em um servidor Web ...</p>
<hr />
<div>{{How to setup a FPC and Lazarus Ubuntu repository}}<br />
<br />
== O que é um repositório? ==<br />
<br />
Um repositório Ubuntu é um diretório. Ele pode ser guardado num disco local ou em um servidor Web ou FTP.<br />
To use it, you add its path into your /etc/apt/sources.list and setup a pgp key. Then you can simply install lazarus with your favourite package gui (e.g. synaptic) and fpc, fpc-src and lazarus will be downloaded, installed and updated automatically.<br />
<br />
== Who needs it? ==<br />
<br />
Administrators who wants to install FPC+Lazarus on a pool of computers. Like in school. Or newbies who just want to quickly test it.<br />
<br />
== The directory structure ==<br />
<br />
Let's assume you want create a repository available via the apache webserver. Then you need to setup a directory like /var/www/lazarus that is public readable and only writable by root.<br />
<br />
Create a sub directory for each target you want to support:<br />
mkdir -p /var/www/lazarus/dists/lazarus-testing/universe/binary-i386<br />
mkdir -p /var/www/lazarus/dists/lazarus-testing/universe/binary-amd64<br />
<br />
== The debs ==<br />
<br />
Put the fpc, fpc-src and lazarus deb files into it.<br />
<br />
=== Creating the deb files yourself ===<br />
<br />
You can create the debs with the scripts in tools/install/ of the lazarus sources.<br />
<br />
==== Install development packages ====<br />
<br />
* install development packages:<br />
sudo apt-get install libgtk2.0-dev libgtk1.2-dev libgdk-pixbuf-dev libgpmg1-dev fakeroot libncurses5-dev<br />
* Install the latest stable FPC. This is needed to build the new FPC and Lazarus:<br />
Either the deb files from the official site or the tar.gz.<br />
* Download the FPC sources. To get the current development version you can use the command below. To get a more stable version, see [[Installing_Lazarus#FPC Sources]]:<br />
svn co http://svn.freepascal.org/svn/fpc/trunk fpc<br />
* Download the lazarus sources:<br />
svn co http://svn.freepascal.org/svn/lazarus/trunk lazarus<br />
<br />
==== Build new deb ====<br />
<br />
* go into the lazarus install script directory:<br />
cd lazarus/tools/install<br />
* build the fpc deb. The following script will build a single fpc deb using the date as version. As parameter you must specify the path of the FPC sources you downloaded above:<br />
sudo ./create_fpc_deb.sh fpc /path/to/the/sources/of/fpc/<br />
* install the new fpc deb. This is needed to build the lazarus deb, which depends on the new fpc deb. Don't forget to uninstall first your old FPC.<br />
sudo dpkg -i fpc_2.3.1-070726_i386.deb<br />
* build the fpc-src deb. This works pretty much the same as above:<br />
./create_fpc_deb.sh fpc-src /path/to/the/sources/of/fpc/<br />
* build the lazarus deb. You can either build a normal lazarus:<br />
./create_lazarus_deb.sh append-revision<br />
or a lazarus using gtk2:<br />
./create_lazarus_deb.sh gtk2 append-revision<br />
<br />
==== Replace the deb files in the repository ====<br />
<br />
* Now you have 3 deb files. Copy them to your repository:<br />
cp fpc_2.3.1-070726_i386.deb fpc-src_2.3.1-070726_i386.deb lazarus_0.9.23.11636-0_i386.deb \<br />
/var/www/lazarus/dists/lazarus-testing/universe/binary-i386/<br />
* Don't forget to remove the old ones.<br />
<br />
== PGP Key ==<br />
<br />
You need to sign the debs with a PGP key, so that the target systems can be sure, that no evil-doer replaced the files.<br />
<br />
=== Creating a PGP key ===<br />
<br />
You can use tools like seahorse or thunderbird to create the PGP key.<br />
<br />
* Install seahorse<br />
* start seahorse<br />
* Key > Create new key<br />
* A window popup up asking for the type. Choose ''PGP Key''.<br />
* Give a full name and an email adress and click ''Create''.<br />
* The passphrase is needed to encrypt the created files. This way no one can use the keys but you, even if they manage to steal your files. If you think, your files will never stolen or read by others you can leave them empty.<br />
* Creating the keys will take some minutes<br />
<br />
=== Upload the key to a public key server ===<br />
<br />
In order to share the key you can upload the key to a public key server.<br />
<br />
* start seahorse<br />
* Edit > Preferences > Key servers > Publish key to: choose a key server. For example: hkp://pgp.mit.edu:11371. Close the dialog.<br />
* Remote > Sync and publish key > Sync.<br />
<br />
=== Remember the key ID ===<br />
<br />
You need the key ID later. The key ID is shown in seahorse. But you can see it also via:<br />
gpg --list-keys<br />
<br />
== Updating repository files ==<br />
<br />
Put the following script into /var/www/lazarus, edit it for your needs and run it:<br />
<br />
<pre><br />
#!/usr/bin/env bash<br />
<br />
set -x<br />
<br />
GPGHome=/home/gaertner/.gnupg/<br />
MainDir=dists/lazarus-testing<br />
<br />
for Arch in i386 amd64; do<br />
Dir=$MainDir/universe/binary-$Arch<br />
<br />
# create index<br />
apt-ftparchive packages $Dir > $Dir/Packages<br />
cat $Dir/Packages | gzip -9c > $Dir/Packages.gz<br />
cat $Dir/Packages | bzip2 > $Dir/Packages.bz2<br />
done<br />
<br />
# create Release file<br />
rm -f $MainDir/Release*<br />
Date=`date`<br />
echo "Origin: Lazarus" >> $MainDir/Release<br />
echo "Label: Lazarus" >> $MainDir/Release<br />
echo "Suite: unstable" >> $MainDir/Release<br />
echo "Codename: lazarus-testing" >> $MainDir/Release<br />
echo "Version: 1.0" >> $MainDir/Release<br />
echo "Date: $Date" >> $MainDir/Release<br />
echo "Architectures: amd64 i386" >> $MainDir/Release<br />
echo "Components: universe" >> $MainDir/Release<br />
echo "Description: Lazarus testing 1.0" >> $MainDir/Release<br />
<br />
apt-ftparchive release $MainDir >> $MainDir/Release<br />
<br />
# sign Release file<br />
gpg --sign --homedir=$GPGHome -ba -o $MainDir/Release.gpg $MainDir/Release<br />
<br />
# end.<br />
</pre><br />
<br />
This will create index files ''Packages'', ''Packages.bz2'' and ''Packages.gz''. And it will create the ''Release'' file containing the checksums of the deb packages and sign it (''Release.gpg'').<br />
<br />
== Adding the repository to a client ==<br />
<br />
The following steps must be done on each computer, you want to use your repository.<br />
<br />
=== Add the key ===<br />
<br />
Download the key from the public key server:<br />
gpg --keyserver hkp://pgp.mit.edu:11371 --recv-keys 3A5B1204<br />
<br />
The 3A5B1204 should be replaced with your key id.<br />
Check the output, that you got the right key.<br />
<br />
Add it to the apt system:<br />
gpg --export 3A5B1204 | sudo apt-key add -<br />
<br />
You can see the list of apt keys with:<br />
sudo apt-key list<br />
<br />
=== Add the repository ===<br />
<br />
You can use synaptic for this or edit the /etc/apt/sources.list directly. Add the line:<br />
deb http://progprak.scale.uni-koeln.de/lazarus/ lazarus-testing universe<br />
<br />
Replace the http path with your own.<br />
<br />
== Install Lazarus ==<br />
<br />
For example:<br />
<br />
sudo apt-get update<br />
sudo apt-get install lazarus</div>Antonioghttps://wiki.freepascal.org/index.php?title=Talk:Windows_CE_Interface/pt&diff=24765Talk:Windows CE Interface/pt2007-10-19T14:32:50Z<p>Antoniog: </p>
<hr />
<div>I don't know how to make this page appear on languages bar.<br />
<br />
:You have to edit the template and add your language (I did it in this case). --[[User:Swen|Swen]] 23:46, 17 October 2007 (CEST)<br />
<br />
::Is there any way to do it myself? Thanks. [[user:antoniog|antonio]] 12:28 19 October 2007 (Brasilia ST = UTC - 02:00:00)</div>Antonioghttps://wiki.freepascal.org/index.php?title=Talk:Windows_CE_Interface/pt&diff=24685Talk:Windows CE Interface/pt2007-10-17T18:32:19Z<p>Antoniog: New page: I don't know how to make this page appear on languages bar.</p>
<hr />
<div>I don't know how to make this page appear on languages bar.</div>Antonioghttps://wiki.freepascal.org/index.php?title=Windows_CE_Interface/pt&diff=24623Windows CE Interface/pt2007-10-13T14:29:59Z<p>Antoniog: /* Configurando a interface do Windows CE */</p>
<hr />
<div>{{Windows CE Interface}}<br />
<br />
== Configurando a interface do Windows CE ==<br />
<br />
Para configurar a interface Windows CE você vai precisar usar ou o instalador add-on ou configurar a interface manualmente. As duas opções são detalhadas a seguir. Usar o instalador add-on é evidentemente muito mais fácil.<br />
<br />
=== Usando o instalador add-on ===<br />
<br />
Guia passo-a-passo:<br />
<br />
* Instale o Lazarus no Windows normalmente.<br />
<br />
* Baixe e instalee o instalador add-on para o Lazarus no Windows de [http://sourceforge.net/project/showfiles.php?group_id=89339&package_id=93599 Lazarus Testing] no sourceforge.<br />
* Você pode compilar aplicações Win32 Arm-WinCE de dentro do Lazarus modificando nas opções do compilador :<br />
** Widget set<br />
** SO Alvo<br />
** CPU Alvo<br />
<br />
Nota: certifique-se de que ambos os instaladores têm a mesma versão do FPC.<br />
<br />
=== Configurando a interface Windows CE manualmente ===<br />
<br />
O compilador e a biblioteca Run-Time para Windows CE estão disponíveis somente na divisão de desenvolvimento do FreePascal, a versão 2.1.x. Os snapshots do Lazarus vêm com esta versão do FreePascal.<br />
<br />
'''Passo 1''' - Para começar você vai precisar recompilar o compilador no Windows para criar um cross-compilador Windows CE - ARM. Há instruções aqui: [[fpc:WinCE_port|WinCE_port]].<br />
<br />
'''Passo 2''' - Você também precisa compilar a FCL (Free Component Library) com o compilador recém-criado. Instruções [[fpc:WinCE_port#Building_FPC_libraries|aqui]].<br />
<br />
'''Passo 3''' - Ponha o arquivo batch abaixo na raiz do seu diretório de subversão do Lazarus e execute-o.<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
make lcl LCL_PLATFORM=wince PP=ppcrossarm.exe CPU_TARGET=arm OS_TARGET=wince<br />
</pre><br />
<br />
Isto deve compilar a LCL para Windows CE.<br />
<br />
'''Passo 4''' - Cross-compile o LazarusPackageIntf de modo que possa usar componentes visuais de terceiros. Vá a lazarus\packager\registration e faça:<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
make PP=ppcrossarm.exe CPU_TARGET=arm OS_TARGET=wince<br />
</pre><br />
<br />
NOTA: you need to specify $(LazarusDir)\packager\units\$(TargetCPU)-$(TargetOS)\ into your project's unit path (adding FCL as requirement should do that).<br />
<br />
'''Step 5''' - Now you can use Lazarus IDE to design,compile and debug your applications.<br />
<br />
* You can also use scripts similar to this for compiling your applications:<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
ppcrossarm.exe -Twince -FuC:\Programas\fpc\rtl\units\arm-wince -FDC:\Programas\arm -XParm-wince- test.pas<br />
ppcrossarm.exe -Twince -FuC:\programas\lazarus\lcl\units\arm-wince -FuC:\programas\lazarus\lcl\units\arm-wince\wince -FuC:\Programas\fpc\rtl\units\arm-wince -FDC:\Programas\arm -XParm-wince- windowtest.pas<br />
</pre><br />
<br />
=== Compiling Windows CE project files with Lazarus IDE ===<br />
<br />
NOTE: recently a "wincemenures.or" file is reported missing on linking. You just need to copy this file from "lazarus/lcl/interfaces/wince" to "lazarus/lcl/units/arm-wince" and everything will be fine.<br />
<br />
Everything is just as you do with other interfaces and OSes.<br />
Make sure you have selected wince as widgetset in in '''Compiler Options->Paths''' and in '''Code''' tab page select '''WinCE''' as target os and '''arm''' as Target CPU.<br />
You also need to change '''compiler path''' in '''Environment options''' to point to your ppcrossarm.exe compiler.<br />
<br />
Now IDE is ready to compiler your files.<br />
<br />
=== Debugging Windows CE software on the Lazarus IDE ===<br />
<br />
You can also debug applications created within Lazarus IDE.<br />
<br />
'''Step 1''' - In Lazarus IDE go to the menu '''Environment->Debugger Options'''. Change the debugger path to the directory with gdb for wince.you can get it from here ftp://ftp.freepascal.org/pub/fpc/contrib/cross/gdb-6.4-win32-arm-wince.zip<br />
<br />
<br />
'''Step 2''' - If you are using Microsoft Device Emulator Preview, launch(or restore)it.Make sure you've started emulator with 128mg of ram.Select a path for shared folders in emulator, add copy command to your .bat file used for building your application to copy the compiled exe file to your shared path.(as you can see in my .bat file).Here is a .bat file you can use to launch emulator with 128 of ram.<br />
<br />
<pre><br />
start deviceemulator.exe ".\ppc_2003_se\PPC_2003_SE_WWE_ARMv4.bin" /memsize 128 /skin <br />
".\ppc_2003_se\PocketPC_2003_Skin.xml"<br />
</pre><br />
<br />
After that just do 'save and exit' whenever you want to quit emulator,and launch it again from shortcuts created in your start menu.(the shortcuts with '(restore)').<br />
<br />
'''Step 3''' - Run Device Emulator Manager and in available emulators right click on the name of emulator and do cradle.Now Microsoft ActiveSync will be launched.If not in Micrososft ActiveSync Go to the menu '''File->Get connected'''.If still ActiveSync doesn't recognize the emulator.Uncradle and Cradle the emulator again.<br />
<br />
'''Step 4''' - Copy that file with File Explorer program in your emulator to \gdb directory.If it is your first time running emulator you have to create a gdb directory in 'My Pocket PC' folder which is your root(\) folder.(To make things even faster for your each build,with file explorer go to your shared folder,press ctrl+c in your exe file,go to \gdb folder and each time before you try to debug your application just press ctrl+v)<br />
<br />
'''Step 5''' - Now you can safely debug your application.gdb for wince will be launched.it will copy arm-wince-pe-stub.exe to \gdb folder and check if your application.exe file is there and will launch the program.<br />
If you encountered an error make sure the \gdb folder is created,arm-wince-pe-stub.exe and you exe file is there.Also most of the times because of big size of exe file you can not copy that into your \gdb file.So you have to call Microsoft Device Emulator Preview with 128mg of ram instead of default 64mg ram.<br />
<br />
'''Some Hints'''<br />
<br />
1. Programs remain in memory still after exiting from them. So you can't overwrite the .exe file. You have to use tools like Process Viewer from Microsoft which remotely shows all processes and allow you to kill them. Or use process killers inside the emulator. Process Explorer is another good option. One can get it from http://madebits.com<br />
<br />
2. Each time you are done with debugging your program don't exit from program.Do program Reset and then Debugger reset. Note that sometimes still program remain in memory,so you also have to kill the process too.<br />
<br />
=== Installing and Using the Pocked PC Emulator ===<br />
<br />
1 - You can download a Pocket PC Emulator from Microsoft [http://www.microsoft.com/downloads/details.aspx?FamilyId=C62D54A5-183A-4A1E-A7E2-CC500ED1F19A&displaylang=en here]. First, download and install the file V1Emulator.zip.<br />
<br />
2 - Next, be careful that there is a wrong information on the website. It will say that you need to install the Virtual Machine Network Driver, but the link provided on the website is broken. Instead, download Virtual PC 2007 [http://www.microsoft.com/downloads/details.aspx?FamilyID=04d26402-3199-48a3-afa2-2dc0b40a73b6&DisplayLang=en here]. This will install the necessary driver too.<br />
<br />
3 - Now, go back to the first website and download and install the efp.msi file<br />
<br />
Now you should have a fully functional PocketPC Emulator which can be utilized together with Lazarus to develop applications.<br />
<br />
To run a Lazarus application on the emulator you can either use GDB via ActiveSync, or you can also just execute it directly.<br />
<br />
==== Running an application on the emulator ====<br />
<br />
1 - Go the the Windows Programs Menu --> "Windows Mobile Emulator Images" --> "PocketPC"<br />
<br />
2 - If you never configured your shared folder for the emulator, do so now, by clicking on the menu File --> Configure once the emulator opens. Set it to a folder where you can access your Windows CE executable created with Lazarus.<br />
<br />
3 - On the emulator click: Start --> Programs. Now select "File Explorer". Now select "Storage Card". Navigate until you find your executable and double click it to execute it.<br />
<br />
== Screenshots ==<br />
<br />
An example of Lazarus+WinCE and the Free Pascal software used to test the cross compiler:<br />
<br />
[[Image:Capture 2.jpg]]<br />
[[Image:Wince.PNG]]<br />
<br />
== How to add a new control ==<br />
<br />
For example TButton.<br />
<br />
TButton is defined in lcl/buttons.pp. This is the platform independent part of the LCL, which is used by the normal LCL programmer.<br />
<br />
Its widgetset class is in lcl/widgetset/wsbuttons.pp. This is the platform independent base for all widgetsets (qt, carbon, gtk, win32, ...).<br />
<br />
It's wince interface class is in lcl/interfaces/wince/wincewsbuttons.pp:<br />
<br />
TWinCEWSButton = class(TWSButton)<br />
private<br />
protected<br />
public<br />
class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;<br />
end;<br />
<br />
Every WS class, that actually implements something must be registered. See the initialization section at the end of the wincewsXXX.pp unit:<br />
RegisterWSComponent(TButton, TWinCEWSButton);<br />
<br />
<br />
Also notice that DestroyHandle should be implemented to clean up memory utilized by the control.<br />
<br />
== See Also ==<br />
<br />
* [[Windows_CE_Development_Notes|Windows CE Interface Development notes]]<br />
<br />
* [[User:CCRDude|Alternative Lazarus Windows CE tutorial using Win64]]<br />
<br />
* [[Roadmap#Widgetset_dependent_components|Roadmap for the Windows CE interface]]<br />
<br />
* Mini framework for WindowsCE applications: [http://ccrdude.net/files/fpc/pkMiniGUI.pas pkMiniGUI.pas] [http://ccrdude.net/docs/pkCEStuff.htm Documentation]<br />
<br />
== Downloads ==<br />
<br />
* An add-on installer for the Lazarus windows installer based on fpc 2.1.1: ftp://ftp.hu.freepascal.org/pub/lazarus/cross/. These files are mirrored at http://michael-ep3.physik.uni-halle.de/Lazarus/cross/ Details can be found at http://www.mail-archive.com/lazarus@miraclec.com/msg12909.html Thanks to Vincent Snijders.</div>Antonioghttps://wiki.freepascal.org/index.php?title=Windows_CE_Interface/pt&diff=24621Windows CE Interface/pt2007-10-13T04:09:31Z<p>Antoniog: /* Setting Up the Windows CE interface */</p>
<hr />
<div>{{Windows CE Interface}}<br />
<br />
== Configurando a interface do Windows CE ==<br />
<br />
To set up the Windows CE interface you will need to either use the add-on installer or set up the interface manually. Both options are detailed below. Using the add-on installer is, of course, much easier.<br />
<br />
=== Using the add-on installer ===<br />
<br />
Step-by-step guide:<br />
<br />
* Install Lazarus on Windows normally.<br />
<br />
* Download and install the add-on installer for the Lazarus windows from [http://sourceforge.net/project/showfiles.php?group_id=89339&package_id=93599 Lazarus Testing] at sourceforge.<br />
* You can compile win32 application and arm-wince application from within Lazarus by changing in the compiler options:<br />
** Widget set<br />
** Target OS<br />
** Target CPU<br />
<br />
Note: make sure that both installers have the same fpc version.<br />
<br />
=== Setting up the Windows CE interface manually ===<br />
<br />
The Compiler and Run-time library for Windows CE are only available on the development branch of Free Pascal, the 2.1.x version. Lazarus snapshot comes with this Free Pascal version.<br />
<br />
<br />
'''Step 1''' - To start with you will need to recompile the compiler on Windows to create a Windows CE - ARM Crosscompiler. There are instructions here: [[fpc:WinCE_port|WinCE_port]].<br />
<br />
'''Step 2''' - You also need to compile FCL (Free Component Library) with the newly built compile. Instructions [[fpc:WinCE_port#Building_FPC_libraries|here]].<br />
<br />
'''Step 3''' - Put the batch file bellow on the root of your subversion Lazarus directory and run it<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
make lcl LCL_PLATFORM=wince PP=ppcrossarm.exe CPU_TARGET=arm OS_TARGET=wince<br />
</pre><br />
<br />
This should compile LCL for Windows CE.<br />
<br />
'''Step 4''' - Cross-compile the LazarusPackageIntf so you can use 3rd party visual components. Go to lazarus\packager\registration and do:<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
make PP=ppcrossarm.exe CPU_TARGET=arm OS_TARGET=wince<br />
</pre><br />
<br />
NOTE: you need to specify $(LazarusDir)\packager\units\$(TargetCPU)-$(TargetOS)\ into your project's unit path (adding FCL as requirement should do that).<br />
<br />
'''Step 5''' - Now you can use Lazarus IDE to design,compile and debug your applications.<br />
<br />
* You can also use scripts similar to this for compiling your applications:<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
ppcrossarm.exe -Twince -FuC:\Programas\fpc\rtl\units\arm-wince -FDC:\Programas\arm -XParm-wince- test.pas<br />
ppcrossarm.exe -Twince -FuC:\programas\lazarus\lcl\units\arm-wince -FuC:\programas\lazarus\lcl\units\arm-wince\wince -FuC:\Programas\fpc\rtl\units\arm-wince -FDC:\Programas\arm -XParm-wince- windowtest.pas<br />
</pre><br />
<br />
=== Compiling Windows CE project files with Lazarus IDE ===<br />
<br />
NOTE: recently a "wincemenures.or" file is reported missing on linking. You just need to copy this file from "lazarus/lcl/interfaces/wince" to "lazarus/lcl/units/arm-wince" and everything will be fine.<br />
<br />
Everything is just as you do with other interfaces and OSes.<br />
Make sure you have selected wince as widgetset in in '''Compiler Options->Paths''' and in '''Code''' tab page select '''WinCE''' as target os and '''arm''' as Target CPU.<br />
You also need to change '''compiler path''' in '''Environment options''' to point to your ppcrossarm.exe compiler.<br />
<br />
Now IDE is ready to compiler your files.<br />
<br />
=== Debugging Windows CE software on the Lazarus IDE ===<br />
<br />
You can also debug applications created within Lazarus IDE.<br />
<br />
'''Step 1''' - In Lazarus IDE go to the menu '''Environment->Debugger Options'''. Change the debugger path to the directory with gdb for wince.you can get it from here ftp://ftp.freepascal.org/pub/fpc/contrib/cross/gdb-6.4-win32-arm-wince.zip<br />
<br />
<br />
'''Step 2''' - If you are using Microsoft Device Emulator Preview, launch(or restore)it.Make sure you've started emulator with 128mg of ram.Select a path for shared folders in emulator, add copy command to your .bat file used for building your application to copy the compiled exe file to your shared path.(as you can see in my .bat file).Here is a .bat file you can use to launch emulator with 128 of ram.<br />
<br />
<pre><br />
start deviceemulator.exe ".\ppc_2003_se\PPC_2003_SE_WWE_ARMv4.bin" /memsize 128 /skin <br />
".\ppc_2003_se\PocketPC_2003_Skin.xml"<br />
</pre><br />
<br />
After that just do 'save and exit' whenever you want to quit emulator,and launch it again from shortcuts created in your start menu.(the shortcuts with '(restore)').<br />
<br />
'''Step 3''' - Run Device Emulator Manager and in available emulators right click on the name of emulator and do cradle.Now Microsoft ActiveSync will be launched.If not in Micrososft ActiveSync Go to the menu '''File->Get connected'''.If still ActiveSync doesn't recognize the emulator.Uncradle and Cradle the emulator again.<br />
<br />
'''Step 4''' - Copy that file with File Explorer program in your emulator to \gdb directory.If it is your first time running emulator you have to create a gdb directory in 'My Pocket PC' folder which is your root(\) folder.(To make things even faster for your each build,with file explorer go to your shared folder,press ctrl+c in your exe file,go to \gdb folder and each time before you try to debug your application just press ctrl+v)<br />
<br />
'''Step 5''' - Now you can safely debug your application.gdb for wince will be launched.it will copy arm-wince-pe-stub.exe to \gdb folder and check if your application.exe file is there and will launch the program.<br />
If you encountered an error make sure the \gdb folder is created,arm-wince-pe-stub.exe and you exe file is there.Also most of the times because of big size of exe file you can not copy that into your \gdb file.So you have to call Microsoft Device Emulator Preview with 128mg of ram instead of default 64mg ram.<br />
<br />
'''Some Hints'''<br />
<br />
1. Programs remain in memory still after exiting from them. So you can't overwrite the .exe file. You have to use tools like Process Viewer from Microsoft which remotely shows all processes and allow you to kill them. Or use process killers inside the emulator. Process Explorer is another good option. One can get it from http://madebits.com<br />
<br />
2. Each time you are done with debugging your program don't exit from program.Do program Reset and then Debugger reset. Note that sometimes still program remain in memory,so you also have to kill the process too.<br />
<br />
=== Installing and Using the Pocked PC Emulator ===<br />
<br />
1 - You can download a Pocket PC Emulator from Microsoft [http://www.microsoft.com/downloads/details.aspx?FamilyId=C62D54A5-183A-4A1E-A7E2-CC500ED1F19A&displaylang=en here]. First, download and install the file V1Emulator.zip.<br />
<br />
2 - Next, be careful that there is a wrong information on the website. It will say that you need to install the Virtual Machine Network Driver, but the link provided on the website is broken. Instead, download Virtual PC 2007 [http://www.microsoft.com/downloads/details.aspx?FamilyID=04d26402-3199-48a3-afa2-2dc0b40a73b6&DisplayLang=en here]. This will install the necessary driver too.<br />
<br />
3 - Now, go back to the first website and download and install the efp.msi file<br />
<br />
Now you should have a fully functional PocketPC Emulator which can be utilized together with Lazarus to develop applications.<br />
<br />
To run a Lazarus application on the emulator you can either use GDB via ActiveSync, or you can also just execute it directly.<br />
<br />
==== Running an application on the emulator ====<br />
<br />
1 - Go the the Windows Programs Menu --> "Windows Mobile Emulator Images" --> "PocketPC"<br />
<br />
2 - If you never configured your shared folder for the emulator, do so now, by clicking on the menu File --> Configure once the emulator opens. Set it to a folder where you can access your Windows CE executable created with Lazarus.<br />
<br />
3 - On the emulator click: Start --> Programs. Now select "File Explorer". Now select "Storage Card". Navigate until you find your executable and double click it to execute it.<br />
<br />
== Screenshots ==<br />
<br />
An example of Lazarus+WinCE and the Free Pascal software used to test the cross compiler:<br />
<br />
[[Image:Capture 2.jpg]]<br />
[[Image:Wince.PNG]]<br />
<br />
== How to add a new control ==<br />
<br />
For example TButton.<br />
<br />
TButton is defined in lcl/buttons.pp. This is the platform independent part of the LCL, which is used by the normal LCL programmer.<br />
<br />
Its widgetset class is in lcl/widgetset/wsbuttons.pp. This is the platform independent base for all widgetsets (qt, carbon, gtk, win32, ...).<br />
<br />
It's wince interface class is in lcl/interfaces/wince/wincewsbuttons.pp:<br />
<br />
TWinCEWSButton = class(TWSButton)<br />
private<br />
protected<br />
public<br />
class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;<br />
end;<br />
<br />
Every WS class, that actually implements something must be registered. See the initialization section at the end of the wincewsXXX.pp unit:<br />
RegisterWSComponent(TButton, TWinCEWSButton);<br />
<br />
<br />
Also notice that DestroyHandle should be implemented to clean up memory utilized by the control.<br />
<br />
== See Also ==<br />
<br />
* [[Windows_CE_Development_Notes|Windows CE Interface Development notes]]<br />
<br />
* [[User:CCRDude|Alternative Lazarus Windows CE tutorial using Win64]]<br />
<br />
* [[Roadmap#Widgetset_dependent_components|Roadmap for the Windows CE interface]]<br />
<br />
* Mini framework for WindowsCE applications: [http://ccrdude.net/files/fpc/pkMiniGUI.pas pkMiniGUI.pas] [http://ccrdude.net/docs/pkCEStuff.htm Documentation]<br />
<br />
== Downloads ==<br />
<br />
* An add-on installer for the Lazarus windows installer based on fpc 2.1.1: ftp://ftp.hu.freepascal.org/pub/lazarus/cross/. These files are mirrored at http://michael-ep3.physik.uni-halle.de/Lazarus/cross/ Details can be found at http://www.mail-archive.com/lazarus@miraclec.com/msg12909.html Thanks to Vincent Snijders.</div>Antonioghttps://wiki.freepascal.org/index.php?title=Windows_CE_Interface/pt&diff=24620Windows CE Interface/pt2007-10-13T04:08:26Z<p>Antoniog: New page: {{Windows CE Interface}} == Setting Up the Windows CE interface == To set up the Windows CE interface you will need to either use the add-on installer or set up the interface manually. B...</p>
<hr />
<div>{{Windows CE Interface}}<br />
<br />
== Setting Up the Windows CE interface ==<br />
<br />
To set up the Windows CE interface you will need to either use the add-on installer or set up the interface manually. Both options are detailed below. Using the add-on installer is, of course, much easier.<br />
<br />
=== Using the add-on installer ===<br />
<br />
Step-by-step guide:<br />
<br />
* Install Lazarus on Windows normally.<br />
<br />
* Download and install the add-on installer for the Lazarus windows from [http://sourceforge.net/project/showfiles.php?group_id=89339&package_id=93599 Lazarus Testing] at sourceforge.<br />
* You can compile win32 application and arm-wince application from within Lazarus by changing in the compiler options:<br />
** Widget set<br />
** Target OS<br />
** Target CPU<br />
<br />
Note: make sure that both installers have the same fpc version.<br />
<br />
=== Setting up the Windows CE interface manually ===<br />
<br />
The Compiler and Run-time library for Windows CE are only available on the development branch of Free Pascal, the 2.1.x version. Lazarus snapshot comes with this Free Pascal version.<br />
<br />
<br />
'''Step 1''' - To start with you will need to recompile the compiler on Windows to create a Windows CE - ARM Crosscompiler. There are instructions here: [[fpc:WinCE_port|WinCE_port]].<br />
<br />
'''Step 2''' - You also need to compile FCL (Free Component Library) with the newly built compile. Instructions [[fpc:WinCE_port#Building_FPC_libraries|here]].<br />
<br />
'''Step 3''' - Put the batch file bellow on the root of your subversion Lazarus directory and run it<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
make lcl LCL_PLATFORM=wince PP=ppcrossarm.exe CPU_TARGET=arm OS_TARGET=wince<br />
</pre><br />
<br />
This should compile LCL for Windows CE.<br />
<br />
'''Step 4''' - Cross-compile the LazarusPackageIntf so you can use 3rd party visual components. Go to lazarus\packager\registration and do:<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
make PP=ppcrossarm.exe CPU_TARGET=arm OS_TARGET=wince<br />
</pre><br />
<br />
NOTE: you need to specify $(LazarusDir)\packager\units\$(TargetCPU)-$(TargetOS)\ into your project's unit path (adding FCL as requirement should do that).<br />
<br />
'''Step 5''' - Now you can use Lazarus IDE to design,compile and debug your applications.<br />
<br />
* You can also use scripts similar to this for compiling your applications:<br />
<br />
<pre><br />
PATH=C:\Programas\lazarus\pp\bin\i386-win32;c:\Programas\arm<br />
ppcrossarm.exe -Twince -FuC:\Programas\fpc\rtl\units\arm-wince -FDC:\Programas\arm -XParm-wince- test.pas<br />
ppcrossarm.exe -Twince -FuC:\programas\lazarus\lcl\units\arm-wince -FuC:\programas\lazarus\lcl\units\arm-wince\wince -FuC:\Programas\fpc\rtl\units\arm-wince -FDC:\Programas\arm -XParm-wince- windowtest.pas<br />
</pre><br />
<br />
=== Compiling Windows CE project files with Lazarus IDE ===<br />
<br />
NOTE: recently a "wincemenures.or" file is reported missing on linking. You just need to copy this file from "lazarus/lcl/interfaces/wince" to "lazarus/lcl/units/arm-wince" and everything will be fine.<br />
<br />
Everything is just as you do with other interfaces and OSes.<br />
Make sure you have selected wince as widgetset in in '''Compiler Options->Paths''' and in '''Code''' tab page select '''WinCE''' as target os and '''arm''' as Target CPU.<br />
You also need to change '''compiler path''' in '''Environment options''' to point to your ppcrossarm.exe compiler.<br />
<br />
Now IDE is ready to compiler your files.<br />
<br />
=== Debugging Windows CE software on the Lazarus IDE ===<br />
<br />
You can also debug applications created within Lazarus IDE.<br />
<br />
'''Step 1''' - In Lazarus IDE go to the menu '''Environment->Debugger Options'''. Change the debugger path to the directory with gdb for wince.you can get it from here ftp://ftp.freepascal.org/pub/fpc/contrib/cross/gdb-6.4-win32-arm-wince.zip<br />
<br />
<br />
'''Step 2''' - If you are using Microsoft Device Emulator Preview, launch(or restore)it.Make sure you've started emulator with 128mg of ram.Select a path for shared folders in emulator, add copy command to your .bat file used for building your application to copy the compiled exe file to your shared path.(as you can see in my .bat file).Here is a .bat file you can use to launch emulator with 128 of ram.<br />
<br />
<pre><br />
start deviceemulator.exe ".\ppc_2003_se\PPC_2003_SE_WWE_ARMv4.bin" /memsize 128 /skin <br />
".\ppc_2003_se\PocketPC_2003_Skin.xml"<br />
</pre><br />
<br />
After that just do 'save and exit' whenever you want to quit emulator,and launch it again from shortcuts created in your start menu.(the shortcuts with '(restore)').<br />
<br />
'''Step 3''' - Run Device Emulator Manager and in available emulators right click on the name of emulator and do cradle.Now Microsoft ActiveSync will be launched.If not in Micrososft ActiveSync Go to the menu '''File->Get connected'''.If still ActiveSync doesn't recognize the emulator.Uncradle and Cradle the emulator again.<br />
<br />
'''Step 4''' - Copy that file with File Explorer program in your emulator to \gdb directory.If it is your first time running emulator you have to create a gdb directory in 'My Pocket PC' folder which is your root(\) folder.(To make things even faster for your each build,with file explorer go to your shared folder,press ctrl+c in your exe file,go to \gdb folder and each time before you try to debug your application just press ctrl+v)<br />
<br />
'''Step 5''' - Now you can safely debug your application.gdb for wince will be launched.it will copy arm-wince-pe-stub.exe to \gdb folder and check if your application.exe file is there and will launch the program.<br />
If you encountered an error make sure the \gdb folder is created,arm-wince-pe-stub.exe and you exe file is there.Also most of the times because of big size of exe file you can not copy that into your \gdb file.So you have to call Microsoft Device Emulator Preview with 128mg of ram instead of default 64mg ram.<br />
<br />
'''Some Hints'''<br />
<br />
1. Programs remain in memory still after exiting from them. So you can't overwrite the .exe file. You have to use tools like Process Viewer from Microsoft which remotely shows all processes and allow you to kill them. Or use process killers inside the emulator. Process Explorer is another good option. One can get it from http://madebits.com<br />
<br />
2. Each time you are done with debugging your program don't exit from program.Do program Reset and then Debugger reset. Note that sometimes still program remain in memory,so you also have to kill the process too.<br />
<br />
=== Installing and Using the Pocked PC Emulator ===<br />
<br />
1 - You can download a Pocket PC Emulator from Microsoft [http://www.microsoft.com/downloads/details.aspx?FamilyId=C62D54A5-183A-4A1E-A7E2-CC500ED1F19A&displaylang=en here]. First, download and install the file V1Emulator.zip.<br />
<br />
2 - Next, be careful that there is a wrong information on the website. It will say that you need to install the Virtual Machine Network Driver, but the link provided on the website is broken. Instead, download Virtual PC 2007 [http://www.microsoft.com/downloads/details.aspx?FamilyID=04d26402-3199-48a3-afa2-2dc0b40a73b6&DisplayLang=en here]. This will install the necessary driver too.<br />
<br />
3 - Now, go back to the first website and download and install the efp.msi file<br />
<br />
Now you should have a fully functional PocketPC Emulator which can be utilized together with Lazarus to develop applications.<br />
<br />
To run a Lazarus application on the emulator you can either use GDB via ActiveSync, or you can also just execute it directly.<br />
<br />
==== Running an application on the emulator ====<br />
<br />
1 - Go the the Windows Programs Menu --> "Windows Mobile Emulator Images" --> "PocketPC"<br />
<br />
2 - If you never configured your shared folder for the emulator, do so now, by clicking on the menu File --> Configure once the emulator opens. Set it to a folder where you can access your Windows CE executable created with Lazarus.<br />
<br />
3 - On the emulator click: Start --> Programs. Now select "File Explorer". Now select "Storage Card". Navigate until you find your executable and double click it to execute it.<br />
<br />
== Screenshots ==<br />
<br />
An example of Lazarus+WinCE and the Free Pascal software used to test the cross compiler:<br />
<br />
[[Image:Capture 2.jpg]]<br />
[[Image:Wince.PNG]]<br />
<br />
== How to add a new control ==<br />
<br />
For example TButton.<br />
<br />
TButton is defined in lcl/buttons.pp. This is the platform independent part of the LCL, which is used by the normal LCL programmer.<br />
<br />
Its widgetset class is in lcl/widgetset/wsbuttons.pp. This is the platform independent base for all widgetsets (qt, carbon, gtk, win32, ...).<br />
<br />
It's wince interface class is in lcl/interfaces/wince/wincewsbuttons.pp:<br />
<br />
TWinCEWSButton = class(TWSButton)<br />
private<br />
protected<br />
public<br />
class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;<br />
end;<br />
<br />
Every WS class, that actually implements something must be registered. See the initialization section at the end of the wincewsXXX.pp unit:<br />
RegisterWSComponent(TButton, TWinCEWSButton);<br />
<br />
<br />
Also notice that DestroyHandle should be implemented to clean up memory utilized by the control.<br />
<br />
== See Also ==<br />
<br />
* [[Windows_CE_Development_Notes|Windows CE Interface Development notes]]<br />
<br />
* [[User:CCRDude|Alternative Lazarus Windows CE tutorial using Win64]]<br />
<br />
* [[Roadmap#Widgetset_dependent_components|Roadmap for the Windows CE interface]]<br />
<br />
* Mini framework for WindowsCE applications: [http://ccrdude.net/files/fpc/pkMiniGUI.pas pkMiniGUI.pas] [http://ccrdude.net/docs/pkCEStuff.htm Documentation]<br />
<br />
== Downloads ==<br />
<br />
* An add-on installer for the Lazarus windows installer based on fpc 2.1.1: ftp://ftp.hu.freepascal.org/pub/lazarus/cross/. These files are mirrored at http://michael-ep3.physik.uni-halle.de/Lazarus/cross/ Details can be found at http://www.mail-archive.com/lazarus@miraclec.com/msg12909.html Thanks to Vincent Snijders.</div>Antoniog