Sign in Join
Wiki copytemporary

Howdy World (Hello World on steroids)/pt: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Este 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.
22
33Este 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.
44
55Leitura recomendada antes de começar: uma introdução abrangente da [Lazarus IDE](http://wiki.lazarus.freepascal.org/Lazarus_Tutorial).
66
77## Vamos começar
88
99É 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.
1010
1111- Criar um novo diretório para o projeto de demonstração (digamos, \$HOME/CalculatorDemo).
1212
1313(*Texto que descreve ações que precisam ser executadas é marcado, como a linha anterior*)
1414
1515Com isto resolvido, é hora de iniciar um novo projeto Lazarus.
1616
1717- Inicie o Lazarus.
1818- Escolha Projeto/Novo Projeto… do menu.
1919- 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).
2020
2121Para ter certeza de que todos os arquivos do nosso novo projeto estarão no diretório certo, o projeto precisa ser salvo primeiro.
2222
2323- Do menu, escolha Arquivo/Salvar Tudo.
2424- Selecione o diretório que foi criado previamente (\$HOME/CalculatorDemo).
2525- Insira um novo nome de projeto: CalculatorDemo.
2626- Pressione Salvar (ou o que corresponder a isto em seu idioma).
2727- A IDE quer salvar o formulário principal também: insira ’’ufrmMain’’ como o nome da unidade do formulário.
2828- A IDE pergunta se o nome do arquivo deve ser modificado para minúsculas. Confirme isto pressionando o botão 'Renomear para minúsculas'.
2929
3030Em 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.
3131
3232- Do menu, escolha Projeto/Opções de Projeto.
3333- Selecione Opções do Compilador/Caminhos (clique no nó da TreeView).
3434- Insira o texto ‘‘bin\\’‘ antes do nome de arquivo alvo (ou ‘‘bin/’‘ ´para ambientes *nix).
3535- Note também o prefixo ‘‘lib’‘ para ‘diretório de saída das unidades’ (não o modifique).
3636- Pressione OK.
3737
3838A imagem abaixo mostra como isto ficaria em uma máquina Windows. ![](/wiki-images/e/eb/Tutcal_project_options.png)
3939
4040Fazendo 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.
4141
4242Agora, como um primeiro teste, o projeto pode ser compilado e executado.
4343
4444- 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.
4545- Finalize a execução clicando no ícone Fechar (isto depende do OS).
4646
4747## O primeiro componente
4848
4949O Lazarus tem uma assim chamada 'paleta de componentes':
5050
51-<figure>
52-<img src="tutcal_component_palette.png" title="tutcal_component_palette.png" />
53-<figcaption>tutcal_component_palette.png</figcaption>
54-</figure>
51+![](/wiki-images/d/d4/Tutcal_component_palette.png)
5552
5653Todos 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.
5754
5855Para 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 [Lazarus introduction](http://wiki.lazarus.freepascal.org/Lazarus_Tutorial)
5956
6057A 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.
6158
6259`# Nota: os componentes visuais são referidos como Controles. `\
6360`  Para o nosso propósito, a diferença entre um "componente" e um "controle" não é relevante.`
6461
6562Para 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.
6663
6764- Pressione F12 uma vez ou duas para posicionar a janela do formulário no topo (veja imagem abaixo).
6865
69-<figure>
70-<img src="tutcal_form_on_top.png" title="tutcal_form_on_top.png" />
71-<figcaption>tutcal_form_on_top.png</figcaption>
72-</figure>
66+![](/wiki-images/e/ed/Tutcal_form_on_top.png)
7367
7468- Selecione a aba Standard na palete de componentes. Esta é a aba que é selecionada por padrão.
7569- Clique sobre o componente TEdit (passe o mouse sobre os ícones de componentes para obter os nomes de classe).
7670- 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.
7771
7872Agora 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. ![](/wiki-images/5/59/Tutcal_object_inspector.png)
7973
8074As 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.
8175
8276Faça as seguintes modificações nas propriedades de Edit1:
8377
8478- Mude o nome para *edDisplay*.
8579- Mude Align para *alTop* (não confundir com Alignment).
8680- Mude Alignment para *alRightJustify* (não confundir com Align).
8781- Mude BorderSpacing.Around para *6*.
8882- Mude Text para *0* (o número zero, não a letra "O").
8983
9084Estas propriedades são bastante autoexplicativas, especialmente quando as modificações acima são feitas e o efeito é monitorado no formulário.
9185
9286Como 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.
9387
9488- 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.
9589- 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.
9690- Clique no botão com três pontos. Isto abre a caixa de diálogo Fonts.
9791- Selecione Verdana, Bold, Tamanho 10.
9892- Pressione OK.
9993
10094O título do formulário não é muito significativo. O padrão é 'Form1'.
10195
10296- No Inspetor de Objetos, clique na propriedade Caption.
10397- Mude o texto para *Calculator Demo*.
10498
10599O resultado de todas estas ações será um formulário que se parece com este: ![](/wiki-images/e/e0/Tutcal_form_with_tedit.png)
106100
107101Agora é uma boa hora para salvar o formulário.
108102
109103- Selecione do menu Arquivo/Salvar ou pressione a combinação de teclas Ctrl+S.
110104
111105Lembre-se de salvá-lo e o salve com frequência!
112106
113107## Botões
114108
115109Para 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.
116110
117111- Na paleta de componentes, selecione um controle TPanel.
118112- 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.
119113- Remova o texto *Panel1* da propriedade Caption.
120114- Modifique Align par a *alClient*.
121115- Modifique Borderspacing.Around para *6*.
122116- Aumente a largura (width) do formulário para *300* (primeiro clique no formulário na TreeView do Inspetor de Objetos).
123117- Aumente a altura (height) do formulário para *350*.
124118
125119(Aumentando o tamanho do formulário nos dará algum espaço para mover os controles.)
126120
127121Agora os botões dos dígitos serão adicionados.
128122
129123- Na paleta de componentes, selecione um controle TButton.
130124- 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.
131125- No Inspetor de Objetos, modifique o valor de Caption para *0* (o número zero).
132126- Modifique a largura (width) para *32*.
133127- Modifique a altura (height) para *30*.
134128- Modifique o nome (name) para *btnDigit0*.
135129
136130Isto 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.
137131
138132- Clique com o botão direito do mouse no botão do dígito *0* e selecione Copiar do menu popup.
139133- 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*.
140134- Modifique a propriedade Caption (rótulo) no Inspetor de Objetos para *1*.
141135- Repita a ação de Colar mais oito vezes para os botões seguintes.
142136- Mova os botões no formulário para obter um layout que se pareça com uma calculadora:
143137
144-<figure>
145-<img src="tutcal_calculator_digits.png" title="tutcal_calculator_digits.png" />
146-<figcaption>tutcal_calculator_digits.png</figcaption>
147-</figure>
138+![](/wiki-images/c/cd/Tutcal_calculator_digits.png)
148139
149140Os próximos são os quatro botões para operações matemáticas (soma, subtração, etc).
150141
151142- Coloque um novo TButton no formulário.
152143- Modifique a largura para *32*.
153144- Modifique a altura para *30*.
154145- Modifique a propriedade Caption para *+*.
155146- Modifique o nome para *btnFunction*.
156147- Copie e Cole este botão mais três vezes, modificando o rótulo (caption) para *-*, *** e */*.
157148- Alinhe os botões verticalmente, ao lado dos botões dos dígitos.
158149
159150E os botões especiais:
160151
161152- Copie e Cole o botão *+*.
162153- Modifique o rótulo para *+/-*
163154- Modifique o nome para *btnPlusMinus*.
164155- Posicione o botão bem embaixo do botão *3*.
165156- Copie e Cole o botão *+*.
166157- Modifique o rótulo para *C*.
167158- Modifique o nome para *btnClear*.
168159- Posicione o botão à direita do botão *+*.
169160- Copie e Cole o botão *+*.
170161- Modifique o rótulo para *=*.
171162- Modifique o nome para *btnCalculate*.
172163- Posicione o botão à direita do botão */*.
173164
174165Redimensione o formulário para que se ajuste aos botões.
175166
176167Isto deve resultar em algo assim:
177168
178-<figure>
179-<img src="tutcal_calculator_gui_ready.png" title="tutcal_calculator_gui_ready.png" />
180-<figcaption>tutcal_calculator_gui_ready.png</figcaption>
181-</figure>
169+![](/wiki-images/c/c2/Tutcal_calculator_gui_ready.png)
182170
183171Lembre-se de salvar e salve com frequência!
184172
185173## Respondendo a eventos
186174
187175Uma 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.
188176
189177- Certifique-se de que o formulário com todos os botões está visível (se necessário, pressione F12 uma ou duas vezes).
190178- 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);
191179- Digite o seguinte código entre as palavras-chave *begin* e *end*:
192180
193181``` pascal
194182edDisplay.Text := edDisplay.Text + '0'
195183```
196184
197185edtDisplay é 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.
198186
199187- Dê um duplo-clique no botão com o rótulo *1*.
200188- Digite o seguinte código entre as palavras-chave *begin* e *end*:
201189
202190``` pascal
203191edDisplay.Text := edDisplay.Text + '1'
204192```
205193
206194É uma boa ideia compilar o código a intervalos para verificar erros de sintaxe.
207195
208196- Selecione do menu: Executar/Executar (ou pressione F9). O projeto é compilado e a aplicação se inicia.
209197- 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.
210198- Pare o programa de Calculadora.
211199
212200É 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.
213201
214202- No editor, localize as linhas em que a classe TForm1 é declarada. Ele vai se parecer com isto:
215203
216204``` pascal
217205 { TForm1 }
218206
219207 TForm1 = class(TForm)
220208 btnDigit0: TButton;
221209 btnDigit1: TButton;
222210 btnDigit2: TButton;
223211 btnDigit3: TButton;
224212 btnDigit4: TButton;
225213 btnDigit5: TButton;
226214 btnDigit6: TButton;
227215 btnDigit7: TButton;
228216 btnDigit8: TButton;
229217 btnDigit9: TButton;
230218 btnFunction: TButton;
231219 btnFunction1: TButton;
232220 btnFunction2: TButton;
233221 btnFunction3: TButton;
234222 btnCalculate: TButton;
235223 btnPlusMinus: TButton;
236224 btnClear: TButton;
237225 edDisplay: TEdit;
238226 Panel1: TPanel;
239227 procedure btnDigit0Click(Sender: TObject);
240228 procedure btnDigit1Click(Sender: TObject);
241229 private
242230 { private declarations }
243231 public
244232 { public declarations }
245233 end;
246234```
247235
248236Note 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).
249237
250238De 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.
251239
252240- Acrescente o procedimento AddDigit à seção *private* do formulário.
253241
254242``` pascal
255243 private
256244 { private declarations }
257245 procedure AddDigit(const pDigit: byte);
258246 public
259247 { public declarations }
260248 end;
261249```
262250
263251Em seguida, o código efetivo para o procedimento AddDigit precisa ser inserido. Novamente a IDE vem em nosso auxílio:
264252
265253- Posicione o caret na linha AddDigit.
266254- Pressione a combinação de teclas Ctrl+Shift+C.
267255
268256A 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.
269257
270258- Acrescente o seguinte código ao procedimento AddDigit:
271259
272260``` pascal
273261edDisplay.Text := edDisplay.Text + IntToStr(pDigit)
274262```
275263
276264Note 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.
277265
278266E para usar este procedimento para todos os dígitos:
279267
280268- Abra o formulário (se necessário, pressione F12 uma ou duas vezes).
281269- Dê um duplo-clique no botão do dígito '0': isto abrirá o editor no manipulador de eventos para o botão 0.
282270- Substituia o código no manipulador de eventos por: AddDigit(0). O procedimento se parecerá com isto:
283271
284272``` pascal
285273procedure TForm1.btnDigit0Click(Sender: TObject);
286274begin
287275 AddDigit(0)
288276end;
289277```
290278
291279- Faça o mesmo para o botão do dígito 1:
292280
293281``` pascal
294282procedure TForm1.btnDigit1Click(Sender: TObject);
295283begin
296284 AddDigit(1)
297285end;
298286```
299287
300288Antes de completar esta sequência para todos os outros botões de dígitos, certifique-se de que ele realmente faz o que queremos.
301289
302290- Execute o programa (pressione F9).
303291- Clique nos botões 0 e 1 algumas vezes e veja se ele realmente funciona.
304292- Finalize o programa.
305293
306294*Um bom programador é um programador preguiçoso*
307295
308296Agora 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. E se houvesse uma maneira de contar os botões separadamente? Felizmente existe.
309297
310298Todos 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*...
311299
312300- Abra o formulário (se necessário, pressione F12 uma ou duas vezes).
313301- Selecione o botão do dígito 1 (clique nele uma vez).
314302- No Inspetor de Objetos, localize a propriedade *Tag* e modifique seu valor par *1*.
315303- Selecione o botão do dígito 2 (clique nele uma vez).
316304- No Inspetor de Objetos, localize a propriedade *Tag* e modifique seu valor para *2*.
317305- Repita isto para os botões dos dígitos 3..9.
318306
319307Agora 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. Agora, para fazer uso deste valor de Tag:
320308
321309- Abra o formulário.
322310- 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).
323311- Note que o procedimento *btnDigit0Click* tem um parâmetro *Sender* de tipo *TObject*.
324312
325313``` pascal
326314procedure TForm1.btnDigit0Click(Sender: TObject);
327315```
328316
329317O 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.
330318
331319- Modifique o código assim:
332320
333321``` pascal
334322procedure TForm1.btnDigit0Click(Sender: TObject);
335323begin
336324 AddDigit(TButton(Sender).Tag)
337325end;
338326```
339327
340328Nã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!
341329
342330Vamos olhar melhor para o Inspetor de Objetos.
343331
344332- Abra o formulário.
345333- Selecione o botão do dígito 0 (btnDigit0).
346334- No Inspetor de Objetos, selecione a aba Events (veja abaixo).
347335
348-<figure>
349-<img src="tutcal_oi_events.png" title="tutcal_oi_events.png" />
350-<figcaption>tutcal_oi_events.png</figcaption>
351-</figure>
336+![](/wiki-images/1/12/Tutcal_oi_events.png)
352337
353338No 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*).
354339
355340- 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.
356341- Abra a lista dropdown para o evento OnClick e selecione *btnDigit0Click*.
357342- Faça o mesmo para todos os outros botões de dígitos 3..9.
358343
359344Now 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.
360345
361346- On the form: select digit button 1. In the Object Inspector we can now see that the event handler indeed is *btnDigit1Click*.
362347- Open the drop down list for the OnClick event and select btnDigit0Click.
363348
364349Now all buttons share the same event handler to add digits to the display box.
365350
366351- Run the program (press F9).
367352- Click all buttons 0..9 a couple of times and see that it actually works.
368353- End the program.
369354
370355For 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.
371356
372357- In the menu select Environment/Options.
373358- Click on Editor/Completion and Hints.
374359- Enable the option 'Auto remove empty methods' (see image below).
375360- Press OK.
376361
377-<figure>
378-<img src="tutcal_auto_remove.png" title="tutcal_auto_remove.png" />
379-<figcaption>tutcal_auto_remove.png</figcaption>
380-</figure>
362+![](/wiki-images/4/4c/Tutcal_auto_remove.png)
381363
382364From now on all empty methods are automatically deleted as soon as the source file is saved.
383365
384366- Locate method *procedure TForm1.btnDigit1Click(Sender: TObject)*
385367- Delete the line 'AddDigit(1)'
386368- Save the file (press Ctrl-S or select from the menu File/Save). The now empty procedure is automatically deleted.
387369
388370## Tuning
389371
390372So 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.
391373
392374### Removing leading zeroes
393375
394376Normally 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.
395377
396378- Locate method *procedure TForm1.AddDigit(const pDigit: byte)*
397379- Change the code to:
398380
399381``` pascal
400382procedure TForm1.AddDigit(const pDigit: byte);
401383begin
402384 // Suppress leading zeroes when adding digits
403385 if edDisplay.Text = '0' then
404386 edDisplay.Text := IntToStr(pDigit)
405387 else
406388 edDisplay.Text := edDisplay.Text + IntToStr(pDigit)
407389end;
408390```
409391
410392### Limit the number of digits
411393
412394This 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:
413395
414396- Locate method *procedure TForm1.AddDigit(const pDigit: byte)*
415397- Change the code to:
416398
417399``` pascal
418400procedure TForm1.AddDigit(const pDigit: byte);
419401begin
420402 // Limit the number of digits
421403 if length(edDisplay.Text) < 8 then
422404 begin
423405 // Suppress leading zeroes when adding digits
424406 if edDisplay.Text = '0' then
425407 edDisplay.Text := IntToStr(pDigit)
426408 else
427409 edDisplay.Text := edDisplay.Text + IntToStr(pDigit)
428410 end;
429411end;
430412```
431413
432414## Operations
433415
434416Now 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:
435417
4364181. The user enters a number
4374192. The user presses a function button (e.g. '+')
4384203. The user enters a second number
4394214. The user presses '='
4404225. The program responds with the addition of the first and second number
441423
442424As soon as the user presses the '=' button the program has to know three things:
443425
4444261. What was the operation?
4454272. What was the first number?
4464283. What was the second number?
447429
448430### What was the operation?
449431
450432Somehow 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.
451433
452434- In the Source Editor, find the location where the form is declared.
453435- Just above the form add the type declaration *TOperationType* for all supported operations:
454436
455437``` pascal
456438 type
457439
458440 { All supported operations for our calculator }
459441 TOperationType = (otNone, otPlus, otMinus, otMultiply, otDivide);
460442
461443 { TForm1 }
462444
463445 TForm1 = class(TForm)
464446```
465447
466448- To temporarily store the operation, a variable is added to the private section of the form's class declaration.
467449
468450``` pascal
469451 private
470452 { private declarations }
471453 SelectedOperation: TOperationType;
472454 procedure AddDigit(const pDigit: byte);
473455```
474456
475457### What was the first number?
476458
477459To temporarily store the first number that was entered we need a variable.
478460
479461- Add a variable to the form's private section.
480462
481463``` pascal
482464 private
483465 { private declarations }
484466 SelectedOperation: TOperationType;
485467 FirstNumber: longint;
486468 procedure AddDigit(const pDigit: byte);
487469```
488470
489471### What was the second number?
490472
491473- Add variable SecondNumber to the form's private section (the same as FirstNumber) and make it a longint as well.
492474
493475## What's on your mind
494476
495477Now 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.
496478
497479- Open the form.
498480- Double click on button '+'. The IDE creates an event handler and the text cursor is placed inside the empty begin/end block.
499481
500482Hold 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.
501483
502484- Locate the form's private section and add a new procedure: StoreOperation.
503485
504486``` pascal
505487 private
506488 { private declarations }
507489 SelectedOperation: TOperationType;
508490 FirstNumber: longint;
509491 SecondNumber: longint;
510492 procedure AddDigit(const pDigit: byte);
511493 procedure StoreOperation(const pOperation: TOperationType);
512494```
513495
514496- Place the blinking text cursor on the newly inserted line.
515497- Press Ctrl-Shift-C (you know the drill by now…).
516498
517499The 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.
518500
519501- Add the following code to the newly created procedure:
520502
521503``` pascal
522504procedure TForm1.StoreOperation(const pOperation: TOperationType);
523505begin
524506 // Store the operation so it can be used later
525507 SelectedOperation := pOperation;
526508
527509 // Store the number that was entered by the user
528510 FirstNumber := StrToInt(edDisplay.Text);
529511end;
530512```
531513
532514Ok, now back to the '+' button:
533515
534516- Open the form.
535517- Double click on button '+'.
536518- Add the following code: StoreOperation(otPlus);
537519- Open the form.
538520- Double click on button '-'.
539521- Add the following code: StoreOperation(otMinus);
540522- Open the form.
541523- Double click on button '*'.
542524- Add the following code: StoreOperation(otMultiply);
543525- Open the form.
544526- Double click on button '/'.
545527- Add the following code: StoreOperation(otDivide);
546528
547529Now test the program and see what happens:
548530
549531- Run the program (press F9)
550532- Enter a number (e.g. 21267)
551533- Press the '+' button
552534- Enter the second number (e.g. 31170)
553535
554536What 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.
555537
556538- Locate the form's private section and add a new variable: doClearDisplay. This variable will be the trigger for erasing the display.
557539
558540``` pascal
559541 private
560542 { private declarations }
561543 SelectedOperation: TOperationType;
562544 FirstNumber: longint;
563545 SecondNumber: longint;
564546 doClearDisplay: boolean;
565547 procedure AddDigit(const pDigit: byte);
566548 procedure StoreOperation(const pOperation: TOperationType);
567549```
568550
569551- Position the blinking text cursor on the line StoreOperation.
570552- Press Ctrl-Shift-CursorDown: this moves the cursor to the body of the StoreOperation procedure.
571553- 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:
572554
573555``` pascal
574556procedure TForm1.StoreOperation(const pOperation: TOperationType);
575557begin
576558 // Store the operation so it can be used later
577559 SelectedOperation := pOperation;
578560
579561 // Store the number that was entered by the user
580562 FirstNumber := StrToInt(edDisplay.Text);
581563
582564 // The display must start with a new number
583565 doClearDisplay := true;
584566end;
585567```
586568
587569- And where better to clear the display than in the AddDigit procedure? Change the code to:
588570
589571``` pascal
590572procedure TForm1.AddDigit(const pDigit: byte);
591573begin
592574 // Must the display be cleared first?
593575 if doClearDisplay then
594576 begin
595577 edDisplay.Text := '0'; // Reset the display to zero
596578 doClearDisplay := false; // Once is enough...
597579 end;
598580
599581 // Limit the number of digits
600582 if length(edDisplay.Text) < 8 then
601583 begin
602584 // Suppress leading zeroes when adding digits
603585 if edDisplay.Text = '0' then
604586 edDisplay.Text := IntToStr(pDigit)
605587 else
606588 edDisplay.Text := edDisplay.Text + IntToStr(pDigit)
607589 end;
608590end;
609591```
610592
611593Now let's see what happens:
612594
613595- Run the program (press F9).
614596- Enter a number.
615597- Press an operation button.
616598- Enter another number.
617599- End the program.
618600
619601We're almost there: we can enter numbers and select an operation. Now it's time to do the actual calculations.
620602
621603## Doing the math
622604
623605Now that we have stored a number and an operation, it's time to do the actual calculations. Let's start easy with additions.
624606
625607- Open the form.
626608- Double click on button '=' (the event handler is created).
627609- Change the procedure:
628610
629611``` pascal
630612procedure TForm1.btnCalculateClick(Sender: TObject);
631613var result: longint;
632614begin
633615 case SelectedOperation of
634616 otPlus: begin
635617 // Retrieve the second number
636618 SecondNumber := StrToInt(edDisplay.Text);
637619 // Do the math
638620 result := FirstNumber + SecondNumber;
639621 // Display the resulting value
640622 edDisplay.Text := IntToStr(result);
641623 end;
642624 end;
643625end;
644626```
645627
646628The 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.
647629
648630We now have a working calculator (that can only add two numbers):
649631
650632- Run the program (press F9).
651633- Enter a number.
652634- Press '+'
653635- Enter another number.
654636- Press '=' : the sum of the two numbers is displayed.
655637- End the program.
656638
657639We 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:
658640
659641``` pascal
660642SecondNumber := StrToInt(edDisplay.Text);
661643```
662644
663645We have seen such a statement before: the StoreOperation procedure contains something similar:
664646
665647``` pascal
666648FirstNumber := StrToInt(edDisplay.Text);
667649```
668650
669651Calculating 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.
670652
671653- Locate the form's private section and add a new function: GetDisplayValue.
672654
673655``` pascal
674656 private
675657 { private declarations }
676658 SelectedOperation: TOperationType;
677659 FirstNumber: longint;
678660 SecondNumber: longint;
679661 doClearDisplay: boolean;
680662 procedure AddDigit(const pDigit: byte);
681663 procedure StoreOperation(const pOperation: TOperationType);
682664 function GetDisplayValue: longint;
683665```
684666
685667- Position the blinking text cursor on the line GetDisplayValue.
686668- Press Ctrl-Shift-C.
687669- Add this code to extract the value that is in the display field:
688670
689671``` pascal
690672function TForm1.GetDisplayValue: longint;
691673begin
692674 result := StrToInt(edDisplay.Text);
693675end;
694676```
695677
696678- Locate the statement: FirstNumber := StrToInt(edDisplay.Text);
697679- Change it to: FirstNumber := GetDisplayValue;
698680
699681So much for refactoring, back to the calculations.
700682
701683- Locate the statement: SecondNumber := StrToInt(edDisplay.Text);
702684- Change it to: SecondNumber := GetDisplayValue;
703685
704686Now look at the following statements:
705687
706688``` pascal
707689 // Retrieve the second number
708690 SecondNumber := GetDisplayValue;
709691 // Do the math
710692 result := FirstNumber + SecondNumber;
711693```
712694
713695Variable *SecondNumber* is used to store the value in the display box. However it is not really necessary. The above code can be simplified:
714696
715697``` pascal
716698 // Do the math
717699 result := FirstNumber + GetDisplayValue;
718700```
719701
720702Now look at the following statements:
721703
722704``` pascal
723705 // Do the math
724706 result := FirstNumber + GetDisplayValue;
725707 // Display the resulting value
726708 edDisplay.Text := IntToStr(result);
727709```
728710
729711The same now applies to the *result* variable. The above code can be simplified to:
730712
731713``` pascal
732714 // Display the resulting value
733715 edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);
734716```
735717
736718Now we can add the 3 remaining operations.
737719
738720- Open the form.
739721- Double click on button '=' (the event handler is created).
740722- Change the code:
741723
742724``` pascal
743725procedure TForm1.btnCalculateClick(Sender: TObject);
744726begin
745727 case SelectedOperation of
746728 otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);
747729 otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);
748730 otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);
749731 otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);
750732 end;
751733end;
752734```
753735
754736We now have a working calculator for all 4 operations:
755737
756738- Run the program (press F9).
757739- Enter a number.
758740- Press an operation button.
759741- Enter another number.
760742- Press '=' : the result is displayed.
761743- End the program.
762744
763745## Intermezzo
764746
765747After 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.
766748
767749First let's add another procedure, just for the fun of it (well, there's more to it of course:-)):
768750
769751- Locate the form's private section and add a new procedure: SetDisplayValue.
770752
771753``` pascal
772754 private
773755 { private declarations }
774756 SelectedOperation: TOperationType;
775757 FirstNumber: longint;
776758 SecondNumber: longint;
777759 doClearDisplay: boolean;
778760 procedure AddDigit(const pDigit: byte);
779761 procedure StoreOperation(const pOperation: TOperationType);
780762 function GetDisplayValue: longint;
781763 procedure SetDisplayValue(const pValue: longint);
782764```
783765
784766- Position the blinking text cursor on the line SetDisplayValue.
785767- Press Ctrl-Shift-C.
786768- Add the code below to give the display a new value, as the procedure name suggests:
787769
788770``` pascal
789771procedure TForm1.SetDisplayValue(const pValue: longint);
790772begin
791773 edDisplay.Text := IntToStr(pValue);
792774end;
793775```
794776
795777The above code should look pretty familiar. Have a look at the procedure that does all calculations:
796778
797779``` pascal
798780procedure TForm1.btnCalculateClick(Sender: TObject);
799781begin
800782 case SelectedOperation of
801783 otPlus : edDisplay.Text := IntToStr(FirstNumber + GetDisplayValue);
802784 otMinus : edDisplay.Text := IntToStr(FirstNumber - GetDisplayValue);
803785 otMultiply : edDisplay.Text := IntToStr(FirstNumber * GetDisplayValue);
804786 otDivide : edDisplay.Text := IntToStr(FirstNumber div GetDisplayValue);
805787 end;
806788end;
807789```
808790
809791This procedure can now be simplified.
810792
811793- Change the code to:
812794
813795``` pascal
814796procedure TForm1.btnCalculateClick(Sender: TObject);
815797begin
816798 case SelectedOperation of
817799 otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);
818800 otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);
819801 otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);
820802 otDivide : SetDisplayValue(FirstNumber div GetDisplayValue);
821803 end;
822804end;
823805```
824806
825807## Loose ends
826808
827809There's a couple of things that need to be done: implement the two loose buttons and make the calculator a bit more robust.
828810
829811### The +/- button
830812
831813- Open the form.
832814- Double click on button '+/-' (the event handler is created).
833815- Add the following code:
834816
835817``` pascal
836818procedure TForm1.btnPlusMinusClick(Sender: TObject);
837819begin
838820 SetDisplayValue(0 - GetDisplayValue);
839821end;
840822```
841823
842824See here the fruits of our labor. We have reused the procedure SetDisplayValue and GetDisplayValue to implement the negate function.
843825
844826Try it by running the program and press the '+/-' button.
845827
846828### The Clear button
847829
848830- Open the form.
849831- Double click on button 'C' (the event handler is created).
850832- Add the following code:
851833
852834``` pascal
853835procedure TForm1.btnClearClick(Sender: TObject);
854836begin
855837 SetDisplayValue(0); // Start from scratch
856838 SelectedOperation := otNone; // No operation selected yet
857839 doClearDisplay := false; // The display is already cleared
858840end;
859841```
860842
861843The 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.
862844
863845### Divide by zero
864846
865847Let'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).
866848
867849- Open the form.
868850- Double click on button '='.
869851- Update the otDivide section:
870852
871853``` pascal
872854procedure TForm1.btnCalculateClick(Sender: TObject);
873855begin
874856 case SelectedOperation of
875857 otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);
876858 otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);
877859 otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);
878860 otDivide : if GetDisplayValue <> 0 then
879861 SetDisplayValue(FirstNumber div GetDisplayValue)
880862 else
881863 begin
882864 // Display an error message to the user
883865 MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);
884866 // Reset the calculator to start with a clean slate
885867 btnClearClick(nil);
886868 end
887869 end;
888870end;
889871```
890872
891873Things noteworthy:
892874
8938751. *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.
8948762. *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.
895877
896878### Overflows
897879
898880- Start the calculator
899881- Enter 99999999 as the first number (8 digits)
900882- Press button '*'
901883- Enter 99999999 as the second number
902884- Press button '='
903885
904886Now two things could have happened:
905887
9068881. The application gives an incorrect result (something like 1674919425).
9078892. The application raises an error.
908890
909891If it's the first option then overflow errors have been disabled for the project. Enable them by ticking the Overflow option box:
910892
911893- Select from the menu Project/Project Options…
912894- Select in the treeview Compiler Options/Code Generation.
913895- Tick the box *Overflow (-Co)* (see image below).
914896- Click OK.
915897
916-<figure>
917-<img src="tutcal_compiler_overflow.png" title="tutcal_compiler_overflow.png" />
918-<figcaption>tutcal_compiler_overflow.png</figcaption>
919-</figure>
898+![](/wiki-images/3/34/Tutcal_compiler_overflow.png)
920899
921900Now run the program again and see what happens with overflows.
922901
923902If 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.
924903
925904- Open the form.
926905- Double click on button '='.
927906- Change the code in the procedure to this:
928907
929908``` pascal
930909procedure TForm1.btnCalculateClick(Sender: TObject);
931910begin
932911 // Catch any overflow errors
933912 try
934913 case SelectedOperation of
935914 otPlus : SetDisplayValue(FirstNumber + GetDisplayValue);
936915 otMinus : SetDisplayValue(FirstNumber - GetDisplayValue);
937916 otMultiply : SetDisplayValue(FirstNumber * GetDisplayValue);
938917 otDivide : if GetDisplayValue <> 0 then
939918 SetDisplayValue(FirstNumber div GetDisplayValue)
940919 else
941920 begin
942921 // Display an error message to the user
943922 MessageDlg('It is not possible to divide a number by 0!', mtWarning, [mbCancel],0);
944923 // Reset the calculator to start with a clean slate
945924 btnClearClick(nil);
946925 end
947926 end;
948927 except
949928 on E: EIntOverflow do
950929 begin
951930 // Display an error message
952931 MessageDlg('The result of the calculation was too big for the calculator to process!', mtWarning, [mbCancel], 0);
953932 // Reset the calculator
954933 btnClearClick(nil);
955934 end
956935 end
957936end;
958937```
959938
960939Note 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. 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.
961940
962941## Final tweaks
963942
964943Remember 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.
965944
966945- Click on message *Note: Private field "TForm1.SecondNumber" is never used*.
967946- Delete longint variable *SecondNumber*.
968947
969948As soon as our demo Calculator is started we see that the number 0 in the display has the focus (see image below).
970949
971-<figure>
972-<img src="tutcal_calculator_focus.png" title="tutcal_calculator_focus.png" />
973-<figcaption>tutcal_calculator_focus.png</figcaption>
974-</figure>
950+![](/wiki-images/4/46/Tutcal_calculator_focus.png)
975951
976952This 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.
977953
978954- Open the form.
979955- Select the display control (click on edDisplay).
980956- 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.
981957- 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.
982958
983959Run the program to see the result of these changes.
984960
985961(Under construction: OO-ify the program)
986962
987963---
988964*From the Free Pascal wiki, page "Howdy World (Hello World on steroids)/pt", as it stood on 2020-02-17 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history