delphi

236
Delphi 3.0 - Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 1 Todos os direitos reservados. Delphi 1. Introdução Delphi é uma ferramenta gráfica para você poder utilizar toda a potencialidade do Object Pascal. Logo após executar o Delphi, você tem à disposição o IDE (Integrated Development Environment), o ambiente Integrado de desenvolvimento. Através dele, lhe será poupada muita digitação, pois através do recurso de arrastar-e-soltar você estará na realidade construindo código-fonte sem tocar no teclado. Estes ambientes integrados, aliás, nos poupou bastante trabalho em termos de digitação, porém, a lógica continua cabendo ao programador. 2. O IDE (Integrated Development Environment) Abaixo é mostrado o IDE. Nele você pode ver três áreas principais: Object Inspector (Inspetor de Objetos) Component Palette (Palheta de Componentes, agregado a uma barra de teclas de atalho) Form (Form em branco)

Upload: sirdata-data

Post on 11-Dec-2014

85 views

Category:

Documents


4 download

DESCRIPTION

programação em delphi

TRANSCRIPT

Page 1: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 1 Todos os direitos reservados.

Delphi

1. Introdução

Delphi é uma ferramenta gráfica para você poder utilizar toda a potencialidade do Object Pascal. Logo após executar o Delphi, você tem à disposição o IDE (Integrated Development Environment), o ambiente Integrado de desenvolvimento. Através dele, lhe será poupada muita digitação, pois através do recurso de arrastar-e-soltar você estará na realidade construindo código-fonte sem tocar no teclado. Estes ambientes integrados, aliás, nos poupou bastante trabalho em termos de digitação, porém, a lógica continua cabendo ao programador.

2. O IDE (Integrated Development Environment)

Abaixo é mostrado o IDE. Nele você pode ver três áreas principais:

Object Inspector (Inspetor de Objetos) Component Palette (Palheta de Componentes, agregado a uma barra de teclas

de atalho) Form (Form em branco)

Object Inspector Component Palette Form

Minimizando o Form (como qualquer janela do Windows), você poderá notar ainda uma outra área que é o Code Editor (Editor de Código-Fonte):

Page 2: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 2 Todos os direitos reservados.

Nesta área, iremos digitar o código adicional necessário à execução dos nossos programas.

3. Construindo um projeto

Quando você executa o Delphi, já tem à sua disposição uma janela com todos as propriedades básicas (de uma janela): estilo da borda (Border Style), altura (Height), largura (Width), título (Caption), etc. , além das ações características passíveis a uma janela do ambiente Windows: arraste, minimização, maximização, fechamento, etc. Isto tudo é para dizer que você não precisa reinventar a roda, ou seja, programar tudo aquilo que já deve estar contido por default numa janela. Porém, não considere isto como uma camisa-de-forças, pois você poderá personalizar a sua janela de acordo com as suas necessidades.

Para entender como será construído o nosso aplicativo, vamos entender como é construído um aplicativo Delphi.

Antes de iniciar a construção de um aplicativo Delphi, vamos entender como é que se constrói um aplicativo executável qualquer:

3.1. Código-fonte: é a parte que contém os comandos digitados pelo usuário ou, inseridos pelo ambiente de desenvolvimento

3.2. Código-objeto: é o resultado da compilação do código-fonte. Toda linguagem de programação contém um compilador que, ao ser executado, verifica se o código-fonte contém erros de sintaxe (por exemplo, o comando Close escrito com "z" como em Cloze). Caso os tenha, o compilador acusa o(s) erro(s), permitindo que você o(s) corrija. Ao término de todas as correções, o compilador então "traduz" todo o código-fonte linha-a-linha em linguagem de máquina (código-binário), ao qual chamamos de código-objeto.

3.3. Código-executável: uma vez terminada a compilação, o código-objeto deve sofrer então uma linkedição. Isto se faz necessário devido ao código-objeto ser

Page 3: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 3 Todos os direitos reservados.

código binário porém "solto", isto é, não temos como "dizer" ao programa a ordem de execução das rotinas. O linkeditor (do inglês: to link : unir, ligar) tem por função unir as rotinas do código-objeto na seqüência de execução.

Devido a estarmos trabalhando num ambiente integrado de desenvolvimento, teremos todas essas ferramentas (editor de código-fonte, gráfico e texto, compilador, linkeditor) disponíveis ao mesmo tempo, diferentemente do que precisávamos em algumas outras linguagens.

Agora que sabemos os passos necessários para gerar um aplicativo (programa executável) qualquer, precisamos entender como construí-lo com o Delphi.

Em primeiro lugar, vamos entender como é composto um código-fonte em Delphi:

Você pode trabalhar com mais de uma janela (criar mais de uma janela no seu aplicativo) podendo, através de comandos por você digitados, alternar entre essas janelas. Mas você terá que ter um lugar onde esteja escrito quais são as janelas constituintes do seu aplicativo. Dito isto, podemos dizer que você deve construir um projeto que contenha quais são as janelas contidas neste projeto. Além disto, cada janela poderá ter um código diferente de outra janela (imagine um sistema que contenha uma janela para senha, uma janela para funcionar com uma calculadora, e uma janela para cálculo de taxas de juros), pois as características básicas o Delphi já escreveu para você, mas as modificações subseqüentes são sua responsabilidade. Assim sendo, podemos dizer, numa primeira análise que, o código-fonte de cada janela adicionada ao seu projeto será escrito numa UNIT, e que o projeto conterá os nomes de todas as units que compõe o seu sistema.

4. Construindo o primeiro aplicativo

PROJETO

UNIT 1 UNIT 2 UNIT n

Page 4: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 4 Todos os direitos reservados.

4.1. Executando a aplicativo

Como você já tem um código-fonte à disposição, execute-o clicando no botão RUN:

Veja agora o aplicativo sendo executado: uma janela em branco, com o título Form1 (observe que os pontinhos de alinhamento não mais aparecem, somente estando presentes na fase de projeto), além do botão RUN desabilitado e a palavra Running:

Arraste-a, redimensione-a e depois a feche. Você retorna automaticamente ao IDE.

4.2. Verificando o código-fonte

Page 5: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 5 Todos os direitos reservados.

Vamos examinar, sem maiores preocupações em entender, ainda, o código-fonte produzido pelo Delphi para o projeto no qual você está trabalhando. Minimize a janela e verifique que o código escrito para a janela é:

unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type TForm1 = class(TForm) private { Private declarations } public { Public declarations } end;

var Form1: TForm1;

implementation

{$R *.DFM}

end.

Podemos ver preliminarmente que, a unit UNIT1 possui uma variável (var) denominada Form1, que é igual ao título da janela. Não vemos mais informação relevante para essa janela.

Vamos verificar agora o código-fonte do projeto. Para isto, dê um clique em View-Project Source:

Page 6: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 6 Todos os direitos reservados.

O código é o seguinte:

program Project1;

uses Forms, Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run;end.

O código nos informa que o projeto cujo nome é Project1, possui uma janela (Form1) na unit UNIT1, que por sua vez está contida no arquivo Unit1.pas. A janela é criada (visualmente) na linha Application.CreateForm(TForm1, Form1); e o aplicativo começa a rodar (executar) com a linha Application.Run; (uma maneira de informar ao Windows que o aplicativo está apto para começar a sua execução. Mais tarde, em manipulando eventos, será explicado o porquê disto).

Para retornar ao form Form1:- dê um clique no botão Select form from list,- clique no nome do form Form1- dê um clique em OK

4.3. Adicionando um botão

Para adicionar um botão, você deve dar um clique no objeto correspondente no Component Palette

Page 7: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 7 Todos os direitos reservados.

e em seguida dar um clique sobre janela, mais ou menos na posição onde você acha que o botão deve ficar. (Preste bem atenção: não precisa ser o local exato onde você deseja que o botão esteja, pois você poderá depois de adicionado o botão arrastá-lo para qualquer lugar dentro da janela à qual você adicionou o botão). Veja que agora o form contém um botão, cujo título é Button1:

Podemos alterar esse título (caption) sem sentido por algo mais explicativo, como por exemplo Fechar. O que você está querendo fazer então é alterar uma das propriedades do objeto, que é o seu caption. Algumas propriedades podem ser alteradas no Object Inspector. Assim, dê um clique no Object Inspector no lado direito onde aparece a propriedade Caption:

Page 8: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 8 Todos os direitos reservados.

Digite a palavra Fechar. Verifique que o caption do botão vai sendo alterado automaticamente. Isto significa que, você acaba de alterar a propriedade Caption do componente Button1.

Mas como Button1, se você alterou o caption de Button1 para Fechar? Veja bem, você alterou o título (caption) do botão de Button1 para Fechar, mas o nome (propriedade Name) do componente continua Button1 (olhe o Object Inspector e verifique que o nome - propriedade Name - do componente é Button1 mas sua propriedade Caption é Fechar).Para alterar o caption da janela, dê um clique (simples) no form ou então dê um clique no ComboBox do Object Inspector:

e selecione

Form1. Altere o Caption para: A primeira janela a gente nunca esquece. Note que o título da janela (Caption) é alterado.

Execute novamente o aplicativo. Dê um clique no botão. Observe que não acontece coisa alguma.

4.4. Manipulando eventos

No item 4.2, verificando o código-fonte do projeto, você pôde ver a linha Application.Run; . Esta linha "aciona" o manipulador de eventos do Windows para a sua aplicação.

Page 9: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 9 Todos os direitos reservados.

O Windows é um sistema operacional multitarefa, e como tal, deve poder gerenciar várias atividades ocorrendo de maneira "simultânea" (para nós parece ser simultâneo o ecoar de uma letra na tela após o pressionar de uma tecla, mas entre uma e outra ação decorre uma fração de tempo). Isto significa dizer que, se antigamente o usuário de um programa interagia com o mesmo, agora, o usuário interage com o Windows, e o mesmo é que tem que notificar o aplicativo sofrendo a ação (um pressionar de uma tecla, um clique do mouse, uma ordem de fechamento), enviando junto à notificação qual o tipo de ação (ou evento) ocorrido. Bem, se o seu aplicativo contiver código que trate (manipule) o evento acontecido, esse código é executado; caso contrário, o aplicativo "pede" ao Windows que manipule o evento com uma ação default.

Para exemplificar, você viu que ao pressionar o botão na janela do seu aplicativo não aconteceu nada. Foi executada uma manipulação padrão pelo Windows. Vamos então escrever código para manipular o evento do clique do botão pelo mouse.

Dê um clique em cima do botão, selecionando-o. Agora, dê um clique na aba Events , seguido de um clique duplo no lado direito do evento OnClick:

Aparece para nós o editor de código com uma estrutura pré-criada, de tal maneira que precisamos somente escrever o código da manipulação de evento para o componente selecionado.

Você pode notar que a estrutura, comentada acima, é a seguinte:

procedure TForm1.Button1Click(Sender: TObject);begin

end;

Page 10: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 10 Todos os direitos reservados.

Isto significa dizer que, um aplicativo Windows funciona manipulando eventos externos, por exemplo os causados por uma pessoa (digitando, deslocando o mouse ou clicando um de seus botões), um outro aplicativo (quando você copia uma coisa num aplicativo e cola em outro) ou o próprio Windows (fechando o seu aplicativo por um determinado motivo, ou qualquer outra ação).

A maior parte das manipulações de evento tratadas pelo Delphi terão a seguinte estrutura básica:

procedure Tipo_Form.Nome_ComponenteNomeEvento (Sender:Tobject);begin

end;

Para finalizar: antes de executar novamente seu aplicativo, digite o código abaixo, entre as linhas begin e end; :

procedure TForm1.Button1Click(Sender: TObject);begin Close ;end;

O comando Close é o comando de fechamento de uma janela. E se essa janela for a janela principal do aplicativo, o próprio aplicativo é fechado.Execute o aplicativo novamente e dê um clique no botão. Veja que o aplicativo é encerrado e há o retorno ao IDE.

4.5. Trabalhando com duas janelas

Ao executar um aplicativo você, em determinados momentos, desejará executar ações diferentes em janelas diferentes.

Para resolver esta questão, precisamos trabalhar com dois forms no nosso projeto, sendo que um deles será o form principal e o outro o form que será "chamado" pelo primeiro form. O form principal aparecerá em primeiro lugar sempre que o aplicativo for executado, e a ele sempre se deverá retornar para uma ação inicial. Geralmente, esse form é o form que deve estar ativo para que encerremos a aplicação.

Um form pode "chamar" outro de duas maneiras: - não-modal: você pode alternar entre as janelas, clicando e selecionando tanto a

janela chamadora, como a janela chamada- modal: você só pode selecionar a janela chamadora caso você feche a janela

chamada.

Você tem diversos exemplos de janelas chamadas (invocadas) de uma das maneiras acima. Por exemplo, ao utilizar o Windows para Localizar Arquivos ou Pastas (Ferramentas-Localizar-Arquivos ou Pastas...), você pode num momento clicar sobre o Windows Explorer e torná-lo ativo, e logo após pode clicar na janela Localizar e torná-la ativa novamente. Esta é a maneira não-modal de invocar uma janela. Já para visualizar a maneira modal, clique em Ferramentas-Ir Para... e , após surgir a janela

Page 11: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 11 Todos os direitos reservados.

Ir para a Pasta tente tornar a janela do Windows Explorer ativa. Note que a ordem não é obedecida, e somente será caso você feche a janela ativa.

4.5.1. Não-Modal

Comece um novo projeto: File - New Application (Caso apareça uma janela de diálogo perguntando se você deseja salvar as alterações para o projeto Project1, clique no botão No). Você já tem em seu projeto um form (Form1)

Adicione um novo form ao seu projeto: File - New Form Visualize os Forms do projeto: View - Forms... Dê um clique sobre o nome do Form1 e depois clique em OK Adicione um botão ao Form1: clique no componente Button (vide item 4.3) da

palheta de componentes (Component Palette) Estando o botão selecionado (verifique no Object Inspector), clique na aba

Events e em seguida dê um duplo clique no lado direito do evento OnClick. Digite o comando Form2.Show; entre os comandos begin e end; como mostrado abaixo (não esqueça de separar o nome do componente Form2 do comando Show por um ponto):

procedure TForm1.Button1Click(Sender: TObject); begin Form2.Show ;end;

Execute a sua aplicação: Run - Run (item 4.1) . Ao aparecer a mensagem:

Form 'Form1' references form 'Form2' declared in unit 'Unit2' which is not in your USES list. Do you wish to add it?

Dê um clique no botão Yes e rode novamente a aplicação. Isto se faz necessário porque o projeto conhece todos os forms que fazem parte da aplicação, mas os forms não se "conhecem" individualmente. Ao invocar o Form2 a partir do Form1, você precisa "explicar ao form1: utilize o Form2 cujo código encontra-se na unit Unit2 deste projeto. A maneira correta de se fazer isto, é adicionar a cláusula USES Unit2; ao código-fonte da Unit1, e o Delphi faz isto por você automaticamente.

Aparece o Form1 (verifique o título - Caption - da janela). Dê um clique no botão: aparece agora o Form2 (verifique novamente o Caption). Dê um clique no Form1 (caso você não esteja vendo o Form1, arraste um pouco o Form2 até que você visualize o Form1). Você pode verificar também se um form é o form ativo, verificando se a sua barra de títulos (onde encontra-se o Caption) está numa cor destacada. Feche o Form2 e depois o Form1, retornando ao IDE.

4.5.2. Modal

Clique novamente no botão, selecionando-o Clique na aba Events do Object Inspector e dê um duplo clique no evento

OnClick (vamos manipular o evento OnClick de Button1) Altere o código-existente de:

Page 12: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 12 Todos os direitos reservados.

Form2.Show ;

Para (adicione a palavra Modal ao comando Show ):

Form2.ShowModal ;

Execute novamente a aplicação. Clique o botão e veja aparecer o Form2. Tente selecionar o Form1 clicando

sobre ele! Você não consegue fazê-lo, a menos que feche o Form2. Feche o Form1 para retornar ao Delphi (IDE)

4.6. Componentes Label e Edit Box

O componente Label é aquele que usamos para conter um texto curto (de uma linha geralmente) indicativo sobre um determinado botão ou ação que deva ser efetuada ou algo a ser digitado. Por exemplo, quando você utiliza o Bloco de Notas do Windows e deseja localizar determinada ocorrência de texto, você clica em Pesquisar - Localizar... e, ao surgir a janela de pesquisa você observa que, antecedendo ao local onde você deve escrever o trecho a localizar, há a palavra Localizar: . Esta palavra está contida em um componente Label e o local onde digitaremos o trecho a localizar estará contido num componente Edit Box. Vamos criar algo parecido:

File - New Application Adicione um botão ao form Manipule o evento OnClick do botão com: Form2.ShowModal Adicione um novo Form ao projeto Adicione um componente Label e um componente Edit Box ao Form2

Arraste os componentes de tal maneira que o Form fique com a aparência final abaixo:

Page 13: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 13 Todos os direitos reservados.

Apague a palavra Edit1 da

propriedade Text do componente Edit Box (cujo nome - propriedade Name - é Edit1. Não deixe a propriedade Name vazia, pois certamente o Delphi ficará perdido sem essa informação, fazendo com que você tenha que abandonar o projeto e recomeçar outro). Esta propriedade, Text, tem por função conter a palavra que aparece no componente.

Dê agora um clique no componente Label e altere a sua propriedade Caption de Label1 para Localizar: (verifique no Object Inspector se o componente ativo é o componente Label. Caso seja e você não esteja conseguindo visualizar a propriedade Caption, utilize a barra de rolagem vertical). Observe que, toda a vez que você coloca um componente no Form, a propriedade Caption ou Text, dependendo do componente, é igual ao nome do mesmo, seguido de um número que indica quantos componentes daquele tipo estão contidos naquele form. Por enquanto, nós não vamos alterar a propriedade Name dos componentes.

Execute a aplicação e dê um clique no botão: aparece o Form2. Veja que você pode selecionar e digitar o que quiser no componente Edit Box, porém o componente Label só pode ser visto, mas não pode ser alterado.

Feche o Form2 e depois o Form1, retornando ao Delphi. Manipule o evento OnDblClick do componente Edit1 com a linha de comando

seguinte (preste atenção: não há espaço em branco entre o caractere dois pontos e o sinal de igual ):

Label1.Caption := Edit1.Text ;

Execute a aplicação novamente, chame o Form2, digite alguma coisa no Edit Box e depois dê um clique duplo nele. Verifique que o Caption do componente Label1 passa a conter o mesmo que Edit1.

Feche o Form2 e depois o Form1, retornando ao Delphi.

A partir de agora, partirei do princípio que você já sabe:

Page 14: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 14 Todos os direitos reservados.

Começar uma nova aplicação: File - New Application Adicionar um componente ao Form: dê um clique no componente desejado,

selecionando-o, seguido de um clique no form. O componente aparece no form. Adicionar múltiplas cópias de um mesmo componente ao Form: mantenha a tecla

shift pressionada e dê um clique no componente desejado (o componente fica envolto por uma caixa de lados pontilhados azuis); libere a tecla shift e vá clicando no Form, nas posições onde você deseja adicionar o componente. Ao adicionar o número desejado do componente, dê um clique na seta branca (no início do component palette). Isto faz com que seja cancelada a seleção do componente.

Alterar as dimensões do componente: para os componentes que permitem tal operação, você deve dar um clique (simples) no componente, selecionando-o (o componente fica delimitado por pequenos quadrados nas suas áreas limítrofes. Quando o cursor do mouse é aproximado de um destes quadradinhos, sua forma é alterada para uma seta dupla. Neste ponto você pode, mantendo o botão esquerdo do mouse pressionado, redimensionar o componente.

Apagar um componente: dê um clique no componente, selecionando-o, e dê um toque na tecla Del (ou Delete) do teclado.

Operações em múltiplos componentes: digamos que, por exemplo, você tenha um componente Button, um componente Label e um componente Edit Box no form. Por hipótese, você deseja mover todos os componentes para a esquerda, de uma só vez. Isto se faz necessário porque digamos você deseja manter as distâncias entre os mesmos. Realize essa operação, mantendo a tecla shift pressionada, seguido de um clique em cada componente desejado. Libere a tecla shift. Os quadradinhos de delimitação ficam acinzentados. Arraste um dos componentes e observe que todos os componentes se movem. Para cancelar a seleção múltipla, dê um clique num componente não selecionado (por exemplo, no Form).Os componentes selecionados podem ser excluídos em grupo também.

Verificar o componente atualmente selecionado: vá ao Object Inspector e verifique o nome do componente na caixa de listagem (logo abaixo de onde se lê: Object Inspector).

Manipular um evento do componente: dê um clique na aba Events do Object Inspector (certifique-se que o componente selecionado é o componente desejado) e dê um clique duplo no evento correspondente, escrevendo o código necessário à sua manipulação.

4.7. Componente Image

Comece uma nova aplicação Clique na aba ADDITIONAL

Adicione o componente Image ao form

Page 15: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 15 Todos os direitos reservados.

Clique na propriedade Picture deste componente; em seguida, dê um clique no botão reticências

Aparece o Picture Editor

Clique em Load

Na caixa

Examinar: selecione uma pasta que contenha qualquer um dos arquivos de desenho (cujas extensões aparecem na caixa Arquivos do tipo:). Você pode pesquisar a pasta: DELPHI3\IMAGES\SPLASH\16COLOR, assumindo uma instalação padrão do Delphi. Clique o botão Abrir.

Clique em OK . Como a imagem é muito grande para caber no componente Image, altere a

propriedade Autosize deste componente de False para True (dê um clique na seta que se encontra ao lado direito da propriedade Autosize, e depois dê um clique em True), como mostrado abaixo:

Adicione um componente Label (aba STANDARD) ao form e altere a sua propriedade Caption com qualquer texto que você deseje.

Adicione um componente Button (aba STANDARD) ao form e, no evento OnClick, escreva o comando "Close ; ", como mostrado abaixo:

Page 16: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 16 Todos os direitos reservados.

procedure Tform1.Button1Click(Sender: Tobject);begin

Close ;end;

Execute a aplicação (Run - Run). Dê um clique no botão para fechar a aplicação (encerrar a execução).

4.8. Janela de Mensagem: ShowMessage

Comece uma nova aplicação. Adicione um botão ao form Altere o Caption do botão para MSG. Na manipulação do evento OnClick do botão, escreva:

ShowMessage ( ' Isto é uma janela de mensagem! ' ) ;

Caso aconteça um erro de compilação, tente alterar os apóstrofes (aspas simples) utilizados na delimitação do texto (utilize os mesmos apóstrofes, tanto no início, como no final do texto).

Adicione outro botão, altere o Caption para &Fechar e manipule o evento OnClick para fechar a aplicação (comando Close).

Execute a aplicação (rode o programa) e dê um clique no botão MSG. Feche a aplicação.

4.9. Janela de Mensagem: MessageDlg

Para que você possa utilizar essa janela de mensagem, você terá que digitar quatro parâmetros entre parênteses (separados por vírgula):

- Mensagem : delimitada por apóstrofes

- Tipo de janela :

mtWarning Janela de mensagem contendo um ponto de exclamação amarelo

mtError Janela de mensagem contendo um sinal de páre (STOP) vermelho.

mtInformation Janela de mensagem contendo a letra "I" azul. mtConfirmation Janela de mensagem contendo uma marca verde. mtCustom Janela de mensagem sem bitmap (figura). O

Caption da janela de mensagem, é o nome do arquivo executável da aplicação.

- Tipo de botão utilizado na janela. Selecione qual (ou quais) botão (ou botões) que aparecerá (ou aparecerão) na sua janela de mensagem:

mbYes Um botão com o texto 'Yes' na sua face

Page 17: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 17 Todos os direitos reservados.

mbNo Um botão com o texto 'No' na sua face mbOK Um botão com o texto 'OK' na sua face mbCancel Um botão com o texto 'Cancel' na sua face mbHelp Um botão com o texto 'Help' na sua face mbAbort Um botão com o texto 'Abort' na sua face mbRetry Um botão com o texto 'Retry' na sua face mbIgnore Um botão com o texto 'Ignore' na sua face mbAll Um botão com o texto 'All' na sua face

Obs1: Ao definir o tipo (ou tipos) de botão, você estará definindo, na realidade, um conjunto de botões. Caso você deseje utilizar um dos botões acima, digite o tipo desejado entre colchetes., pois o Delphi só reconhece um conjunto se os elementos do conjunto estiverem delimitados por colchetes. Caso você deseje utilizar mais de um botão na sua janela, os tipos desejados devem ser separados por vírgula.

Obs2: Os conjuntos pré-definidos abaixo dispensam a utilização de colchetes (por serem eles próprios um conjunto):

mbYesNoCancel Coloca os botões Yes, No e Cancel na janela de mensagem

mbOkCancel Coloca o botão OK e Cancel na janela de mensagem

mbAbortRetryIgnore Coloca os botões Abort, Retry e Ignore na janela de mensagem

- HelpCtx : ligação (link) ao tópico de ajuda. Caso não haja ajuda (e no nosso caso não há), utilize o parâmetro 0 (zero).

Vamos então testar algumas janelas de mensagem:

Comece uma nova aplicação Coloque cinco botões no form Altere os caption para: Aviso , Erro , Informação , Confirmação e Fechar Manipule o evento OnClick dos botões da seguinte forma:

botão Aviso: MessageDlg ('Aviso' , mtWarning , [mbOK] , 0 ) ; botão Erro : MessageDlg ('Erro' , mtError , [mbRetry,mbCancel] , 0 ) ; botão Informação: MessageDlg ('Informação' , mtInformation , [mbOK] , 0 ) ; botão Confirmação: MessageDlg ('Confirmação' , mtConfirmation, mbOKCancel , 0 ) ; botão Fechar: MessageDlg ('Fechar' , mtCustom, [mbYes] , 0 ) ;

Obs3.: Mais uma vez: no botão Confirmação, mbOKCancel não está delimitado por colchetes por ser ele próprio um conjunto pré-definido.

4.10. Componente Timer

O componente Timer (aba System do Component Palette) gera uma chamada ao seu aplicativo em intervalos de tempo programáveis, como se fosse um despertador.

Page 18: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 18 Todos os direitos reservados.

Vamos construir um relógio simples, que mostra, a cada segundo, a hora correta. Para isso, necessitaremos de um componente Label (o relógio mostrará a hora; não faz sentido deixar o usuário escrever algo diferente da informação que é mostrada. Você pode ver um relógio idêntico na barra de tarefas do Windows), além de um componente Timer, programado para gerar eventos OnTimer a cada 1000 ms (1000 ms = 1s). A função NOW retorna a data e a hora do sistema operacional e TimeToStr formatará o valor de retorno de NOW para gerar um conjunto de caracteres representando a hora.

File - New Application Adicione um componente Label e um componente Timer (aba System) ao Form1

Com o componente Timer1 selecionado (verifique no Object Inspector; caso não seja o componente Timer1, dê um clique simples sobre ele, selecionando-o), verifique se a sua propriedade Enabled está em True e a propriedade Interval está com o valor 1000, como abaixo:

Agora,

precisamos manipular seu evento OnTimer. Clique na aba Events do Object Inspector e

Page 19: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 19 Todos os direitos reservados.

dê um clique duplo no lado direito do evento (que é o único evento que um componente Timer pode gerar), escrevendo o código

Label1.Caption := TimeToStr (NOW) ;

como mostrado abaixo (preste atenção: não há espaço em branco entre o caractere dois pontos e o sinal de igual ):

procedure Tform1.Timer1Timer(Sender: Tobject);begin Label1.Caption := TimeToStr (NOW) ;end;

Execute o aplicativo e veja a cada segundo o relógio sendo atualizado. Feche a janela

5. Linguagem Pascal

Page 20: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 20 Todos os direitos reservados.

Para desenvolver aplicativos em Delphi, precisamos conhecer o Object Pascal, que é baseada na linguagem Pascal com adições inerentes ao ambiente Windows.

5.1. Estrutura básica de um programa Delphi

Basicamente, nós iremos manipular os eventos dos objetos que componham nosso projeto. Não todos, mas somente aqueles que forem necessários.

A cada instante, o usuário poderá clicar (com o mouse) sobre um determinado form, ou um objeto nesse form, ou chamar um outro form, ou mesmo fechá-lo. Ao mesmo tempo que isso possa estar acontecendo, o form pode estar recebendo um evento OnTimer, além de "n" outras situações possíveis dentro do ambiente Windows.

Aqui então iremos considerar a estrutura mais simples possível, que é aquela utilizada pela rotina tratadora do evento do objeto considerado.

Para manipular um evento, o Delphi faz uso de uma pequena rotina, dentro de uma rotina maior, que chamamos de programa principal, isto é, o programa principal chama, a cada geração de evento, a rotina correta para tratar aquele evento. Assim, quando você dá o clique duplo no lado direito do evento do componente, aparece uma estrutura semi-montada com a palavra reservada procedure:

procedure Tnome_Form.Nome_Componente_Nome_Evento (Sender : Tobject) ;beginend ;

Esta pequena estrutura segue a estrutura básica de um programa Pascal e, sendo assim, poderemos utilizar a estrutura descrita abaixo:

procedure Tnome_Form.Nome_Componente_Nome_Evento (Sender : Tobject) ;Const

Const1 = Valor1 ;Const2 = Valor2 ;

TypeTipo1 = Tipo_ObjectPascal1_Modificado ;Tipo2 = Tipo_ObjectPascal2 _Modificado ;

VarVar1 : Tipo1 ;Var2 : Tipo2 ;Var3 : Tipo3 ;

beginComando1 ;Comando2 ;

ComandoN ;end ;

5.2. Constantes

Page 21: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 21 Todos os direitos reservados.

São símbolos (nomes) que você associa a valores (numéricos, letras, etc.), e que se tornam invariáveis durante a execução da procedure, ou seja, uma vez que eu associe a constante ao valor desejado, não poderá haver entre os comandos begin e end qualquer alteração no valor do símbolo em questão, e ele sempre valerá o que foi definido na cláusula Const. Caso você queira alterar esse valor, precisará editar o código-fonte e recompilar o programa. Por exemplo, a seguir foi associado o valor 1000 à constante Num_Maximo_Dados:

ConstNum_Maximo_Dados = 1000 ;

Sempre finalize a declaração de uma constante com o caractere ponto-e-vírgula (; ). Você poderá utilizar a constante, dentro do seu programa, em substituição ao

valor numérico 1000. Imagine a hipótese de você ter a manipulação de um evento com 550 linhas, e que destas 550 linhas, 43 linhas referem-se à impressão do valor 1000. Caso você queira alterar esse valor para 3900, precisará alterar as 43 linhas do código-fonte que fazem referência ao valor 1000. Caso você trabalhe com a constante Num_maximo_Dados, precisará alterar apenas a linha

ConstNum_Maximo_Dados = 1000 ;

para,

ConstNum_Maximo_Dados = 3900 ;

o que certamente lhe trará flexibilidade e rapidez.

5.3. Tipos

Para que você possa utilizar valores não-constantes no seu programa (que estão armazenados na memória RAM de seu computador), você precisa declarar variáveis de memória, ou simplesmente, variáveis, que são os símbolos que permitem a você manipular um determinado valor de acordo com certas características. Por exemplo, você precisa ter uma variável para armazenar idades de pessoas. Essa variável conterá, então, um valor numérico que poderá ser incrementado de 1 unidade ou diminuído de outro valor , etc. , coisas que são relativas a valores numéricos. Você poderia querer utilizar outra variável para armazenar nomes pessoais. Nesse caso, não convém operar aritmeticamente sobre os dados. Ou seja, na etapa de criação de um programa, você desejará declarar quantas variáveis forem necessárias para resolver o problema proposto. E cada variável desta terá um tipo de comportamento correspondente. Podemos definir as características de uma variável pela definição de seu tipo.

5.3.1. Tipos Ordinais: têm predecessor e sucessor

Page 22: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 22 Todos os direitos reservados.

Numéricos:

- ShortInt : -128 .. 127 sinal : 8 bits- SmallInt (ou Integer) : -32768 .. 32767 sinal : 16 bits- LongInt : -2147483648 .. 2147483647 sinal : 32 bits- Byte : 0 .. 255 sem sinal : 8 bits- Word : 0 .. 65535 sem sinal : 16 bits

Char (caracter):

- AnsiChar (ou Char) : conjunto de caracter ANSI sem sinal : 8 bits- WideChar : conjunto de caracter UNICODE sem sinal : 16 bits

Obs1.: Todo caractere em Pascal deve estar delimitado por apóstrofe ( ' ).

Obs2.: Os 256 primeiros caracteres do conjunto UNICODE correspondem aos caracteres do conjunto ANSI.

Enumerados:

Tipos enumerados definem conjuntos de valores que enumeram os identificadores que denotam esses valores. Por exemplo, podemos criar o tipo enumerado Cartao com os valores: CREDICARD, AMEX, VISA, OUTROS, associando-os pelo sinal de igual, como mostrado abaixo:

Type Cartao = (CREDICARD, AMEX, VISA, OUTROS) ;

Sendo que CREDICARD é uma constante do conjunto Cartao. Mais tarde construiremos uma aplicação que faz uso de tipos enumerados.

Boolean:

Tipos que somente contém dois valores: True (verdadeiro) e False (falso).

SubRange:

Tipos que somente contém os valores delimitados pelos valores inicial e final separados por dois pontos ( . . ) , indicando tratar-se de um limite, que tem como base o tipo chamado hospedeiro (ou tipo host), que deve ser do tipo ordinal.

Por exemplo, se você declara o seguinte tipo:

Typeidade = 1 .. 90 ;

Significa que o tipo idade é um conjunto de valores Byte dentro do limite inicial 1 e limite final 90.5.3.2. Tipo Real: contêm um subconjunto do conjunto dos números reais

Page 23: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 23 Todos os direitos reservados.

- Real : 2.9 x 10-39 .. 1.7 x 1038 sinal: 6 bytes

Obs1.: O tipo Real foi mantido devido à compatibilidade com o Delphi 1 e o Turbo Pascal

- Single : 1.5 x 10-45 .. 3.4 x 1038 sinal: 4 bytes- Double : 5.0 x 10-324 .. 1.7 x 10308 sinal: 8 bytes- Extended : 3.4 x 10-4932 .. 1.1 x 104932 sinal: 10 bytes- Comp : -263 + 1 .. 263 + 1 sinal: 8 bytes- Currency : -922337203685477.5808 .. 922337203685477.5807 sinal: 8 bytes

Obs2.: Nas nossas aplicações, utilizaremos o tipo Extended para valores com casas decimais.

5.3.3. Tipo String: cadeia de caracteres

Strings servem para armazenar caracteres alfanuméricos e simbólicos, de maneira mista ou não. Isto dependerá da sua necessidade no momento. Toda string em Pascal deve ser delimitada pelo caractere apóstrofe. Exemplos de string são:

'Curso de Delphi - Professor José Luiz A. Rosa - 1998''Delphi é um Ambiente Visual que Utiliza Pascal Orientado a Objeto!' '20.541-130'

Observe que a terceira string contém, não uma operação aritmética (subtração de dois valores numéricos), mas um código de CEP (dos Correios).

Assim sendo, strings servem também para armazenar números que não necessitam de operações aritméticas, como CEP, CPF, CGC, etc., onde os caracteres não-numéricos são utilizados apenas para formatação.

O Delphi suporta três tipos de strings: ShortString , AnsiString e WideString .

- ShortString : string estática e comprimento máximo de 255 caracteres. É mantido por razões de compatibilidade com o Delphi1.

- AnsiString : string dinamicamente alocada com um comprimento máximo limitado somente pela memória disponível.

Obs1.: Quando você declara uma variável como sendo do tipo String, na realidade você está declarando uma variável AnsiString (vide no Help a diretiva de compilação $H).

- WideString : string dinamicamente alocada com um comprimento máximo limitado somente pela memória disponível. Utiliza 16 bits de representação (caracteres UNICODE). A versão 32-bits de OLE utiliza UNICODE para todas as strings.

Obs2.: Várias propriedades são do tipo string, como, por exemplo, a propriedade Caption do form ou do componente Label e a propriedade Text do componente Edit Box.

5.4. Variáveis

Page 24: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 24 Todos os direitos reservados.

Já lhe foi dito que para manipular valores no seu programa (que estão armazenados na memória RAM de seu computador), você precisa declarar variáveis de memória, ou simplesmente, variáveis, que são os símbolos que permitem a você manipular um determinado valor de acordo com certas características.

Como você já estudou também alguns dos tipos disponíveis no Object Pascal, chegou a hora de se declarar as variáveis.

Isto pode ser feito na seção de declaração de variáveis, logo após a palavra reservada Var .

Por exemplo, abaixo você vê a declaração de 6 variáveis:

VarA : Integer ;B , C : Real ;D , E , F : Boolean ;G : String ;

A variável de nome A é do tipo inteiro; as variáveis B e C são reais; as variáveis D, E e F são Boolean (variáveis lógicas - só aceitam os valores True e False) e a variável G é string.

Você pode utilizar as estruturas estudadas acima para auxiliar na declaração das variáveis. Por exemplo, caso você deseje declarar uma variável de nome Taxa que, por um motivo qualquer somente necessite armazenar valores entre 10 e 100, você faria como:

Type

Limite = 10 .. 100 ;Var

Taxa : Limite ;

O que é idêntico a:

Var

Taxa : 10 .. 100 ;

Assim feito, a variável Taxa é uma variável ordinal (inteira) que somente armazena valores entre 10 e 100 (vide no Help a diretiva de compilação $R).

5.5. Operadores

Page 25: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 25 Todos os direitos reservados.

Declaradas todas as constantes, tipos e variáveis de que você necessita, precisamos saber agora como manipular esses valores dentro do programa.

Na realidade, já utilizamos o operador atribuição ( := ) em exemplos anteriores, quando por exemplo você atribuiu ao Caption de Label1 a hora retornada pela função NOW, ou quando você atribuiu ao Caption de Label1, o conteúdo da propriedade Text do componente Edit Box.

5.5.1. Operadores Aritméticos

5.5.1.1. Binários (requerem dois operandos para sua execução)

Operador Operação Operandos Tipo de Resultado+ Adição inteiro + inteiro inteiro

inteiro (ou real) + real real- Subtração inteiro - inteiro inteiro

inteiro (ou real) - real real* Multiplicação inteiro * inteiro inteiro

inteiro (ou real) * inteiro (ou real) real/ Divisão (real) inteiro / inteiro real

inteiro (ou real) / real realdiv Divisão (inteira) inteiro div inteiro inteiromod Resto da Divisão (inteira) inteiro mod inteiro inteiro

5.5.1.2. Unários (requerem um operando apenas para sua execução)

Operador Operação Operandos Tipo de Resultado+ Identificador de sinal + inteiro inteiro

+ real real- Negativação - inteiro inteiro

- real real

5.5.2. Operadores Bitwise (operação a nível de bits - bitwise operations)

Operador Operação Operandos Tipo de Resultadonot Negação (unário) not inteiro inteiroand Lógica "e" inteiro e inteiro inteiroor Lógica "ou" inteiro or inteiro inteiroxor Lógica "ou-exclusivo" inteiro xor inteiro inteiroshl Rotação (shift) à esquerda inteiro shl inteiro inteiroshr Rotação (shift) à direita inteiro shr inteiro inteiro

5.5.3. Operadores Lógicos

Page 26: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 26 Todos os direitos reservados.

Operador Operação Operandos Tipo de Resultadonot Inversão (unário) not lógico lógicoand Lógica "e" lógico e lógico lógicoor Lógica "ou" lógico or lógico lógicoxor Lógica "ou-exclusivo" lógico xor lógico lógico

5.5.4. Operador de String

Operador Operação Operandos Tipo de Resultado+ Concatenação char (ou string) + char (ou string) string

5.5.5. Operadores Relacionais

Operador Operação Operandos Tipo de Resultado= Igual tipo = mesmo tipo lógico

<> Diferente (não igual) tipo <> mesmo tipo lógico< Menor que tipo < mesmo tipo lógico> Maior que tipo > mesmo tipo lógico

<= Menor que ou igual a tipo <= mesmo tipo lógico>= Maior que ou igual a tipo >= mesmo tipo lógico

5.6. Exemplos

- 10 + 5 resulta 15- 10.0 + 5 resulta 15.0- 10.0 + 5.0 resulta 15.0- 10 * 5 resulta 50- 10 * 5.0 resulta 50.0- 10 / 5 resulta 2.0- 10.0 / 5 resulta 2.0- 10 div 3 resulta 3 (pois: 10 3 )

1 3

- 10 mod 3 resulta 1 (pois: 10 3 )1 3

- not True resulta False

- 11010010 and 00110001 resulta 00010000- 11010010 or 00110001 resulta 11110011

- 'Alô ' + 'Você!' resulta 'Alô Você!'- '012345678' + '9' resulta '0123456789'

5.7. Execução Condicional

Page 27: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 27 Todos os direitos reservados.

5.7.1. IF / THEN / ELSE

Sintaxe:IF <condição> THEN

begincomando11 ;

comando12 ;

comando1N ;end

ELSEbegin

comando21 ;comando12 ;

comando2N ;end ;

Isto significa que: se (IF) a condição ( <condição> ) é verdadeira (True) então ( THEN ) todos os comandos "1i" (i =1,2,..,N) entre o primeiro bloco begin / end são executados; senão ( ELSE ) se (IF) a condição ( <condição> ) é falsa todos os comandos "2i" (i =1,2,..,N) entre o segundo bloco begin / end são executados.

Obs1.: O bloco de comandos entre o begin e o end pode ser constituído somente de um único comando. Neste caso, o uso do begin / end é opcional.

Obs2.: O uso da cláusula ELSE é opcional. Caso não seja utilizada e a condição entre o IF e o THEN resulte num valor lógico False, nenhum comando é executado.

Obs3.: A prática de se escrever estruturas hierarquicamente inferiores a outras é chamada de IDENTAÇÃO, e serve apenas para melhorar a visibilidade do seu código-fonte, nada afetando em termos de performance do compilador.

Obs4.: Cada linha de comando é separada de outra pelo caractere ponto-e-vírgula, conforme mostrado acima. No entanto, não se pode utilizar ponto-e-vírgula antes de um comando ELSE, sob pena de o compilador acusar erro de "statement" (erro na estrutura).

Obs5.: Comandos If sucessivos podem ser "aninhados", ou seja, o bloco de comandos que segue o Then pode ser um outro comando If, e assim sucessivamente. Isto se faz necessário, quando precisamos após uma primeira filtragem, executar processamentos diferentes. Por exemplo, após selecionar todos os funcionários que têm matrícula começando pelo caractere ' v ' (funcionários da seção de vendas), somente receberão aumento de 10% no salários os que ganhem menos de 500,00 e de 7.5% os que ganhem mais de 500,00.

Page 28: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 28 Todos os direitos reservados.

No exemplo abaixo, atribuiremos o valor 10 à variável A e compararemos o conteúdo dessa variável ao valor 10. Como eles são iguais, a variável B receberá o valor True; caso eles fossem diferentes, a variável C receberia 'São diferentes':

VarA : Integer ;B : Boolean ;C : String ;

beginA := 10 ;If A = 10 Then { Compara o conteúdo da variável A com o valor 10 }

B := TrueElse

C := 'São diferentes' ;

Obs6.: O texto entre chaves é um comentário do programador, sendo ignorado pelo compilador (não é compilado).

No exemplo abaixo, construiremos uma calculadora.

Comece uma nova aplicação Coloque dois componentes Label no form Altere o Caption do primeiro para Calculadora e o Caption do segundo para = Coloque quatro componentes Edit Box , os alinhe (utilize os pontinhos do form)

pelo topo e apague a propriedade Text dos quatro, deixando-as em branco Coloque um botão no form e altere seu Caption para &Operar

A aparência do form deve ser a seguinte:

Você deverá entrar com um valor numérico inteiro no primeiro Edit Box (Edit1), com um operador aritmético no segundo Edit Box (Edit2), com outro valor numérico inteiro no terceiro Edit Box (Edit3) e dar um clique no botão, verificando o resultado da operação no quarto Edit Box.Mas antes de executar a nossa aplicação, vamos continuar com a nossa tarefa.

Page 29: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 29 Todos os direitos reservados.

Manipule o evento OnClick de Button1 com a linha de comando abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var N1, N2 : Integer ;begin N1 := StrToInt (Edit1.Text) ; N2 := StrToInt (Edit3.Text) ; If Edit2.Text = '+' Then { Se o operador for igual a + }

Edit4.Text := IntToStr (N1 + N2) {Soma os números} Else {Senão, se não for igual a +}If Edit2.Text = '-' Then { Se for igual a - }

Edit4.Text := IntToStr (N1 - N2) {Subtrai}Else {Senão, se não igual a -}

If Edit2.Text = '*' Then {Se for igual a *}Edit4.Text := IntToStr (N1 * N2) {multiplica}

Else {Senão, se não for igual a *}If Edit2.Text = '/' Then {divide}

Edit4.Text := IntToStr (N1 div N2);end;

Obs7.: Como N1 é uma variável do tipo inteiro e Text é uma propriedade do tipo String, antes de efetuar a atribuição do valor contido em Text à variável N1, precisamos convertê-lo de String para Integer (é óbvio que a string a ser convertida somente deverá conter caracteres numéricos). A função StrToInt converte a string (Str) entre seus parênteses para (To) o valor inteiro (Int) correspondente. A mesma explicação se aplica à variável N2.Processo inverso (IntToStr) é efetuado para atribuir o resultado numérico da operação aritmética entre os dois operandos (N1 e N2) para a propriedade Text de Edit4.

Execute a aplicação, digite o valor 10 no primeiro Edit Box, digite o operador de divisão encontrado em máquinas de calcular ( / ) no segundo Edit Box e digite 7 no terceiro Edit Box. Dê um clique no botão Operar ou tecle Alt-O e veja que aparece o valor 1 no quarto Edit Box (resultante da divisão inteira de 10 por 7).

Altere o operador (no segndo Edit Box) para * e clique o botão Operar. Veja que o quarto Edit Box passa agora a conter 70.

Apague o conteúdo do quarto Edit Box e altere o conteúdo do segundo Edit Box de * para @ e clique o botão Operar. Veja que nada aconteceu. Como a manipulação OnClick do botão Operar efetua a adição se Edit2.Text for igual a '+' , subtrai se Edit2.Text for igual a '-', multiplica se Edit2.Text for igual a '*' e divide (divisão inteira) se Edit2.Text for igual a '/', mas nada diz a respeito (não contém cláusula ELSE) caso o operador não seja um desses quatro citados, nada acontece, pois nenhum comando é executado.

Obs8.: É óbvio que poderíamos cercar todas as possibilidades com comandos IF/THEN/ELSE. Mas o programa ficaria por demais complexo, com uma identação que tenderia a ultrapassar o limite do editor de textos do Delphi. Poderia você me perguntar se é obrigatório utilizar identação.

Page 30: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 30 Todos os direitos reservados.

Não, não é obrigatório, mas verifique abaixo o mesmo código com e sem identação:

- Com identação:

procedure TForm1.Button1Click(Sender: TObject);Var N1, N2 : Integer ;begin N1 := StrToInt (Edit1.Text) ; N2 := StrToInt (Edit3.Text) ; If Edit2.Text = '+' Then

Edit4.Text := IntToStr (N1 + N2) Else

If Edit2.Text = '-' ThenEdit4.Text := IntToStr (N1 - N2)

ElseIf Edit2.Text = '*' Then

Edit4.Text := IntToStr (N1 * N2)Else

If Edit2.Text = '/' ThenEdit4.Text := IntToStr (N1 div N2);

end;

- Sem identação:

procedure TForm1.Button1Click(Sender: TObject);VarN1, N2 : Integer ;beginN1 := StrToInt (Edit1.Text) ;N2 := StrToInt (Edit3.Text) ;If Edit2.Text = '+' ThenEdit4.Text := IntToStr (N1 + N2)ElseIf Edit2.Text = '-' ThenEdit4.Text := IntToStr (N1 - N2)ElseIf Edit2.Text = '*' ThenEdit4.Text := IntToStr (N1 * N2)ElseIf Edit2.Text = '/' ThenEdit4.Text := IntToStr (N1 div N2);end;

E responda qual o código que é mais legível?

Page 31: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 31 Todos os direitos reservados.

5.7.2. CASE / OF

Sintaxe:CASE <variável_ordinal> OF

valor1 : comando1 ;

valor2 : begincomando21 ;

comando22 ;

comando2N ;end ;

valorN : begincomandoN ;

end

ELSE

begincomandoE1 ;

comandoE2 ;

comandoEN ;end ;

END ;

Isto significa que: caso (CASE) o valor da variável ordinal ( <variável_ordinal> ) seja igual a ( OF ): valor1 execute o comando1

valor2 execute os comandos entre o bloco begin / end (comando21, comando22, ... ,comando2N)valorN execute o comandoN

Caso não seja nenhum dos valores acima (ELSE), execute todos os comandos "Ei" (i =1,2,..,N) entre o último bloco begin / end .

Obs1.: O primeiro valor que satisfaça a igualdade proposta (valor este que seja igual à variável ordinal) é executado, finalizando-se o comando CASE / OF (END do CASE).

Obs2.: O uso da cláusula ELSE é opcional. Caso não seja utilizada e nenhum dos valores de teste seja igual ao da variável ordinal, nenhum comando é executado.

Obs3.: Note que o comando CASE / OF possui um comando END; finalizador .

Obs4.: Note a IDENTAÇÃO aqui utilizada.

Page 32: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 32 Todos os direitos reservados.

Obs5.: Você pode comparar a variável ordinal com qualquer valor ordinal, ou com qualquer variável ordinal (cujo tipo seja compatível, por exemplo, variável ordinal do tipo Integer e valor - ou outra variável ordinal - do tipo Byte, desde que os valores máximo e mínimo dos tipo utilizados seja respeitado)

Obs6.: Você também pode comparar a variável ordinal com um conjunto de valores ordinais ou com um limite de valores também ordinal. Por exemplo, caso você queira comparar uma variável ordinal com os valores 1, 2 , 3 e 57 , faça como abaixo:

CASE <variável_ordinal> OF

1, 2, 3, 57 : comando1 ;

Caso essa comparação seja com um limite ininterrupto de valores, como, por exemplo, de 1 a 100, de 1 em 1 (1, 2, 3, 4, 5, 6, 7, ..., 98, 99, 100), utilize os dois

pontos ( .. ) para definir um subrange (limite) ordinal, como mostrado abaixo:

CASE <variável_ordinal> OF

1 .. 100 : comando1 ;

Obs7.: O bloco de comandos entre o begin e o end pode ser constituído somente de um único comando, como nos casos dos valores "valor1" e "valorN". Neste caso, o uso do begin / end é opcional (aqui foram utilizados os comandos begin e end em "valorN" apenas para efeito didático, podendo, como já foi dito, ser retirados).

Reescreva o exemplo anterior (da calculadora) com o comando Case:

procedure TForm1.Button1Click(Sender: TObject);Var

N1, N2 : Integer ;Operador : Char ;

beginN1 := StrToInt (Edit1.Text) ;N2 := StrToInt (Edit3.Text) ;Operador := Edit2.Text [1] ; {Atribua à variável Operador, o primeiro

caractere da String contida em Edit2.Text}Case Operador Of

'+' : Edit4.Text := IntToStr (N1 + N2) ;'-' : Edit4.Text := IntToStr (N1 - N2) ;'*' : Edit4.Text := IntToStr (N1 * N2) ;'/' : Edit4.Text := IntToStr (N1 Div N2) ;

End ;end;

Obs8.: Utilizamos uma variável do tipo Char porque o tipo String não é tipo ordinal.

Page 33: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 33 Todos os direitos reservados.

5.8. Execução de Repetição

5.8.1. FOR / DO

Sintaxe:FOR variável_ordinal_numérica := valor_inicial TO valor_final DO

begincomando1 ;

comando2 ;

comandoN ;end ;

Isto significa que: a variável ordinal recebe (:= ) um valor (numérico) inicial e, se esse valor for menor ou igual ao valor final, todos os comandos entre o bloco begin / end são executados; ao final dessa primeira execução, a variável ordinal é incrementada de 1 unidade e, se o seu valor após o incremento for menor ou igual ao valor final, todos os comandos entre o bloco begin / end são novamente executados; ao final dessa segunda execução, a variável ordinal é incrementada de 1 unidade e, se o seu valor após o incremento for menor ou igual ao valor final, todos os comandos entre o bloco begin / end são novamente executados; e assim por diante, até que o valor da variável ordinal seja maior do que o valor final

Obs1.: O bloco de comandos entre o begin e o end pode ser constituído somente de um único comando. Neste caso, o uso do begin / end é opcional.

Obs2.: Se o valor inicial for maior do que o valor final nada é executado. Porém, caso você precise utilizar um decremento ao invés de um incremento, altere o TO por DOWNTO (observe o comentário no programa do exemplo abaixo). Neste caso o valor inicial deve ser maior do que o valor final para o bloco ser executado. A cada passo, o valor da variável ordinal é decrementado de 1 unidade.

Por exemplo, vamos criar uma tabela de conversão de centímetros (cm) para polegadas (pol) , sendo: 2,54 cm = 1 pol .

Comece uma nova aplicação Coloque no Form, um componente Memo (aba Standard):

Page 34: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 34 Todos os direitos reservados.

Adicione um botão ao Form

Manipule o evento OnClick deste botão com o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var

Pol : Integer ;Cm : Extended ;Valor : String ;

beginFor Pol := 1 To 100 Do {Para decrementar use: For Pol := 100 DownTo 1 Do }

beginCm := 2.54 * Pol ;Valor := IntToStr (Pol ) + ' = ' + FloatToStr ( Cm ) ;Memo1.Lines.Append ( Valor ) ;

end ;end;

Execute a aplicação, clique o botão e, depois de examinar a tabela de valores convertidos, feche a aplicação.

Um componente Memo tem uma propriedade chamada Lines, que contém linhas de strings. Você pode adicionar strings ao componente Memo em tempo de execução, através do comando Append, como no código acima:

Memo1.Lines.Append ( Valor ) ;

O comando Append irá adicionar uma string ao final da lista de strings do componente Memo. No caso estudado, temos a concatenação de três valores:

a. A string resultante da conversão do valor inteiro contido na variável Cmb. A string ' = ' (caractere espaço, caractere igual, caractere espaço)c. A string resultante da conversão do valor real (Float) contido na variável Pol

Você pode inicializar a sua aplicação sem a palavra Memo1 da tabela. Para isto, utilize

o String List

Page 35: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 35 Todos os direitos reservados.

Editor, clicando no botão reticências da propriedade Lines do componente Memo1 (apague a palavra Memo1 e clique em OK):

5.8.2. WHILE / DO

Sintaxe:WHILE <condição> DO

begincomando1 ;

comando2 ;

comandoN ;end ;

Isto significa que: enquanto (WHILE ) a condição ( <condição> ) for verdadeira faça ( DO ) a execução de todos os comandos entre o bloco begin / end; ao final dessa primeira execução, o programa retorna para testar novamente a condição e, se ela resultar em True (continuar verdadeira) , todos os comandos entre o bloco begin / end são novamente executados; e assim por diante, até que a condição seja falsa.

Obs1.: O bloco de comandos entre o begin e o end pode ser constituído somente de um único comando. Neste caso, o uso do begin / end é opcional.

Obs2.: Se a condição resultar inicialmente em False (seja uma condição falsa), nenhum comando é executado.

Obs3.: Apesar do comando Break quebrar a execução de um loop While / Do (bem como do loop For / Do), é uma boa prática evitá-lo, sob pena de você perder o controle do seu programa. Utilize-o somente em ocasiões muito especiais, onde não puder ser evitado, o que é difícil de acontecer, pois um comando If / Then aninhado dentro do comando While / Do resolve boa parte dos nossos problemas de execução indesejada.

Por exemplo, vamos refazer a tabela de conversão de centímetros (cm) para polegadas (pol) , sendo: 2,54 cm = 1 pol .

Comece uma nova aplicação Coloque no Form, um componente Memo (aba Standard):

Page 36: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 36 Todos os direitos reservados.

Adicione um botão ao Form Manipule o

evento OnClick deste botão com o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var Pol : Integer ; Cm : Extended ; Valor : String ;begin

Pol := 1 ; While Pol <= 100 Do begin Cm := 2.54 * Pol ; Valor := IntToStr (Pol ) + ' = ' + FloatToStr ( Cm ) ; Memo1.Lines.Append ( Valor ) ;

Pol := Pol + 1 ; end ;end;

Execute a aplicação, clique o botão e, depois de examinar a tabela de valores convertidos, feche a aplicação.

Obs4.: Observe que a variável utilizada como controle (Pol) é inicializada com 1 e, depois da execução de todos os comandos do loop, a variável tem seu conteúdo antigo incrementado de 1, antes que o controle retorne ao teste da condição. Isto se faz necessário para evitar um "loop infinito", que é aquele que não acaba nunca, devido à condição sempre resultar verdadeira.

Obs5.: O comando While / Do não exige que a condição seja ordinal (nem muito menos numérica). Qualquer condição que resulte em um valor True (verdadeiro) ou False (falso) serve como condição para este comando. Assim sendo, examine o trecho de programa abaixo:

VarOp : Char ;

beginOp := 'S' ;While Op = 'S' Do {Enquanto a variável Op for igual a 'S' faça}

begin {Início do bloco}

Page 37: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 37 Todos os direitos reservados.

If MessageDlg ('Deseja Continuar?',mtInformation, [mbYes,mbNo],0) = mrNo Then Op := 'N'

end ; {Fim do bloco}end;

A seguinte pergunta é feita na execução da condição: Op é igual a 'S'. Isto é verdadeiro (True) ou é falso (False)? Se for True executa o bloco; se for False, pula todo o bloco e executa o(s) comando(s) após o end do bloco .

5.8.3. REPEAT / UNTIL

Sintaxe:REPEAT

comando1 ;comando2 ;

comandoN ;

UNTIL <condição> ;

Isto significa que: repita (REPEAT) todos os comandos que seguem (entre o REPEAT e o UNTIL) até (UNTIL) que a condição ( <condição> ) seja verdadeira.

Obs1.: Como o bloco de comandos inicia com o comando REPEAT e termina com o comando UNTIL, se faz desnecessário utilizar os comandos begin e end.

Obs2.: Todos os comandos serão executados pelo menos uma vez, mesmo que a condição resulte inicialmente em True (seja uma condição verdadeira).

Obs3.: Observe que a lógica de teste da condição para o comando Repeat / Until é contrária à logica da condição para o comando While / Do.

Obs4.: Apesar do comando Break quebrar a execução de um loop Repeat / Until (bem como do loop For / Do ou do loop While / Do), é uma boa prática evitá-lo, sob pena de você perder o controle do seu programa. Utilize-o somente em ocasiões muito especiais, onde não puder ser evitado, o que é difícil de acontecer, pois um comando If / Then aninhado dentro do comando Repeat / Until resolve boa parte dos nossos problemas de execução indesejada.

Por exemplo, vamos refazer a tabela de conversão de centímetros (cm) para polegadas (pol) , sendo: 2,54 cm = 1 pol .

Comece uma nova aplicação Coloque no Form, um componente Memo (aba Standard):

Page 38: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 38 Todos os direitos reservados.

Adicione um botão ao Form Manipule o

evento OnClick deste botão com o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var Pol : Integer ; Cm : Extended ; Valor : String ;begin

Pol := 1 ; Repeat Cm := 2.54 * Pol ; Valor := IntToStr (Pol ) + ' = ' + FloatToStr ( Cm ) ; Memo1.Lines.Append ( Valor ) ;

Pol := Pol + 1 ;Until Pol > 100 ;

end;

Execute a aplicação, clique o botão e, depois de examinar a tabela de valores convertidos, feche a aplicação.

Page 39: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 39 Todos os direitos reservados.

Obs5.: Observe que a variável utilizada como controle é inicializada com 1 e, depois da execução de todos os comandos do loop, a variável tem seu conteúdo antigo incrementado de 1, antes que o controle vá ao teste da condição. Isto se faz necessário para evitar um "loop infinito", que é aquele que não acaba nunca, devido à condição sempre resultar falsa (neste caso).

Obs6.: O comando Repeat / Until não exige que a condição seja ordinal (nem muito menos numérica). Qualquer condição que resulte em um valor True (verdadeiro) ou False (falso) serve como condição para este comando. Assim sendo, examine o trecho de programa abaixo:

VarOp : Char ;

beginOp := 'S' ;Repeat { repita todos os comandos abaixo}

If MessageDlg ('Deseja Continuar?',mtInformation, [mbYes,mbNo],0) = mrNo Then Op := 'N'

Until Op = 'N' {até que Op seja igual a 'N'} end;

A seguinte pergunta é feita na execução da condição: Op é igual a 'N'. Isto é verdadeiro (True) ou é falso (False)? Se for True finaliza a repetição; se for False, retorna ao comando Repeat e reinicia a execução dos comandos.

5.9. Componente StringGrid

Comece uma nova aplicação Coloque um StringGrid (aba Additional) e um botão (aba Standard) no Form

Page 40: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 40 Todos os direitos reservados.

Altere (no Object Inspector) as propriedades abaixo:

Botão (Button1):

Caption : Contador

StringGrid (StringGrid1):

Name : sgTabColCount : 6RowCount : 6

Reposicione e redimensione SgTab (o novo nome de StrinGrid1) de tal maneira que todas as células fiquem visíveis na tela (não apareça barra de rolamento alguma)

Obs1.: Para dar ajustes finos, você pode trabalhar com as setas de posicionamento do cursor (no seu teclado) e as teclas Shift e Ctrl.Mantendo a tecla Shift pressionada e pressionando uma das setas, você poderá redimensionar o seu componente.Mantendo a tecla Ctrl pressionada e pressionando uma das setas, você poderá reposicionar o seu componente.

Manipule o evento OnClick de Button1 com o seguinte código:

procedure TForm1.Button1Click(Sender: TObject);Var

Col : Byte ;begin

For Col := 1 To 5 DosgTab.Cells [Col,1] := IntToStr (Col) ;

end;

Obs2.: Observe a propriedade Cells de sgTab (o novo nome do componente StringGrid). Esta propriedade possui a string contida na célula cuja coluna no grid é o primeiro parâmetro e cuja linha no grid é o segundo parâmetro. Isto significa dizer que, nem todas as propriedades de um componente vão estar localizadas o Object Inspector, necessitando-se, em alguns casos, contar com a ajuda do Help online do Delphi. Por exemplo, selecione sgTab (dê um clique no StringGrid) e pressione a tecla F1. Aparece o Help do Delphi:

Page 41: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 41 Todos os direitos reservados.

Dê um clique em Properties e veja as propriedades deste componente.Você pode repetir este processo com qualquer componente do Delphi.

Execute a aplicação e dê um clique no botão.

Obs3.: A primeira célula de um StringGrid tem coordenadas [0,0] ou seja a primeira célula é Cells [0,0].

Feche o aplicativo e altere a manipulação OnClick acima para:

procedure TForm1.Button1Click(Sender: TObject);Var

Lin, Col : Byte ;begin

sgTab.Cells [0,0] := 'Grade de Strings' ;sgTab.Cells [1,0] := 'Coluna 1' ;sgTab.Cells [2,0] := 'Coluna 2' ;sgTab.Cells [3,0] := 'Coluna 3' ;sgTab.Cells [4,0] := 'Coluna 4' ;sgTab.Cells [5,0] := 'Coluna 5' ;sgTab.Cells [0,1] := 'Linha 1' ;sgTab.Cells [0,2] := ' Linha 2' ;sgTab.Cells [0,3] := ' Linha 3' ;sgTab.Cells [0,4] := ' Linha 4' ;sgTab.Cells [0,5] := ' Linha 5' ;For Lin := 1 To 5 Do

Page 42: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 42 Todos os direitos reservados.

For Col := 1 To 5 DosgTab.Cells [Col,Lin] := IntToStr (5 * (Lin -1) + Col) ;

end;

Execute novamente o aplicativo. Dê um clique no botão e feche o aplicativo.

Obs4.: Preste atenção nos comandos For / Do aninhados. Aqui, para cada valor da variável Col, será executada a linha de comando

sgTab.Cells [Col,Lin] := IntToStr (5 * (Lin -1) + Col) ;como já foi explicado anteriormente. Porém, o For / Do com a variável Col é repetida 5 vezes devido à linha de comando

For Lin := 1 To 5 Domais acima. Isto significa dizer que, a linha de comando envolvendo sgTab irá ser repetida por 25 vezes (5 vezes 5).

5.10. Cláusula: WITH / DO

Sintaxe:WITH <nome_do_objeto> DO

beginpropriedade1 := valor1 ;propriedade2 := valor2 ;

propriedadeN := valorN ;end ;

Assim, as propriedades entre o begin e o end pertencem ao objeto <nome_do_objeto> (entre os comandos With e Do).Por exemplo, reescreva a manipulação OnClick acima com o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var

Lin, Col : Byte ;begin

With sgTab Dobegin

Cells [0,0] := 'Grade de Strings' ;Cells [1,0] := 'Coluna 1' ;Cells [2,0] := 'Coluna 2' ;Cells [3,0] := 'Coluna 3' ;Cells [4,0] := 'Coluna 4' ;Cells [5,0] := 'Coluna 5' ;Cells [0,1] := 'Linha 1' ;Cells [0,2] := ' Linha 2' ;Cells [0,3] := ' Linha 3' ;Cells [0,4] := ' Linha 4' ;

Page 43: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 43 Todos os direitos reservados.

Cells [0,5] := ' Linha 5' ;For Lin := 1 To 5 Do

For Col := 1 To 5 DoCells [Col,Lin] := IntToStr ( 5 * (Lin -1) + Col) ;

end ;end;

Aproveite a aplicação acima e adicione um componente Label no Form. Manipule o evento OnClick de sgTab, com o seguinte código:

procedure TForm1.sgTabClick(Sender: TObject);begin Label1.Caption := IntToStr (sgTab.Col) ;end;

Execute o aplicativo. Aconteceu um erro de compilação. Sabe o por quê disto? Vá ao form e dê um clique sobre SgTab, e pressione em seguida a tecla F1. Aparecendo o Help online do Delphi, dê um clique em Properties (em verde) e verifique que um componente do tipo TStringGrid tem uma propriedade chamada Col. Como o begin / end do With / Do engloba o For / Do que utiliza a variável Col, há um conflito, pois variável e propriedade têm o mesmo nome, e isto não pode ocorrer. Assim sendo na manipulação OnClick do botão , renomeie a variável de Col para Coluna e você eliminará o erro.

Execute o aplicativo novamente e vá dando cliques em células diferentes de sgTab. Veja que o Caption de Label1 vai sendo alterado toda a vez que você clica em uma célula não fixa (em cor cinza).

Obs.: FixedCols e FixedRows contém a quantidade de células fixas de um StringGrid.

5.11. Janela de Senha e a propriedade ModalResult

Comece uma nova aplicação Clique em File - New

Ao surgir a janela de Templates (New Items) clique na aba Dialogs e em

Page 44: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 44 Todos os direitos reservados.

seguida selecione uma PasswordDlg (Password Dialog) Altere o Caption de Label1 de Enter password: para Digite sua senha Veja no Object Inspector que a propriedade PasswordChar do componente

Password (TEdit) é o caractere *, ou seja, quando você digitar algo no Edit Box de Password, irá aparecer um * ao invés da digitação real

Manipule o evento OnClick do botão OkBtn com o código abaixo:

procedure TPasswordDlg.OKBtnClick(Sender: TObject);begin

Form1.Label1.Caption := Password.Text ;end;

Obs1.: Note que o componente Label (cujo Caption será alterado) encontra-se no Form1 e não em PasswordDlg.

Retorne ao Form1 e adicione um Label e um Botão Manipule o evento OnClick do botão Button1 com o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);begin

PasswordDlg.ShowModal ;end;

Execute a aplicação e clique em Sim nas duas vezes que o compilador alertá-lo sobre a colocação dos cabeçalhos das Unit1 e Unit2.

Execute a aplicação novamente. Clique em Button1, digite algo no Edit Box da janela de senha, dê um clique no botão OKBtn e veja que o Caption de Label1 do Form1 é alterado. Feche o aplicativo.

Obs2.: Você tem colocado vários botões no Form, sem que um clique num deles feche a janela, a não ser com o uso do comando Close. Por que, então, a janela de senha é fechada com um clique num dos botões: OK ou Cancel? Quando você chama uma janela de forma Modal, você pode utilizar em conjunto a propriedade ModalResult do botão:

Aqui, os botões OkBtn e CancelBtn possuem a propriedade ModalResult igual a mrOk (modal result Ok) e mrCancel (modal result Cancel), respectivamente.

Page 45: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 45 Todos os direitos reservados.

Uma vez que o botão é clicado, transfere ao Form um resultado modal de fechamento, que pode ser um dos tipos abaixo:

mrNone mrOk mrCancel mrAbort mrRetry mrIgnore mrYes mrNo mrAll mrNoToAll mrYesToAll

A razão então de anteriormente você não ter fechado o Form com um clique de botão, é porque ou o botão possuia um ModalResult igual a mrNone ou porque o Form não foi chamado de maneira Modal.

Adicione outro componente Label a Form1 Manipule o evento OnClose de PasswordDlg com o seguinte código:

procedure TPasswordDlg.FormClose(Sender: TObject; var Action: CloseAction);begin If PasswordDlg.ModalResult = mrOk Then Form1.Label2.Caption := 'mrOk' ; If PasswordDlg.ModalResult = mrCancel Then Form1.Label2.Caption := 'mrCancel'end;

Execute o aplicativo, clique o botão, digite algo no Edit Box e dê um clique no botão OK. Veja que o Caption de Label2 é alterado para mrOK, que é o modo de fechamento da janela (ModalResult) da janela PasswordDlg . Clique o botão novamente, e depois dê um clique no botão Cancel. Verifique agora que Label1 tem seu Caption alterado para mrCancel.

Feche o aplicativo.

Obs3.: Note que a propriedade ModalResult do Form não aparece no Object Inspector, porque esta propriedade é intrínseca do seu fechamento e só é alterada em tempo de execução (run-time), não estando disponível em tempo de design.

Obs4.: Uma janela de senha nada mais é do que um Form normal com um Label, um Edit Box (com PasswordChar diferente de #0 = caractere nulo = ASCII 0) e dois botões (com a propriedade ModalResult de cada um alterada de mrNone para um dos tipos explicitados acima). Ao fechar a janela de senha, você pode permitir o acesso do usuário (caso a senha dele seja válida) ou mesmo fechar o aplicativo, caso o usuário clique o botão de cancelar.

Page 46: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 46 Todos os direitos reservados.

5.12. Janela de Senha sem usar o Template

Vamos construir a mesma janela de senha do exercício anterior, utilizando os componentes direto do Object Inspector.

Comece uma nova aplicação Adicione Form1 um Label e um Button Manipule o evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin

PasswordDlg.ShowModal ;end;

Adicione ao projeto outro Form Redimensione Form2 de modo que ele ocupe cerca de 20% da área de Form1,

como mostrado abaixo:

Adicione a Form2, um Label, um Edit Box e um Botton Altere as propriedades abaixo:

Form2- Name: PasswordDlg- Caption: Password Dialog

Label1- Caption: Digite sua senha

Page 47: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 47 Todos os direitos reservados.

Edit1- Name: Password- PasswordChar: @- apague a propriedade Text (deixe-a em branco)

Button1- Name: OKBtn- Caption: OKBtn- ModalResult: mrOK

Manipule o evento OnClick de OKBtn com:

procedure TPasswordDlg.OKBtnClick(Sender: TObject);begin

Form1.Label1.Caption := Password.Text ;end;

Execute a aplicação. Clique em Yes para inserir Uses Unit2 ; no cabeçalho da Unit1.

Execute novamente aplicação e clique o botão. Após digitar a sua senha (observe que você só consegue ver o caractere @), dê um clique em OKBtn. Form2 é então fechado e Form1 torna a ficar ativo.

Feche a aplicação.

Page 48: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 48 Todos os direitos reservados.

5.13. Botões de Bitmap e SpeedButtons

Comece uma nova aplicação Adicione ao Form um SpeedButton (aba Additional)

Clique no botão

reticências da propriedade Glyph e carregue uma imagem de bitmap (da mesma maneira como você já fez com o componente Image)

Manipule o evento OnClick com:

procedure TForm1.SpeedButton1Click(Sender: TObject);begin Form2.ShowModal ;end;

Adicione um segundo Form ao projeto

Page 49: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 49 Todos os direitos reservados.

Agora, adicione a Form2, um BitBtn

Altere a sua propriedade Kind

para bkOk (bitbtn kind Ok)

Obs1.: Como você deve ter observado, esses dois botões têm em comum, além da capacidade de conter um Caption, conter também uma "picture", uma imagem que tenha algum significado útil para o contexto do botão, como os botões de atalho que você vê no menu do Word, entre tantos outros aplicativos.

Obs2.: A propriedade Kind de BitBtn já seleciona uma imagem padrão para o tipo escolhido. Porém, caso você deseje, clicando no botão reticências da propriedade Glyph, você pode alterar este bitmap por outro mais conveniente.

Obs3.: Observe que SpeedButton não contém propriedade ModalResult, não podendo fechar um Form, a não ser que você na manipulação de um dos eventos deste botão, digite o comando Close.

Execute o aplicativo e dê um clique em SpeedButton1 Aparecendo o Form2, dê um clique em BitBtn1 Feche Form1 para retornar ao Delphi Altere a propriedade Flat de SpeedButton1 de False para True Execute o aplicativo Passe com o cursor do mouse sobre SpeedButton1 e veja a aparência idêntica

ao Internet Explorer Feche tudo e retorne ao Delphi Adicione mais 2 SpeedButton a Form2 Altere a propriedade GroupIndex de todos os SpeedButton para 1 (ou qualquer

valor diferente de 0 ) Altere a propriedade Down do 1º SpeedButton para True (ele fica "abaixado") Execute a aplicação. Clique no 2º SpeedButton e depois no 3º SpeedButton.

Veja que a cada clique num deles, o outro do mesmo grupo que estava "abaixado" é "levantado".

Feche o aplicativo e retorne ao Delphi.

Page 50: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 50 Todos os direitos reservados.

5.14. Menus

Comece um novo projeto Adicione 2 Botões ao Form Adicione um componente MainMenu ao Form

Dê um duplo

clique em MainMenu1 ou então dê um clique no botão reticências da sua propriedade Items (você terá acesso ao Menu Designer)

Obs1.: Vamos denominar cada palavra na horizontal como "Menu" e cada palavra na vertical como "Item de Menu". Por exemplo, no Delphi você tem no Menu File o Item de Menu New Application .

Observe que já há um menu (em branco) no Menu Designer:

Page 51: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 51 Todos os direitos reservados.

Altere o Caption do

menu para Botão&1 Pressione a tecla Enter. Observe o nome do componente: Boto11

Obs2.: O Caption é Botão1 mas o nome (propriedade Name) é Boto11, pois o Delphi não reconhece, como constituinte do nome de um componente, caracteres acentuados. Daí decorre a ausência do "ã" no nome do Menu. A razão do "11" é porque o Delphi coloca um número de contagem em cada nome de menu. Como o nome é Boto1, o Delphi o renomeia para Boto11. Se tivesse outro Botão1, seu nome seria Boto12.

Dê um clique no menu ao lado e altere seu caption para Botão&2 Pressione a tecla Enter Dê um clique no menu ao lado e altere seu Caption para Sai&r

Obs3.: Caso você deseje retirar algum Menu do Menu Designer, basta dar um clique nele e pressionar a tecla Del (ou Delete).

Dê um clique no Menu Boto11 Aparece então um espaço para você criar Itens de Menu Dê um clique no primeiro item e altere seu Caption para Visível Pressione a tecla Enter Dê um clique no item abaixo do item de menu Visvel1 Altere seu Caption para Não-Visível

Obs4.: O nome do Menu ou do Item de Menu, por enquanto, não é um ponto crítico da nossa aplicação, pois o que nos interessa é a manipulação do evento OnClick dos mesmos.

Obs5.: Dê um clique com o botão direito do mouse no Menu Designer (na área cinza) e você poderá carregar menus já prontos ou salvar o seu menu no Menu Template.

Page 52: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 52 Todos os direitos reservados.

O seu Menu deve estar com a seguinte aparência:

Manipule o evento OnClick de cada um dos itens de menu (janela vertical) de Boto11 com os códigos abaixo (respectivos a cada item):

procedure TForm1.Visvel1Click(Sender: TObject);begin Button1.Visible := True ;end;

procedure TForm1.NoVisvel1Click(Sender: TObject);begin Button1.Visible := False ; end;

Manipule o evento OnClick de Boto21 com:

procedure TForm1.Boto21Click(Sender: TObject);begin If Button2.Left < 50 Then Button2.Left := 100 Else Button2.Left := 10 ;end;

Por último, manipule o evento OnClick Do menu Sair1 com:

procedure TForm1.Sair1Click(Sender: TObject);begin Close ;end;

Execute a aplicação e experimente o seu menu. Feche-o e retorne ao Delphi.

Page 53: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 53 Todos os direitos reservados.

Dê um clique duplo no componente MainMenu1 e, no Menu Designer, dê um clique no Item Visvel1 (Item de Menu cujo Caption é Visível).

Pressione a tecla Ins (ou Insert). Digite o caractere hífen ( - ) no Caption do novo Item (digite apenas um caractere hífen) e pressione a tecla Enter. Você acaba de criar uma divisão.

Pressione novamente a tecla Ins (ou Insert) e Altere o Caption para Estado. Pressione a tecla Enter.

Dê um clique no Item Estado1. Mantenha a tecla Ctrl pressionada e dê um toque na tecla seta direita ( ) do seu teclado. Libere as teclas. Aparece um Sub-item de Menu. Dê um clique no Sub-item e altere o seu Caption para Habilitado. Pressione a tecla Enter.

Dê um toque no Sub-item abaixo de Habilitado1 e altere o seu Caption para Desabilitado.

Manipule cada evento OnClick desses Sub-itens de Menu com os códigos:

procedure TForm1.Habilitado1Click(Sender: TObject);begin Button1.Enabled := True ;end;

procedure TForm1.Desabilitado1Click(Sender: TObject);begin Button1.Enabled := False ;end;

Execute o aplicativo e teste seu novo Menu. Feche o aplicativo e retorne ao Delphi.

Dê um clique no Item Visível e, em seguida, selecione a tecla de atalho (ShortCut) Ctrl-V para este item:

A

figura acima mostra o Item já associado a tecla de atalho

Ctrl-V.

Page 54: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 54 Todos os direitos reservados.

6. Procedimentos e Funções de Usuário

Um projeto é constituído de units, que por sua vez são divididas em pequenos trechos de programa, aos quais chamamos genericamente de sub-programas ou sub-rotinas.

Às vezes, digitamos trechos de código-fonte idêntico em várias manipulações de evento, simplesmente porque sua execução num determinado momento da manipulação é necessária. Se tivermos 1000 linhas de código em digamos 10 manipulações de evento veremos que algumas manipulações acabam tendo 1 ou mais trechos repetidos.

Então, para que não seja necessário reescrever várias vezes um determinado código que esteja repetido em vários trechos do programa, implementamos uma sub-rotina no programa e damos-lhe um nome. Toda vez que for necessária a execução das linhas de comando lá contidas, simplesmente digitamos o nome da sub-rotina em questão. A isto damos o nome: invocar a sub-rotina.

Essas sub-rotinas podem ser divididas em duas classes principais:- procedimento : executa as linhas de comando e retorna ao ponto de

chamada- função : executa as linhas de comando e retorna ao ponto de

chamada com um "valor de retorno", que deve ser atribuído a uma variável ou utilizado em uma condição IF/THEN, WHILE/DO, REPEAT/UNTIL ou outro comando que permita esta utilização.

Vamos exemplificar o uso de procedures:

Comece uma nova aplicação Coloque um Botão e um Edit Box em Form1 Manipule o evento do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Close ;end;

Manipule o evento OnActivate de Form1 com:

procedure TForm1.FormActivate(Sender: TObject);begin Edit1.SetFocus ;end;

Execute a aplicação. Verifique que ao ser ativado, a aplicação transfere o foco (componente ativo) para Edit1, através da procedure SetFocus. Além disso, quando você clica o botão, a procedure Close fecha o aplicativo simplesmente. Você não precisa reescrever todo o código-fonte referente a essas rotinas, porque basta digitar seus nomes para "invocá-las".

Feche o aplicativo (clique o botão).

Page 55: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 55 Todos os direitos reservados.

Vamos exemplificar o uso de functions:

Comece uma nova aplicação Coloque um Botão e dois Edit Box em Form1 Manipule o evento do botão com:

procedure TForm1.Button1Click(Sender: TObject);Var

A, B : Extended ; begin

A := StrToFloat ( Edit1.Text ) ;B := SQRT ( A ) ;

Edit2.Text := FloatToStr (B ) ;end;

Execute a aplicação. Digite um número qualquer em Edit1 e clique o botão. Veja surgir em Edit2 a raiz quadrada ( SQuare (RooT ) do número por você digitado.

Feche a aplicação.

O que você fez foi utilizar uma função prédefinida pelo Delphi que é a função SQRT, que "retorna" ao ponto chamador (a linha de comando onde aconteceu a chamada à função) com um valor de retorno (neste caso, a raiz quadrada do valor contido em Edit1.Text).

Você utilizou também as funções de conversão de string para real, pois A e B são variáveis Extended e Text é uma propriedade String. Assim, StrToFloat retorna ao ponto de chamada com um valor em ponto flutuante (Float = contém casas decimais e ponto separador; é ponto separador e não vírgula, pois a notação utilizada pelo Delphi é a notação americana) resultante da conversão da string entre parênteses. Este valor é atribuído então à variável A. Da mesma forma, não poderíamos atribuir um valor Extended à propriedade Text de Edit2. Por isso, você utilizou a função FloatToStr que retorna ao ponto de chamada com uma string contendo os dígitos numéricos, o ponto decimal e o sinal (se for número negativo) do valor em ponto flutuante entre parênteses.

Essas sub-rotinas são pré-definidas pelo Delphi e você pode utilizá-las à vontade. Bem como, você também pode definir suas sub-rotinas, com características próprias, utilizando, dentro delas, as sub-rotinas do Delphi.

A utilização de uma sub-rotina nem sempre é para evitar código repetido, mas também para organizar melhor o código-fonte, permitindo a reutilização de um mesmo código em várias partes diferentes de um programa.

Vamos desenvolver uma aplicação cujo form contenha cinco edit box. Você terá que digitar um valor numérico no primeiro edit box, um outro valor numérico no segundo edit box, uma operação aritmética no terceiro edit box e um valor numérico no quarto edit box. Há, porém, uma condição: o segundo valor numérico deverá ser menor do que o primeiro valor numérico, caso contrário, os edit box deverão ter seus conteúdos apagados, recomeçando a entrada de dados do início. Caso a condição acima seja satisfeita, um clique no botão deverá calcular o fatorial da subtração dos dois primeiros números, esse resultado deverá ser operado aritmeticamente com o terceiro valor numérico, cujo operador encontra-se no terceiro edit box, e o resultado final deverá mostrado no quinto edit box.

Page 56: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 56 Todos os direitos reservados.

Por exemplo, caso tenhamos a seguinte situação:

Ao clique do botão, teremos:

10 - 6 = 44! = 4 x 3 x 2 x 1 = 24 (fatorial de 4 é igual a 24)24 / 2 = 12

O que resultaria em (resultado no quinto edit box):

Obs1.: Lembremos que só existe fatorial de número inteiro positivo .

Obs2.: Por definição, o fatorial de zero é igual a um: 0! = 1 .

Agora, se você digitar o valor zero para o terceiro edit box e pedir a sua divisão, também acontece um erro (erro de divisão por zero), e nesse caso, precisaríamos também recomeçar a entrada de dados, apagando todos os edit box (é obvio que só precisaríamos digitar um valor não nulo no quarto edit box, mas finja que isto é necessário).

Comece uma nova aplicação Coloque cinco Edit Box e um Botão no Form:

10 6 / 2

10 6 / 2 12

Page 57: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 57 Todos os direitos reservados.

Apague a propriedade Text dos cinco edit box. Manipule os eventos abaixo:

OnClick de Edit3:

procedure TForm1.Edit3Click(Sender: TObject);Var A, B : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A < B Then

Page 58: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 58 Todos os direitos reservados.

begin Edit1.Clear ; Edit2.Clear ; Edit3.Clear ; Edit4.Clear ; Edit5.Clear ; Edit1.SetFocus ; {Dá o foco a Edit1: coloca o cursor em Edit1} end ;end;

OnClick de Edit4:

procedure TForm1.Edit4Click(Sender: TObject);Var A, B : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A < B Then begin Edit1.Clear ; Edit2.Clear ; Edit3.Clear ; Edit4.Clear ; Edit5.Clear ; Edit1.SetFocus ; end ;end;

OnClick de Button1:

procedure TForm1.Button1Click(Sender: TObject);Var A, B, C, Fat : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A > B Then begin Fat := 1 ; For C := (A - B) DOWNTO 1 Do Fat := Fat * C ; {O novo valor de Fat é o seu valor antigo vezes C}

Page 59: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 59 Todos os direitos reservados.

Case Edit3.Text [1] Of {Edit3.Text [1] = caractere na posição 1 de Edit3} '+' : C := Fat + StrToInt (Edit4.Text) ; '-' : C := Fat - StrToInt (Edit4.Text) ; '*' : C := Fat * StrToInt (Edit4.Text) ; '/' : C := Fat Div StrToInt (Edit4.Text) ; End ; Edit5.Text := IntToStr (C) ; end Else begin Edit1.Clear ; Edit2.Clear ; Edit3.Clear ; Edit4.Clear ; Edit5.Clear ; Edit1.SetFocus ; end ;end;

Execute a aplicação e digite a seqüência abaixo:

1. Edit1: 102. Edit2: 63. Edit3: /4. Edit4: 2

Clique o botão. Veja o resultado ( 12 ) em Edit5. Digite agora a seqüência:

1. Edit1: 62. Edit2: 10

Verifique que, ao clicar em Edit3, todos os edit box são apagados (Clear) e o controle retorna a Edit1.

Feche o aplicativo e retorne ao Delphi.Vamos analisar o código acima.

a. O trecho:

A := StrToInt (Edit1.Text) ;B := StrToInt (Edit2.Text) ;

repete-se por três vezes (uma em cada manipulação de evento).

b. O trecho:

Edit1.Clear ;Edit2.Clear ;

Page 60: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 60 Todos os direitos reservados.

Edit3.Clear ;Edit4.Clear ;Edit5.Clear ;Edit1.SetFocus ;

repete-se também por três vezes (uma em cada manipulação de evento).

Isto significa dizer que: qualquer alteração a ser feita em uma das linhas de comando, demandará no mínimo três alterações no código. Por exemplo, se o foco a partir de agora passar para Edit2 em vez de Edit1, teremos que refazer as três partes do código-fonte. E se quisermos processar o código da manipulação Onclick de Button1 no click de Edit4, teremos que reescrever o código desta manipulação. Mas eu posso copiar e colar com Ctrl-C e Ctrl-V, dirá você. Realmente você pode, mas toda a vez que você altera de alguma maneira o seu código, seja digitando, seja copiando/colando, erros podem ser introduzidos no código-fonte, sem que você consiga descobrir onde está esse erro (ou erros).

Porém, caso você tenha uma estrutura que lhe forneça o código repetido, e o execute a cada chamada, uma modificação no código da estrutura no nosso caso, diminui em 67% a introdução de bugs (erros), pois só haverá uma modificação, e não três modificações, como no código apresentado.

Para isso, vamos agregar o código que utiliza o comando Clear dos edit box repetido numa procedure, cuja sintaxe é:

procedure Nome_da_procedure ;beginend;

Muito parecido com o cabeçalho de uma manipulação de evento.

E o código que obtém o primeiro caractere da string contida em Edit3.Text irá para uma function, cuja sintaxe geral é a seguinte:

function Nome_da_function : Tipo_da_function ;beginend; Assim sendo, altere o código anterior adicionando o código que segue abaixo

(preste atenção aos trechos em negrito):

implementation

{$R *.DFM}

procedure Limpa ;begin Form1.Edit1.Clear ;

Page 61: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 61 Todos os direitos reservados.

Form1.Edit2.Clear ; Form1.Edit3.Clear ; Form1.Edit4.Clear ; Form1.Edit5.Clear ; Form1.Edit1.SetFocus ;end ;

function Obtem_Operador : Char ;begin Result := Form1.Edit3.Text [1] ;end ;

procedure TForm1.Edit3Click(Sender: TObject);Var A, B : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A < B Then Limpa ;end;

procedure TForm1.Edit4Click(Sender: TObject);Var A, B : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A < B Then Limpa ;end;procedure TForm1.Button1Click(Sender: TObject);Var A, B, C, Fat : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A > B Then begin Fat := 1 ; For C := (A - B) DOWNTO 1 Do Fat := Fat * C ; Case Obtem_Operador Of '+' : C := Fat + StrToInt (Edit4.Text) ;

Page 62: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 62 Todos os direitos reservados.

'-' : C := Fat - StrToInt (Edit4.Text) ; '*' : C := Fat * StrToInt (Edit4.Text) ; '/' : C := Fat Div StrToInt (Edit4.Text) ; End ; Edit5.Text := IntToStr (C) ; end Else Limpa ;end;

end.

Execute a aplicação e repita as entradas (10 , 6 , / e 2) e verifique que o programa processa o problema da mesma maneira.

Feche a aplicação e retorne ao Delphi.

Mas por que você não "enxugou" a aplicação poupando a digitação das linhas de comando IntToStr e StrToInt e poupou a linha que "pega" o primeiro caractere de Edit3.Text?

Bom, tudo isto se resume em estilo de cada programador. Então, se você gosta de empanturrar o seu programa com procedures e functions, sinta-se à vontade. Mas não vá abusar, pois você tem sempre que pensar:

Se eu colocar este ou aquele trecho em uma sub-rotina estarei simplificando o meu código? Será que eu pouparei digitação? Será que o código ficará um pouco mais complicado, mas se acontecer um erro, eu o acharei mais facilmente?

São todas perguntas, em determinados momentos, difíceis de responder.Vamos conversar mais sobre procedures e functions.

6.1. Procedimentos de Usuário

Até agora você utilizou procedures nas manipulações de evento, mas essas procedures são "escritas" pelo Delphi, não por você. As procedures que você escreve são comumente chamadas de: procedures de usuário.

Uma procedure pode conter parâmetros, que são valores e/ou variáveis que você envia para ser processada na rotina local à procedure. Por exemplo, qualquer manipulação de evento contém o parâmetro Sender, que é uma variável que indica o objeto que está sofrendo o evento naquele momento.

A sintaxe geral de uma procedure é a seguinte:

procedure Nome_da_procedure (p1 : tipo1 ; p2 , p3 : tipo2 ; Var p3 : tipo3 ) ;Const

Page 63: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 63 Todos os direitos reservados.

Declaração das constantesType

Definição de tiposVar

Declaração das variáveisbegin

comandos da procedureend ;

Assim, quando a procedure Nome_da_procedure for invocada, deverá conter entre parênteses quatro variáveis de tipos iguais a: tipo1, tipo2, tipo2 e tipo3, nesta ordem. Isso significa que você deseja processar os comandos da procedure com determinados valores específicos e, os parâmetros servirão de variáveis locais à procedure, o que significa que só serão visíveis dentro da procedure (somente existirão enquanto a procedure estiver sendo executada, sendo destruídas ao término da procedure).

Você deve ter observado que:- a declaração dos parâmetros é idêntica à declaração das variáveis:

nome_da_variável : tipo - podemos declarar parâmetros de tipos diferentes: é só separá-los por ponto-e-

vírgula- podemos declarar mais de um parâmetro do mesmo tipo: é só separá-los por

vírgula- o último parâmetro tem a palavra reservada Var antes de seu nome: isto é

chamado passagem de parâmetro por referência (os três primeiros são passagem de parâmetros por valor). Isto significa que, qualquer alteração no conteúdo do parâmetro durante a execução da procedure, altera o conteúdo da variável que foi passada por referência à procedure

Vamos fazer uma modificação no código anterior para exemplificar o uso de procedures. A modificação que será feita, visa passar uma string que servirá de texto à janela de mensagem ShowMessage indicando o tipo de erro acontecido. Como será passada uma string, a variável parâmetro que receberá a string também deve ser do tipo string.

implementation

{$R *.DFM}

procedure Limpa ( Mensagem : String) ;begin Form1.Edit1.Clear ; Form1.Edit2.Clear ; Form1.Edit3.Clear ; Form1.Edit4.Clear ; Form1.Edit5.Clear ; Form1.Edit1.SetFocus ; ShowMessage (Mensagem) ;

Page 64: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 64 Todos os direitos reservados.

end ;

function Obtem_Operador : Char ;begin Result := Form1.Edit3.Text [1] ;end ;

procedure TForm1.Edit3Click(Sender: TObject);Var A, B : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A < B Then Limpa ( 'Edit1 não pode ser menor do que Edit2' ) ;end;

procedure TForm1.Edit4Click(Sender: TObject);Var A, B : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A < B Then Limpa ( 'Edit1 não pode ser menor do que Edit2' ) ;end;

procedure TForm1.Button1Click(Sender: TObject);Var A, B, C, Fat : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A > B Then begin Fat := 1 ; For C := (A - B) DOWNTO 1 Do Fat := Fat * C ; Case Obtem_Operador Of '+' : C := Fat + StrToInt (Edit4.Text) ;

Page 65: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 65 Todos os direitos reservados.

'-' : C := Fat - StrToInt (Edit4.Text) ; '*' : C := Fat * StrToInt (Edit4.Text) ; '/' : C := Fat Div StrToInt (Edit4.Text) ;

Else Limpa ( 'Operador Inválido' )

End ; Edit5.Text := IntToStr (C) ; end Else Limpa ( 'Edit1 não pode ser menor do que Edit2' ) ;end;

end.

Execute a aplicação e tente, numa primeira vez, entrar com um valor menor em Edit1 do que em Edit2. Depois, tente entrar com o operador @ em Edit3. Veja as mensagens de erro "sensíveis" ao contexto.

Outra coisa que você deve ter notado, é que o código manipulado em Edit4Click é

idêntico ao código manipulado em Edit3Click. será que não podemos simplificar essa chamada com uma procedure?

Vamos fazer melhor: remova a manipulação OnClick de Edit4, deixando apenas o cabeçalho inicial , como abaixo:

procedure TForm1.Edit4Click(Sender: TObject);beginend;

Recompile o programa (Project - Compile) e veja que não há mais a manipulação deste evento (observe na aba Events do Oject Inspector que a manipulação OnClick de Edit4 está em branco).

Dê um clique na setinha preta contida após a parte branca da manipulação

Page 66: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 66 Todos os direitos reservados.

e

depois dê um clique na manipulação Edit3Click. Note que a manipulação OnClick de Edit4 contém agora o nome da manipulação OnClick de Edit3. Isto significa dizer que: qualquer alteração introduzida em Edit3Click será executada por Edit4Click também, evitando que códigos desnecessários sejam digitados. Mas preste bem atenção: o que foi realizado aqui vale apenas para a manipulação de eventos.

6.2. Funções de Usuário

A diferença básica entre uma chamada a uma procedure e a uma function é que a segunda retorna um valor para o ponto de chamada, podendo (esse valor de retorno da função) ser atribuído a uma variável ou ser utilizado em uma condição de um dos comandos de controle: IF/THEN, WHILE/DO, REPEAT/UNTIL ou como valor de um CASE/OF, entre tantos outros usos. Já uma procedure é chamada de maneira independente não tendo valor de retorno e, por conseqüência, não podendo ser utilizado como condição de comando algum, e nem ser atribuída à variável alguma.

É importante observar que, o tipo de parâmetro (ou parâmetros) nada tem haver com o tipo do valor de retorno da função, podendo em alguns casos serem iguais.

Vamos mais uma vez alterar o código anterior, modificando a função Obtem_Operador que conterá como parâmetros uma string e um valor numérico indicando qual a posição em que se deve extrair o caractere da string passada como parâmetro.

Altere a função Obtem_Operador com o código abaixo:

function Obtem_Operador ( M : String ; Posicao : Integer ) : Char ;begin

Page 67: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 67 Todos os direitos reservados.

Result := M [ Posicao ] ; end ;

Altere também o código OnClick de Button1:

procedure TForm1.Button1Click(Sender: TObject);Var A, B, C, Fat : Integer ;begin A := StrToInt (Edit1.Text) ; B := StrToInt (Edit2.Text) ; If A > B Then begin Fat := 1 ; For C := (A - B) DOWNTO 1 Do Fat := Fat * C ; Case Obtem_Operador ( Edit3.Text , 1) Of '+' : C := Fat + StrToInt (Edit4.Text) ; '-' : C := Fat - StrToInt (Edit4.Text) ; '*' : C := Fat * StrToInt (Edit4.Text) ; '/' : C := Fat Div StrToInt (Edit4.Text) ;

Else Limpa ( 'Operador Inválido' )

End ; Edit5.Text := IntToStr (C) ; end Else Limpa ( 'Edit1 não pode ser menor do que Edit2' ) ;end;

end.

Execute a aplicação e repita os passos anteriores para testar o novo código. Feche a aplicação.

Aqui, você invocou a função Obtem_Operador mandando dois parâmetros entre parênteses: um string e outro inteiro, que são recebidos nas variáveis locais M e Posicao, respectivamente. Isto nos faz concluir que, as variáveis declaradas como parâmetro são inicializadas com os valores passados entre parênteses quando da chamada da subrotina, o que nos obriga a passar valores de tipos compatíveis na ordem em que são declarados no cabeçalho da função.

Uma outra observação a ser feita, é que os parâmetros passados (string e integer) têm tipos diferentes do tipo do valor de retorno da função (tipo char).6.3. Passagem de Parâmetro por Referência

A passagem de parâmetro por referência, não importa se numa procedure ou numa function, faz com que a variável recebedora utilize a mesma posição de memória da

Page 68: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 68 Todos os direitos reservados.

variável que passa o dado na chamada da sub-rotina. Isto impõe que, numa passagem de parâmetros por referência, utilizemos somente variáveis, ou seja, não podemos neste caso utilizar uma constante, coisa que fizemos quando invocamos a função Obtem_Operador. Observe que o segundo parâmetro é a constante numérica 1).

Vejamos um exemplo:

Comece uma nova aplicação Digite a seguinte procedure no seu código ( abaixo da diretiva de compilação

{$R *.DFM}):

procedure Altera_Valor ( X : Integer ; Var Y : Integer ; Z,W : Integer ) ;begin ShowMessage ( 'Durante a chamada à procedure' + Chr(13) + '(antes da alteração):' + Chr(13) + Chr(13) + 'X = ' + IntToStr(X) + Chr(13) + 'Y = ' + IntToStr(Y) + Chr(13) + 'Z = ' + IntToStr(Z) + Chr(13) + 'W = ' + IntToStr(W) ) ;

X := 10 ; Y := 20 ; Z := 30 ; W := 40 ; ShowMessage ( 'Durante a chamada à procedure' + Chr(13) + '(após a alteração):' + Chr(13) + Chr(13) + 'X = ' + IntToStr(X) + Chr(13) + 'Y = ' + IntToStr(Y) + Chr(13) + 'Z = ' + IntToStr(Z) + Chr(13) + 'W = ' + IntToStr(W) ) ;end ;

Veja que o segundo parâmetro será passado por referência.

Coloque um botão no form Manipule o evento OnClick deste botão com o seguinte:

procedure TForm1.Button1Click(Sender: TObject);

Page 69: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 69 Todos os direitos reservados.

Var A, B, C, D : Integer ;begin A := 3 ; B := 5 ; C := 7 ; D := 9 ;

ShowMessage ( 'Antes da chamada à procedure:' + Chr(13) + 'A = ' + IntToStr(A) + Chr(13) + 'B = ' + IntToStr(B) + Chr(13) + 'C = ' + IntToStr© + Chr(13) + 'D = ' + IntToStr(D) ) ;

Altera_Valor (A, B, C, D) ;

ShowMessage ( 'Após chamada `a procedure:' + Chr(13) + 'A = ' + IntToStr (A) + Chr(13) + 'B = ' + IntToStr (B) + Chr(13) + 'C = ' + IntToStr (C) + Chr(13) + 'D = ' + IntToStr (D) ) ;

end;

Execute a aplicação e clique o botão.

Aparece o primeiro MessageBox com os valores das variáveis. Quando você entrou na manipulação do evento OnClick do botão, foi alocada memória RAM para armazenar os valores contidos nas variáveis A, B, C e D, como mostra abaixo:

3 endereço de memória da variável A

5 endereço de memória da variável B

7 endereço de memória da variável C

9 endereço de memória da variável D

A

B

C

D

Page 70: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 70 Todos os direitos reservados.

Quando a procedure é invocada, mais memória é alocada para as variáveis que recebem os parâmetros, com exceção da variável Y, que compartilha a mesma posição de memória da variável B , pois essa passagem é feita por referência e as demais por valor. Isto quer dizer que: com exceção da variável B, as outras variáveis passam o conteúdo que cada uma delas tem para as variáveis recebedoras. Já a variável B, fornece o endereço na memória para Y, e elas passam a coexistir nessa mesma posição:

3 endereço de memória da variável A

5 endereço de memória das variáveis B e Y

7 endereço de memória da variável C

9 endereço de memória da variável D

3 endereço de memória da variável X

7 endereço de memória da variável Z

9 endereço de memória da variável W

Quando você imprime os conteúdos das variáveis X, Y, Z e W, você imprime o conteúdo de cada uma das posições de memória acima. Ao alterar o conteúdo de cada uma dessas variáveis, acontece o seguinte:

3 endereço de memória da variável A

20 endereço de memória das variáveis B e Y

7 endereço de memória da variável C

A

B = Y

C

D

X

Z

W

A

B = Y

C

Page 71: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 71 Todos os direitos reservados.

9 endereço de memória da variável D

10 endereço de memória da variável X

30 endereço de memória da variável Z

40 endereço de memória da variável W

E aí, quando você imprime o conteúdo de cada uma delas, aparecem os novos valores: X = 10, Y = 20, Z = 30 e W = 40. Porém, quando a procedure chega ao fim, as variáveis locais são destruídas, e há o retorno ao ponto de chamada da procedure. O que acontece com o conteúdo de cada posição de memória:

3 endereço de memória da variável A

20 endereço de memória da variável B

7 endereço de memória da variável C

9 endereço de memória da variável D

É isso mesmo, o conteúdo da posição de memória ocupada pela variável B, que era compartilhado pela variável Y, ficou modificada. Isso porque houve passagem por referência, e não por valor, como foi o caso das outras variáveis.

6.4. InputBox

Esta função faz surgir uma janela de diálogo e retorna a string digitada no edit box da janela. Envolve três parâmetros:

function InputBox(const ACaption, APrompt, ADefault: string): string;

D

X

Z

W

A

B

C

D

Page 72: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 72 Todos os direitos reservados.

O primeiro (Acaption) é o título da janela; o segundo (Aprompt) é o texto informativo do que o usuário deve digitar; e o terceiro (Adefault), é o valor default que estará contido inicialmente no edit box da janela de diálogo. A palavra const é para indicar que os valores passados não sofrerão alteração nos seus conteúdos. Isso otimiza a memória e dá maior velocidade de processamento.

Comece uma nova aplicação Adicione um Label ao form Manipule o evento OnActivate de Form1 com o código:

procedure TForm1.FormActivate(Sender: TObject);begin Label1.Caption := InputBox ('Janela de Login' , 'Login Name:' ,'aluno') ;end;

Execute a aplicação e clique em OK. Feche e execute novamente a aplicação e clique em Cancel. Feche e execute novamente a aplicação, digite o seu nome e clique em OK. Feche e execute novamente a aplicação, digite o seu nome e clique em Cancel. Feche a aplicação

6.5. InputQuery

Esta função faz surgir uma janela de diálogo e retorna True se for clicado o botão OK e False se for clicado o botão Cancel . Envolve três parâmetros, com as mesmas finalidades descritas para InputBox:

function InputQuery(const ACaption, APrompt: string; var Value: string): Boolean;

Observe que o terceiro parâmetro é passado por referência. Assim, qualquer alteração no edit box seguido de um clique no botão OK, altera o conteúdo da variável Value, que conterá o que foi digitado pelo usuário.

Comece uma nova aplicação Adicione um Label ao form Manipule o evento OnActivate de Form1 com o código:

procedure TForm1.FormActivate(Sender: TObject);Var Mens : String ;begin If InputQuery ('Janela de Login' , 'Login Name:' , Mens) Then Label1.Caption := Mens ;end;

Execute a aplicação e clique em OK. Feche e execute novamente a aplicação e clique em Cancel. Feche e execute novamente a aplicação, digite o seu nome e clique em OK. Feche e execute novamente a aplicação, digite o seu nome e clique em Cancel.

Page 73: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 73 Todos os direitos reservados.

Feche a aplicação

6.6. A função Format

Comece uma nova aplicação Coloque no Form, um componente Memo (aba Standard):

Adicione um botão ao Form Manipule o

evento OnClick deste botão com o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var Pol : Integer ; Cm : Extended ; Valor : String ;begin

Pol := 1 ; Repeat Cm := 2.54 * Pol ; Valor := Format ( '%3d = %6.2f ' , [ Pol , Cm ] ) ;

Page 74: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 74 Todos os direitos reservados.

Memo1.Lines.Append ( Valor ) ;Pol := Pol + 1 ;

Until Pol > 100 ;end;

Execute a aplicação, clique o botão e, depois de examinar a tabela de valores convertidos, feche a aplicação.

Obs.: Para um detalhamento dos parâmetros da função Format Strings, utilize o Help online do Delphi.

6.7. O parâmetro Sender

Este parâmetro é um parâmetro especial, e indica qual o tipo de objeto que está sofrendo o evento. Para testar se isso ocorre, faça o seguinte:

Comece um novo aplicativo Coloque um edit box, um label e um memo no form Manipule o evento OnKeyPress de Edit1 com:

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);begin Label1.Caption := Sender.ClassName ;end;

Selecione esta manipulação de evento para os componentes Button1 e Memo1 Execute a aplicação, dê um clique no edit box e digite algo; verifique que o

Caption de Label1 alterou para TEdit. Dê um clique no botão e pressione uma tecla. Agora, o Caption alterou para TButton. Dê um clique no componente Memo1 e digite algo. Verifique a alteração do Caption de Label1 de TButton para TMemo.

Feche a aplicação

7. Matrizes

Comece uma nova aplicação Coloque um botão e um memo no form Manipule o evento OnActivate do form com:

procedure TForm1.FormActivate(Sender: TObject);begin Memo1.Clear ; {Apaga tudo o que estiver escrito em Memo1}end;

Manipule o evento OnClick de Button1 com:

Page 75: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 75 Todos os direitos reservados.

procedure TForm1.Button1Click(Sender: TObject);Var v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, Linha, Total_Linhas, Soma : Integer ;begin Total_Linhas := Memo1.Lines.Count ; {Quantidade de linhas de Memo1} Linha := 1 ; v1 := 0 ; v2 := 0 ; v3 := 0 ; v4 := 0 ; v5 := 0 ; v6 := 0 ; v7 := 0 ; v8 := 0 ; v9 := 0 ; v10 := 0 ; If Linha <= Total_Linhas Then begin v1 := StrToInt ( Memo1.Lines.Strings [ 0 ] ) ; Inc (Linha) ; {Incremente a variável Linha de 1, ou seja: Linha := Linha + 1} end ; If Linha <= Total_Linhas Then begin v2 := StrToInt ( Memo1.Lines.Strings [ 1 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v3 := StrToInt ( Memo1.Lines.Strings [ 2 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v4 := StrToInt ( Memo1.Lines.Strings [ 3 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v5 := StrToInt ( Memo1.Lines.Strings [ 4 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v6 := StrToInt ( Memo1.Lines.Strings [ 5 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v7 := StrToInt ( Memo1.Lines.Strings [ 6 ] ) ;

Page 76: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 76 Todos os direitos reservados.

Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v8 := StrToInt ( Memo1.Lines.Strings [ 7 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v9 := StrToInt ( Memo1.Lines.Strings [ 8 ] ) ; Inc (Linha) ; end ; If Linha <= Total_Linhas Then begin v10 := StrToInt ( Memo1.Lines.Strings [ 9 ] ) ; Inc (Linha) ; end ; Soma := v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 ; Memo1.Lines.Append ( Format ( 'Total = %d' , [ Soma ] ) ) ;end ;

Execute a aplicação Digite o número 10 e pressione Enter Digite o número 15 e pressione Enter Digite o número 30 e pressione Enter Digite o número 100 e pressione Enter Dê um clique no botão e veja o Total = 155. Feche a aplicação

Obs1.: A função Memo1.Lines.Count retorna o número de linhas contidas no componente Memo. No caso acima, no clique do botão, Total_Linhas conterá quatro, pois teremos quatro strings em Memo1.

Obs2.: A procedure Inc ( Nome_Var , quant ) passa Nome_Var por referência e a incrementa de quant vezes. Quando quant é igual a 1, pode-se omiti-la.Isto significa dizer que Linha := Linha + 1 é o mesmo que Inc (Linha) .

Obs3.: A procedure Dec ( Nome_Var , quant ) passa Nome_Var por referência e a decrementa de quant vezes. Quando quant é igual a 1, pode-se omiti-la.Isto significa dizer que X := X - 5 é o mesmo que Dec (X , 5) .

O problema com o código acima, é a grande quantidade de variáveis, do mesmo

tipo, envolvidas no cálculo do total. Como podemos evitar manipular grande quantidade de variáveis de um mesmo tipo, e como podemos automatizar o processo de manipulação, uma vez que se tivermos que alterar a quantidade de valores envolvidos, digamos de 10 valores para 50 valores, teremos um bom trabalho de digitação? Podemos utilizar matrizes, que são variáveis que suportam vários valores diferentes (porém do mesmo tipo), e nos permite referenciar cada valor por um índice, que corresponde à posição da matriz, na qual encontra-se o valor desejado.

Page 77: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 77 Todos os direitos reservados.

Para utilizar matrizes no Delphi, utilizamos a palavra reservada Array e definimos a dimensão da matriz entre colchetes. Por exemplo,

1 2 3 4 5 6 7 8 9 10

V

É um vetor de nome V com 10 posições, sendo que a primeira posição possui o conteúdo 1, a segunda posição o conteúdo 2, a terceira posição o conteúdo 5, a quarta posição o conteúdo 14, e assim por diante. Abaixo você tem a declaração da variável Array e a inicialização dos valores conforme o esquema acima:

Var

V : Array [ 1 .. 10 ] Of Integer ;begin

V [ 1 ] := 1 ;V [ 2 ] := 2 ;V [ 3 ] := 5 ;V [ 4 ] := 14 ;V [ 5 ] := 857 ;V [ 6 ] := 29 ;V [ 7 ] := 31 ;V [ 8 ] := 18 ;V [ 9 ] := 77 ;V [ 10 ] := 34 ;

end ;

Note que a quantidade de elementos que o vetor possui, é a diferença entre o primeiro valor e o último valor mais 1 (são dez elementos: 10 - 1 + 1 = 10). Esses valores também dizem qual o índice inicial e qual o índice final (só podemos utilizar valores ordinais para definir os limites inicial e final de um array). Há casos em que temos que definir um índice inicial diferente da unidade. Para declarar, por exemplo, uma tabela de temperatura que varie de -37ºC à 135ºC e, que em cada uma das 173 posições da tabela (135 - (-37) + 1 = 173) contenha o nome de uma localidade (com 50 caracteres), faça:

Var

Temp : Array [ -37 .. 135 ] Of String [ 50 ] ;

Obs4.: Os dois pontos ( .. ) indicam que os valores em questão tratam-se de um limite.

Vamos reescrever o código anterior:

procedure TForm1.Button1Click(Sender: TObject);Var K, Linha, Total_Linhas, Soma : Integer ; V : Array [ 1 .. 10 ] Of Integer ; begin Total_Linhas := Memo1.Lines.Count ; Linha := 1 ;

1 2 5 14 857 29 31 18 77 34

Page 78: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 78 Todos os direitos reservados.

For K := 1 To 10 Do V [ K ] := 0 ; While Linha <= Total_Linhas Do begin V [ Linha ] := StrToInt ( Memo1.Lines.Strings [ Linha - 1 ] ) ; Inc (Linha) ; end ; Soma := 0 ; For K := 1 To 10 Do Soma := Soma + V [ K ] ; Memo1.Lines.Append ( Format ( 'Total = %d' , [Soma] ) ) ;end ;

Verifique que o código ficou mais "suave".

Mas e se você deseja trabalhar com matrizes com mais de uma dimensão? Simples, é só definir as dimensões (e seus limites) dentro dos colchetes, separados por vírgula. Por exemplo, para declarar a variável array Mat de elementos reais (matriz 3 x 5):

Faça como abaixo:

Type Matriz = Array [ 1 .. 3 , 1 .. 5 ] Of Extended ;Var Mat : Matriz ;

Preste bem atenção: não é obrigatório o uso da cláusula Type, porém torna o código mas "elegante".E para inicializar os elementos da matriz acima com zero, podemos fazer como já fizemos para o StringGrid:

For Linha := 1 To 3 Do For Coluna := 1 To 5 Do Mat [ Linha , Coluna ] := 0 ;

Obs5.: Podemos utilizar as seções Const e Type para tornar o código acima mais elegante ainda:

Linha 1 Linha 2 Linha 3

Coluna 1 Coluna 2 Coluna 3 Coluna 4 Coluna 5

Page 79: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 79 Todos os direitos reservados.

Const Tot_Linhas = 3 ; Tot_Colunas = 5 ;Type Dimensao1 = 1 .. Tot_Linhas ; Dimensao2 = 1 .. Tot_Colunas ; Matriz = Array [ Dimensao1 , Dimensao2 ] Of Extended ;Var Mat : Matriz ; Linha : Dimensao1 ; Coluna : Dimensao2 ;begin

For Linha := 1 To Tot_Linhas Do For Coluna := 1 To Tot_Colunas Do

Mat [ Linha , Coluna ] := 0 ;

Assim, qualquer alteração nas dimensões da matriz, acarretará a modificação apenas de pouca linhas de código.

Podemos então definir a sintaxe geral de declaração de um tipo Array de "n" dimensões:

Nome_Var_Array : Array [ li1 .. lf1 , li2 .. lf2 , .... , lin .. lfn ] Of Tipo_Array ;

Obs6.: Tome cuidado com a quantidade de memória alocada, pois um Array de strings pode chegar a alocar alguns MegaByte, dependendo das strings que você venha a manipular.

Obs7.: Como se pode trabalhar então com dados de diferentes tipos? Caso você queira trabalhar com as notas de vários alunos de uma turma, calculando a média de cada aluno, a média da turma, etc., você pode declarar uma matriz de strings para armazenar os nomes de cada aluno e declarar duas outras matrizes reais, para armazenar as notas da primeira prova e da segunda prova (considere somente estas duas notas). Assim sendo, o aluno que estiver na posição 1 da matriz de strings, terá sua primeira nota armazenada na posição 1 da primeira matriz real e terá sua segunda nota armazenada na segunda matriz real, e assim por diante, como esquematizado abaixo:

Matriz de strings (Contém os nomes dos alunos)

1ª Matriz real (Notas da primeira

Nome do Nome do Nome do Nome doAluno nº 1 Aluno nº 2 Aluno nº 3 Aluno nº n

1ª Nota do 1ª Nota do 1ª Nota do 1ª Nota doAluno nº 1 Aluno nº 2 Aluno nº 3 Aluno nº n

Page 80: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 80 Todos os direitos reservados.

prova)

2ª Matriz real(Notas da segunda prova)

Caso o nome da matriz de strings seja igual a Nome, a primeira matriz real seja N1 e a segunda matriz real seja igual a N2, implicará em:

Nome [ 1 ] = Nome do aluno 1N1 [ 1 ] = Nota da primeira prova do aluno 1N2 [ 1 ] = Nota da segunda prova do aluno 1

Nome [ 2 ] = Nome do aluno 2N1 [ 2 ] = Nota da primeira prova do aluno 2N2 [ 2 ] = Nota da segunda prova do aluno 2

Nome [ 3 ] = Nome do aluno 3N1 [ 3 ] = Nota da primeira prova do aluno 3N2 [ 3 ] = Nota da segunda prova do aluno 3

Nome [ n ] = Nome do aluno nN1 [ n ] = Nota da primeira prova do aluno nN2 [ n ] = Nota da segunda prova do aluno n

Vamos agora fazer uma aplicação que leia o nome de todos os alunos de uma classe, as respectivas notas das duas provas realizadas (assuma que a falta do aluno é considerada nota zero) e no final imprima a média de cada aluno e a média da turma.

Comece uma nova aplicação Coloque três labels, três edit box e um botão no form Altere o caption de:

Label1: Nome do aluno Label2: Nota 1 Label3: Nota 2 Button1: &Incluir

Apague a propriedade Text de todos os edit box Altere a propriedade CharCase de Edit1 para ecUpperCase

2ª Nota do 2ª Nota do 2ª Nota do 2ª Nota do Aluno nº 1 Aluno nº 2 Aluno nº 3 Aluno nº n

Page 81: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 81 Todos os direitos reservados.

Al

tere a propriedade Name de: Edit1: ebNome Edit2: ebN1 Edit3: ebN2

Insira logo abaixo da diretiva de compilação {$R *.DFM} linhas de código contendo uma seção Const, uma seção Type e uma seção Var, como mostrado abaixo:

implementation

{$R *.DFM}

Const Num_Alunos = 5 ;Type Limite = 1 .. Num_Alunos ; Tipo_Nome = String [ 15 ] ; Mat_Nomes = Array [ Limite ] Of Tipo_Nome ; Mat_Notas = Array [ Limite ] Of Extended ;Var Nome : Mat_Nomes ; N1 , N2 : Mat_Notas ;

i : Limite ;

end.

Manipule o evento OnClick de Button1 com:

Page 82: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 82 Todos os direitos reservados.

procedure TForm1.Button1Click(Sender: TObject);Var k : Limite ; Soma1 , Soma2 : Extended ;begin Nome [ i ] := ebNome.Text ; N1 [ i ] := StrToFloat ( ebN1.Text ) ; N2 [ i ] := StrToFloat ( ebN2.Text ) ; Inc ( i ) ; ebNome.SetFocus ; If i > Num_Alunos Then begin Memo1.Clear ; Memo1.Visible := True ; Soma1 := 0 ; Soma2 := 0 ; For k := 1 To Num_Alunos Do begin Soma1 := Soma1 + N1 [ k ] ; Soma2 := Soma2 + N2 [ k ] ; Memo1.Lines.Add ( Format ( ' Aluno = %15s - Nota1 = %4.1f Nota2 = %4.1f Média = %4.1f ' , [ Nome [ k ] , N1 [ k ] , N2 [ k ], ( N1 [ k ] + N2 [ k ] ) / 2 ] ) ) ; end ; Soma1 := Soma1 / Num_Alunos ; Soma2 := Soma2 / Num_Alunos ; Memo1.Lines.Add ( Format ( ' Média da Turma = %4.1f ' , [ ( Soma1 + Soma2 ) / 2 ] ) ) ; end ;end ;

Obs8.: As linhas de comando: "Memo1.Lines.Add ( Format ... " foram diminuídas devido ao seu tamanho exceder os limites da página na qual a apostila está sendo escrita. No Delphi, você deverá digitar a linha de comando sem se preocupar em alterar o tamanho da fonte. A função Format contém o seguinte:

primeira ocorrência:

Format ( ' Aluno = %15s - Nota1 = %4.1f Nota2 = %4.1f Média = %4.1f ' , [ Nome [ k ] , N1 [ k ] , N2 [ k ] , ( N1 [ k ] + N2 [ k ] ) / 2 ] ) ) ;

segunda ocorrência:

Format ( ' Média da Turma = %4.1f ' , [ ( Soma1 + Soma2 ) / 2 ] ) ) ;

Coloque um componente Memo no form, de tal maneira que ele encubra os edit box e o botão

Page 83: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 83 Todos os direitos reservados.

Altere a propriedade Visible do componente Memo1 para False

Execute o aplicativo.

Digite vários nomes e várias notas e veja o resultado quando aparecer o componente Memo1. Você deve ter observado que os dados do primeiro aluno não aparecem, enquanto que um sexto aluno (o array contém 5 elementos) aparece nas estatísticas. Por que? Porque o aplicativo não sabe qual é o valor inicial da variável "i". Feche o aplicativo.

Adicione antes do "end." da unit as seguintes linhas de comando:

Initialization i := 1 ;

Tudo que se encontra na área de inicialização de uma unit é executada antes que qualquer comando ou manipulação de evento. Assim fazendo, quando você manipula o click de Button1 pela primeira vez, a variável "i" é igual a 1.

Execute novamente o aplicativo e veja agora o resultado correto aparecer na tela.

Feche o aplicativo.

Obs9.: O porquê de se ter declarado a constante, os tipos e as variáveis após a diretiva de compilação e não dentro de uma manipulação de evento, deveu-se à necessidade de termos essas declarações com um aspecto global (válido por toda a unit e não somente dentro da manipulação de um determinado evento). Quando uma manipulção de evento é executada, tudo aquilo que é declarado nela (constantes, tipos e variáveis) é criado e, ao término da manipulação do evento, tudo aquilo que foi declarado é destruído, desalocando a memória requerida. Porém, como era de interesse armazenar até o final da execução do aplicativo os dados armazenados nas matrizes (nomes e notas), foi preciso criar estruturas globais, e não locais a uma determinada manipulação de evento.

Obs10.: A função Add faz o mesmo que a procedure Append porém, a função Add retorna um valor inteiro que significa qual o índice da nova string (qual é a posição da string no componente memo).

Page 84: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 84 Todos os direitos reservados.

8. Registros

São estruturas que servem para armazenar, sob uma mesma variável, valores de tipos diferentes, mas que são correlacionados.

A sintaxe geral é:

Var Nome_Var_Registro : Record

Campo1 : Tipo1 ;Campo2 : Tipo2 ;

Campon : Tipon ;

end ;

Podemos utilizar também a cláusula Type:

Type TNome_Var_Registro : Record

Campo1 : Tipo1 ;Campo2 : Tipo2 ;

Campon : Tipon ;

end ;

VarNome_Var_Registro : TNome_Var_Registro ;

Adotando a notação do Delphi de sempre começar um tipo pela letra T (maiúscula).Uma vez declarada a variável Record, podemos atribuir valores aos seus campos

utilizando a notação:

Nome_Var_Registro.Nome_do_Campo := Valor ;

ou seja, para referenciarmos um campo de Record, digitamos o nome da variável e o nome do campo em questão, separados por um ponto (. ).

Page 85: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 85 Todos os direitos reservados.

No exemplo anterior, onde foi necessário o armazenamento de um nome e duas notas, poderíamos ter utilizado o tipo Record, o que nos aumentaria a performance:

Type TDados_Aluno : Record

Nome : String [ 15 ] ;N1 : Extended ;N2 : Extended ;

end ;

VarAluno : T Dados_Aluno ;

Feito isto, o aluno Fulano de Tal cuja nota na primeira prova foi 8,5 e cuja segunda nota foi 7,3 , pode ter seus dados armazenados da seguinte forma:

Aluno.Nome := ' Fulano de Tal ' ;Aluno.N1 := 8.5 ;Aluno.N2 := 7.3 ;

Obs1.: Observe que a notação americana para separação de casas decimais utiliza o ponto decimal, e não a vírgula. Por isso, um número real é denominado: valor em ponto-flutuante.

Você também pode utilizar a cláusula With / Do para referenciar os campos de um registro:

With Aluno Dobegin

Nome := ' Fulano de Tal ' ;N1 := 8.5 ;N2 := 7.3 ;

end ;

Mas não adianta muito, armazenar somente os dados de um aluno. Se reescrevêssemos o programa anterior, precisaríamos de 5 variáveis record para representar todos os alunos da turma, o que não faz muito sentido, pois a digitação seria muito grande (imagine para uma turma de 100 alunos!).

Como nós precisamos armazenar os dados dos alunos de uma turma inteira, precisamos declarar um Array de registros, para que possamos manipular os vários dados envolvidos, sem nos preocuparmos com os n Arrays necessários para essa implementação.

Page 86: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 86 Todos os direitos reservados.

Para tanto, observe a declaração abaixo:

Const Num_Alunos = 5 ;Type Limite = 1 .. Num_Alunos ;

TDados_Aluno = Record Nome : String [ 15 ] ;N1 : Extended ;N2 : Extended ;

end ;TAluno = Array [ Limite ] Of TDados_Aluno ;

Var Aluno : TAluno ;

i : Limite ;

Aqui, a cada click do botão, em vez de fazer:

Nome [ i ] := ebNome.Text ; N1 [ i ] := StrToFloat ( ebN1.Text ) ; N2 [ i ] := StrToFloat ( ebN2.Text ) ; Inc ( i ) ;

para armazenar os vários dados em diferentes arrays, declarado o array de record poderíamos fazer:

Aluno[i].Nome := ebNome.Text ;Aluno[i].N1 := StrToFloat ( ebN1.Text ) ;Aluno[i].N2 := StrToFloat ( ebN2.Text ) ;Inc ( i ) ;

Ou, utilizando a cláusula With / Do :

With Aluno[i] Dobegin

Nome := ebNome.Text ;N1 := StrToFloat ( ebN1.Text ) ;N2 := StrToFloat ( ebN2.Text ) ;

end ;Inc ( i ) ;

Page 87: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 87 Todos os direitos reservados.

Vamos alterar o programa (unit1) anterior.

Altere a manipulaçao de Button1:

procedure TForm1.Button1Click(Sender: TObject);Var k : Limite ; Soma1 , Soma2 : Extended ;begin

With Aluno[i] Dobegin

Nome := ebNome.Text ;N1 := StrToFloat ( ebN1.Text ) ;N2 := StrToFloat ( ebN2.Text ) ;

end ; Inc ( i ) ; ebNome.SetFocus ; If i > Num_Alunos Then begin Memo1.Clear ; Memo1.Visible := True ; Soma1 := 0 ; Soma2 := 0 ; For k := 1 To Num_Alunos Do With Aluno [ k ] Do begin Soma1 := Soma1 + N1 ; Soma2 := Soma2 + N2 ; Memo1.Lines.Add ( Format ( ' Aluno = %15s - Nota1 = %4.1f Nota2 = %4.1f Média = %4.1f ' , [ Nome, N1 , N2, ( N1 + N2 ) / 2 ] ) ) ; end ; Soma1 := Soma1 / Num_Alunos ; Soma2 := Soma2 / Num_Alunos ; Memo1.Lines.Add ( Format ( ' Média da Turma = %4.1f ' , [ ( Soma1 + Soma2 ) / 2 ] ) ) ; end ;end ;

Obs2.: Mais uma vez é importante lembrar que:as linhas de comando: "Memo1.Lines.Add ( Format ... " foram diminuídas devido ao seu tamanho exceder os limites da página na qual a apostila está sendo escrita. No Delphi, você deverá digitar a linha de comando sem se preocupar em alterar o tamanho da fonte. A função Format contém o seguinte:primeira ocorrência:

Format ( ' Aluno = %15s - Nota1 = %4.1f Nota2 = %4.1f Média = %4.1f ' , [ Nome , N1 , N2 , ( N1 + N2 ) / 2 ] ) ) ;

segunda ocorrência:

Format ( ' Média da Turma = %4.1f ' , [ ( Soma1 + Soma2 ) / 2 ] ) ) ;

Page 88: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 88 Todos os direitos reservados.

Altere agora as declarações globais:

implementation

{$R *.DFM}

Const Num_Alunos = 5 ;Type Limite = 1 .. Num_Alunos ; Tipo_Nome = String [ 15 ] ;

TDados_Aluno = Record Nome : Tipo_Nome ;N1 : Extended ;N2 : Extended ;

end ;TAluno = Array [ Limite ] Of TDados_Aluno ;

Var Aluno : TAluno ;

i : Limite ;

Execute o aplicativo e depois o feche.

Obs3.: A unit1, ao final, deverá ser igual ao código que segue:

unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type TForm1 = class(TForm) ebNome: TEdit; Label1: TLabel; Label2: TLabel; ebN1: TEdit; Label3: TLabel; ebN2: TEdit; Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;

var Form1: TForm1;

Page 89: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 89 Todos os direitos reservados.

implementation

{$R *.DFM}

Const Num_Alunos = 5 ;Type Limite = 1 .. Num_Alunos ; Tipo_Nome = String [ 15 ] ; TDados_Aluno = Record Nome : Tipo_Nome ; N1 : Extended ; N2 : Extended ; end ; TAluno = Array [ Limite ] Of TDados_Aluno ;Var Aluno : TAluno ;

i : Limite ;

procedure TForm1.Button1Click(Sender: TObject);Var k : Limite ; Soma1 , Soma2 : Extended ;begin With Aluno[i] Do begin Nome := ebNome.Text ; N1 := StrToFloat ( ebN1.Text ) ; N2 := StrToFloat ( ebN2.Text ) ; end ; Inc ( i ) ; ebNome.SetFocus ; If i > Num_Alunos Then begin Memo1.Clear ; Memo1.Visible := True ; Soma1 := 0 ; Soma2 := 0 ; For k := 1 To Num_Alunos Do With Aluno [ k ] Do begin Soma1 := Soma1 + N1 ; Soma2 := Soma2 + N2 ; Memo1.Lines.Add ( Format ( ' Aluno = %15s - Nota1 = %4.1f Nota2 = %4.1f Média = %4.1f ' , [ Nome, N1 , N2, ( N1 + N2 ) / 2 ] ) ) ; end ; Soma1 := Soma1 / Num_Alunos ; Soma2 := Soma2 / Num_Alunos ; Memo1.Lines.Add ( Format ( ' Média da Turma = %4.1f ' , [ ( Soma1 + Soma2 ) / 2 ] ) ) ; end ;end ;

Initialization i := 1 ;

end.

Page 90: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 90 Todos os direitos reservados.

9. Ponteiros

Quando você declara uma variável (variável de memória), você na realidade está alocando memória para armazenar valores compatíveis com o tipo da variável, isto é, se você declara uma variável do tipo Byte, você está alocando 1 byte de memória para armazenar valores entre 0 e 255. Se você declara uma variável do tipo Word, você está alocando 2 bytes de memória para armazenar valores entre 0 e 65535, e assim por diante. Quando você quiser manipular o valor armazenado em uma determinada posição de memória, basta que você utilize a variável correspondente, declarada na seção Var. Na realidade, nem lembramos que, ao manipular uma variável, estamos na verdade manipulando uma dada porção de memória. Para grandes quantidades de memória, podemos utilizar um Array de n posições. Mas e se você não souber a quantidade de dados que serão manipulados? Por exemplo, imagine que você todo dia digita uma quantidade de informações (como as informações contidas em cheques) para dar entrada em um processamento contábil. Num dia você só digita 200 informações, mas no outro dia você chega a digitar 1500 informações. O que você faria? Delimitaria, com certeza, um Array com 1500 posições. Mas e se um outro dia você precisasse manipular 2300 informações? E assim por diante.

Para resolver casos como esse, podemos trabalhar com a memória diretamente, alocando ou desalocando memória, de acordo com as nossas necessidades. Variáveis que, ao invés de armazenarem um valor qualquer, armazenam um endereço de memória são chamadas Ponteiros de Memória ou simplesmente Ponteiros.

Imagine a memória como sendo uma longa fila, onde você pode armazenar valores em posições de memória, como mostrado abaixo:

endereço 1 - variável V1

endereço 2 - variável V2

endereço 3 - variável V3

endereço 4 - variável V4

endereço 5 - variável V5

endereço 7 - variável V7

endereço 8 - variável V8

endereço 9 - variável V9

Isto significa que, a variável V1, que está associada à posição de memória endereço 1, contém o valor numérico 12, ou seja, quando foi realizada a operação:

V1 := 12 ;na realidade foi atribuído o valor 12 àquela posição de memória, como mostrado acima. E temos a mesma explicação para as demais variáveis.

12

456

-20

33

1054

220

0

758

36

endereço 6 - variável V6

Page 91: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 91 Todos os direitos reservados.

Para declarar uma variável ponteiro, você digita o caractere circunflexo antes do tipo desejado, ou seja, você cria uma variável para conter a posição de memória alocada para um tipo Pascal conhecido. Por exemplo, para criar um ponteiro para inteiro:

Var Var_Ponteiro : ^Integer ;

E para atribuir um valor à posição de memória apontada pela variável ponteiro, você utiliza o mesmo circunflexo após o nome da variável. Por exemplo, para atribuir o valor 1023 à variável ponteiro acima, faça:

Var_Ponteiro^ := 1023 ;

O operador @ atribui a um ponteiro o endereço de memória de uma variável. Por exemplo,

Comece uma nova aplicação Coloque um memo e um botão no form Manipule o evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);Var Num : Integer ; P1 , P2 : ^Integer ;begin Num := 1025 ; P1 := @Num ; P2 := P1 ; P2^ := 50 ;

Memo1.Lines.Append ( IntToStr ( Num ) ) ;Memo1.Lines.Append ( IntToStr ( P1^ ) ) ;Memo1.Lines.Append ( IntToStr ( P2^ ) ) ;

end;

Isto significa dizer que P1 recebeu o endereço de memória da variável Num e que P2 recebeu o conteúdo de P1, que em última análise é o endereço de memória da variável Num. Ao alterar o conteúdo de memória apontada por P2, você alterou o conteúdo da variável Num, como atesta a listagem de Memo1. Esquematicamente teríamos:

P1

Num

P2

Feche a aplicação.

1025

Page 92: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 92 Todos os direitos reservados.

Na realidade, trabalhar com ponteiros em Pascal não é uma tarefa das mais simples, se comparada ao uso de ponteiros na linguagem C.

Uma forma razoavelmente simples de trabalhar com ponteiros no Pascal, é fazer o uso de listas ligadas, para o que você pode seguir os passos abaixo:

1. Idealizar a estrutura de um registro (o nome e os campos)2. Seção Type: Definir um tipo ponteiro para esse registro3. Seção Type: Definir um registro que contenha, além dos campos idealizados

em "1." , um campo que seja do tipo ponteiro definido em "2.", com o nome Prox

4. Seção Var: Declarar três variáveis ponteiro do tipo definido em "2." : uma de nome P, outra de nome Inicio e a outra de nome Anterior.

Por exemplo, vamos redefinir o record que armazena dados dos alunos:

Type TAluno = ^TDados_Aluno ; TDados_Aluno = Record Nome : String ; N1 : Extended ; N2 : Extended ; Prox : TAluno ; end ;Var P , Inicio, Anterior : TAluno ;

5. Pedir alocação de memória para a variável ponteiro, através da procedure New e atribuir o valor Nil ao campo Prox (sendo Nil o equivalente ao valr nulo para variáveis ponteiros, isto é, um ponteiro que contenha o valor Nil não aponta para lugar nenhum):

New ( P ) ;P^.Prox := Nil ;

6. Guardar o endereço inicial na variável ponteiro Inicio: Inicio := P ;7. Guardar o endereço de P na variável Anterior: Anterior := P ;8. Armazenar informações sobre um aluno nos campos do registro atualmente

apontado por P : P^.Nome := Edit1.Text ;P^.N1 := StrToFloat (Edit2.Text ) ;P^.N2 := StrToFloat (Edit3.Text ) ;

9. Para armazenar um novo aluno, alocar mais memória para P (é como se você estivesse incrementando de 1 o índice final do Array de registros):

New ( P ) ;P^.Prox := Nil ;

10. Como Anterior possui o endereço de memória anterior à nova alocação, atualize o campo Prox do registro anterior: Anterior^.Prox := P ;

11. Atualize o ponteiro Anterior com o novo endereço de P: Anterior := P ;12. Retorne ao item "8." até não ser mais necessária a entrada de dados.

Até este ponto, temos vários registros na memória, sendo que o endereço do primeiro registro está armazenado na variável Inicio.

Page 93: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 93 Todos os direitos reservados.

Graficamente, o que você fez com os passos anteriores foi:

- item 5. :

- item 6. :

- item 7. :

Por hipótese, vamos supor que os edit box contenham os dados: AL1 , 10 e 8.2 :

- item 8. :

NomeN1N2Prox Nil

endereço do 1º registro: E1

P

NomeN1N2Prox Nil

endereço do 1º registro: E1

P Inicio

NomeN1N2Prox Nil

endereço do 1º registro: E1

P Inicio

Anterior

Nome AL1 N1 10.0 N2 8.2 Prox Nil

endereço do 1º registro: E1

P Inicio

Anterior

Page 94: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 94 Todos os direitos reservados.

- item 9. :

Observe que P aponta para o novo registro, mas Anterior ainda aponta para o registro anteriormente criado.

- item 10. :

O campo Prox do primeiro registro contém o endereço do próximo registro que, neste caso, é o endereço de memória que contém o segundo registro. Só nos falta agora, antes de alterar os campos do registro corrente (2º registro), atualizar a variável ponteiro Anterior para, num próximo passo, repetir as ações acima (a partir do item "8.").

Nome AL1 N1 10.0 N2 8.2 Prox Nil

NomeN1N2 Prox Nil

endereço do 1º registro: E1

Anterior Inicio

endereço do 2º registro: E2

P

Nome AL1 N1 10.0 N2 8.2 Prox E2

NomeN1N2 Prox Nil

endereço do 1º registro: E1

Anterior Inicio

endereço do 2º registro: E2

P

Page 95: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 95 Todos os direitos reservados.

- item 11. :

Retornando ao item 8:

Vamos supor que, agora, os edit box contenham os seguintes dados: AL2 , 6.2 e 7.5 :

- item 8. :

Nome AL1 N1 10.0 N2 8.2 Prox E2

NomeN1N2 Prox Nil

endereço do 1º registro: E1

Inicio

endereço do 2º registro: E2

P Anterior

Nome AL1 N1 10.0 N2 8.2 Prox E2

Nome AL2N1 6.2N2 7.5Prox Nil

endereço do 1º registro: E1

Inicio

endereço do 2º registro: E2

P Anterior

Page 96: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 96 Todos os direitos reservados.

- item 9. :

- item 10. :

Nome AL1 N1 10.0 N2 8.2 Prox E2

Nome AL2N1 6.2N2 7.5Prox Nil

Nome N1 N2 Prox Nil

endereço do 1º registro: E1

Inicio

endereço do 2º registro: E2

Anterior

endereço do 3º registro: E3

P

Nome AL1 N1 10.0 N2 8.2 Prox E2

Nome AL2N1 6.2N2 7.5Prox E3

Nome N1 N2 Prox Nil

endereço do 1º registro: E1

Inicio

endereço do 2º registro: E2

Anterior

endereço do 3º registro: E3

P

Page 97: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 97 Todos os direitos reservados.

E mais uma vez Anterior é atualizado com o endereço contido em P e há o retorno ao item 8, até não mais ser necessária a alocação de mais memória.

Agora nós vamos fazer o oposto: vamos recuperar as informações armazenadas na memória, como mostra os demais passos:

13. Atribuir à P o conteúdo da variável Inicio: P := Inicio ;14. Enquanto o campo Prox for diferente de Nil faça:

14.1. Visualizar os dados armazenados no registro (nos campos do registro):

Memo1.Lines.Add ( ' Format ( ' %s - N1 = %4.1f N2 = %4.1f ' , [ P^.Nome , P^.N1 , P^.N2 ] ) ;

14.2. Atualizar o conteúdo de P com o endereço do próximo registro ( que está armazenado no campo Prox do registro atual): P := P^.Prox ;

15. Liberar a memória alocada por P (por Anterior e por Inicio): Dispose ( P ) ;

Vamos criar um aplicação que realize os passos acima.

Comece uma nova aplicação Adicione ao form três label, três edit box, um botão e um memo Apague o Text dos edit box e altere o Caption de Button1 para &Incluir Alterar a propriedade CharCase de Edit1 para ecUpperCase Após a diretiva de compilação {$R *.DFM} e antes do end. da unit, digite as

linhas abaixo para criar os tipos e variáveis globais e a seção de inicialização (digite apenas o que estiver dentro do retângulo, pois o resto o Delphi já fez):

{$R *.DFM}

Page 98: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 98 Todos os direitos reservados.

end. Manipule o evento OnClick de Button1 com:

procedure TForm1.Button1Click(Sender: TObject);begin With P^ Do

Type

TAluno = ^TDados_Aluno ; TDados_Aluno = Record

Nome : String ; N1 : Extended ; N2 : Extended ; Prox : TAluno ;

End ;

Var

P , Inicio , Anterior : TAluno ;

Initialization

New ( P ) ; Inicio := P ; Anterior := P ;

P^.Prox := Nil ;

Page 99: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 99 Todos os direitos reservados.

begin Nome := Edit1.Text ; N1 := StrToFloat ( Edit2.Text ) ; N2 := StrToFloat ( Edit3.Text ) ; end ; New ( P ) ; P^.Prox := Nil ; Anterior^.Prox := P ; Anterior := P ; Edit1.SetFocus ;end;

Manipule o evento OnDblClick de Memo1 com:

procedure TForm1.Memo1DblClick(Sender: TObject);begin P := Inicio ; While P^.Prox <> Nil Do begin Memo1.Lines.Add ( Format ( ' %S N1 = %4.1f N2 = %4.1f ' , [ P^.Nome , P^.N1 , P^.N2 ] ) ) ; P := P^.Prox ; end ;end;

Manipule o evento OnClose de Form1 com:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);begin Dispose ( P ) ;end;

Execute o aplicativo Digite um nome e duas notas ; clique no botão Repita esse procedimento para quantos alunos você desejar Dê um clique duplo em Memo1 e veja o relatório Feche o aplicativo

Agora, se nós quisermos imprimir ao contrário da ordem de entrada, precisamos de mais um campo no nosso registro, que é o campo ponteiro Antes , que como o próprio nome diz, conterá o endereço do registro anterior.

Aqui nos preocuparemos também em armazenar o endereço anterior ao endereço atualmente apontado por P. Observe que o endereço anterior ao primeiro endereço

Page 100: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 100 Todos os direitos reservados.

alocado será igual a Nil, ou seja, não apontará para lugar algum, pois não há endereço que esteja alocado pelo ponteiro P.

Outra coisa que você irá notar, é que podemos escrever os nomes dos campos de mesmo tipo, separados por vírgulas, e ao final digitar os dois pontos e o tipo dos campos.

Comece uma nova aplicação Adicione ao form três label, três edit box, um botão, um memo e dois

RadioButton (aba Standard):

Obs1. : Os

componentes RadioButton são mutuamente exclusivos, o que significa dizer que, uma vez que um deles é clicado, o outro deixa de ser selecionado (sua propriedade Checked passa para False), como são os botões de um rádio. Por isso seu nome é RadioButton.

Altere a propriedade Caption de RadioButton1 para Crescente Altere a propriedade Name de RadioButton1 para rbC Altere também a propriedade Checked deste componente para True Altere a propriedade Caption de RadioButton2 para Decrescente Altere a propriedade Name de RadioButton2 para rbD Apague a propriedade Text dos edit box Altere o Caption de Button1 para &Incluir Alterar a propriedade CharCase de Edit1 para ecUpperCase

Após a diretiva de compilação {$R *.DFM} e antes do end. da unit, digite as linhas abaixo para criar os tipos e variáveis globais e a seção de inicialização:

Type TAluno = ^TDados_Aluno ;

Page 101: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 101 Todos os direitos reservados.

TDados_Aluno = Record Nome : String ; N1 : Extended ; N2 : Extended ; Antes , Prox : TAluno ; End ;

Var P , Inicio , Anterior : TAluno ;

Initialization New ( P ) ; Inicio := P ; Fim := P ; Anterior := P ; P^.Prox := Nil ; P^.Antes := Nil ;

Obs2.: Note a variável Fim, que armazena o último endereço.

Manipule o evento OnClick de Button1 com:

procedure TForm1.Button1Click(Sender: TObject);begin With P^ Do begin Nome := Edit1.Text ; N1 := StrToFloat ( Edit2.Text ) ; N2 := StrToFloat ( Edit3.Text ) ; end ; Fim := P ; {Atualiza Fim, pois aqui estão os dados do último aluno} New ( P ) ; {Aloca mais memória para outro registro} P^.Prox := Nil ; P^.Antes := Anterior ; Anterior^.Prox := P ; Anterior := P ; Edit1.SetFocus ;end;

Obs3.: Note que foi adicionada a linha:P^.Antes := Anterior ;

a esta manipulação de evento, pois agora precisamos armazenar, no novo endereço, o endereço anterior, que está armazenado na variável Anterior.

Manipule o evento OnDblClick de Memo1 com:

procedure TForm1.Memo1DblClick(Sender: TObject);begin Memo1.Clear ;

Page 102: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 102 Todos os direitos reservados.

If rbC.Checked Then begin P := Inicio ; While P^.Prox <> Nil Do begin Memo1.Lines.Add ( Format ( ' %S N1 = %4.1f N2 = %4.1f ' , [ P^.Nome , P^.N1 , P^.N2 ] ) ) ; P := P^.Prox ; end ; end Else begin P := Fim ; While P^.Antes <> Nil Do begin Memo1.Lines.Add ( Format ( ' %S N1 = %4.1f N2 = %4.1f ' , [ P^.Nome , P^.N1 , P^.N2 ] ) ) ; P := P^.Antes ; end ;

{ Quando o campo P^.Antes for igual a Nil, é porque foi alcançado o primeiro registro, então devem ser impressos os dados desse primeiro aluno } Memo1.Lines.Add ( Format ( ' %S N1 = %4.1f N2 = %4.1f ' , [ P^.Nome , P^.N1 , P^.N2 ] ) ) ; end ;end;

Execute o aplicativo Digite os dados do primeiro aluno e clique o botão Digite os dados do segundo aluno e clique o botão Digite os dados do terceiro aluno e clique o botão Dê um duplo clique em Memo1 Dê um clique em rbD (radiobutton cujo Caption é Decrescente) Dê novo duplo clique em Memo1 Feche o aplicativo

10. Proteção Contra Erros em Tempo de Execução

Comece uma nova aplicação Coloque três Edit box e um Botão no Form Manipule o evento OnClick de Button1 com:

Page 103: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 103 Todos os direitos reservados.

procedure TForm1.Button1Click(Sender: TObject);Var A , B , C : ^Extended ;begin New (A) ; New (B) ; New (C) ; C^ := -1 ; A^ := StrToFloat (Edit1.Text) ; B^ := StrToFloat (Edit2.Text) ; C^ := A^ / B^ ; Edit3.Text := FloatToStrF (C^ , ffFixed , 1 , 2) ; Dispose (A) ; Dispose (B) ; Dispose (C) ;end;

Execute a aplicação e digite os valores: 10 e 2 , e dê um clique em seguida no botão.

Digite agora os valores: 10 e 0 (zero) e dê um clique no botão. Veja que o programa é interrompido com uma mensagem de erro e o resultado em Edit3 ainda possui o valor anterior: 5.00. Feche a aplicação.

Obs1.: A função FloatToStrF retorna uma string formatada da transformação do valor Extended entre parênteses. Para uma obtenção dos parâmetros, vide o Help online do Delphi.

Para evitar quebras do programa pela execução de uma "exceção", utilizamos blocos de proteção contra erros em tempo de execução (Run-Time Errors).

Nas lições anteriores, você trabalhou com ponteiros de memória, e viu que, para utilizá-los, é preciso alocar memória através da procedure New, mas ao final do seu uso, é preciso "devolver" essa memória alocada ao Sistema Operacional, sob pena de uma redução drástica nos recursos do sistema. Esta desalocação se faz com a procedure Dispose.

Agora suponha que, após alocar 10 MB de RAM para a utilização de uma variável ponteiro, você executa uma operação ilegal, semelhante àquela realizada acima (divisão por zero). Não há como desalocar a memória utilizada pelo ponteiro. A não ser que você utilize o bloco de proteção: TRY / FINALLY / END.

Sua sintaxe geral é:

TryComando 1 ;

Page 104: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 104 Todos os direitos reservados.

Comando 2 ;

Comando n ;Finally

ComandoFinal1 ;ComandoFinal2 ;

ComandoFinalm ;End ;

Assim, independente de haver ou não um erro em tempo de execução (desde que não haja, obviamente, o desabamento do Sistema Operacional), os ComandoFinali serão executados normalmente.

Reescreva a manipulação de evento acima com:

procedure TForm1.Button1Click(Sender: TObject);Var A , B , C : ^Extended ;begin Try New (A) ; New (B) ; New (C) ; C^ := -1 ; A^ := StrToFloat (Edit1.Text) ; B^ := StrToFloat (Edit2.Text) ; C^ := A^ / B^ ; Finally Edit3.Text := FloatToStrF (C^ , ffFixed , 1 , 2) ; Dispose (A) ; Dispose (B) ; Dispose (C) ; End ;end;

Execute a aplicação Digite os valores: 10 e 2 e clique o botão. Veja o resultado: 5.00 . Digite agora os valores: 10 e 0 (zero) e clique o botão. Veja que o resultado

apresentado é igual a -1, pois independente de ter havido o erro de divisão por zero, é impresso o conteúdo de memória alocada por C (como houve erro de divisão por zero, este conteúdo não é alterado pela divisão de A por B, pois a atribuição é cancelada no momento do erro).

feche a aplicação.

Page 105: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 105 Todos os direitos reservados.

Um outro bloco de proteção que pode ser usado é o bloco TRY / EXCEPT / END, que difere-se do bloco anterior por não executar um bloco de código de maneira incondicional, e sim, na ocorrência de uma exceção.

Sua sintaxe geral é:

TryComando1 ;Comando2 ;

Comandon ;Except ComandoExceção 1 ;

ComandoExceção 2 ;

ComandoExceção m ;End ;

Reescreva o código OnClick acima com (substitua Finally por Except):

procedure TForm1.Button1Click(Sender: TObject);Var A , B , C : ^Extended ;begin Try New (A) ; New (B) ; New (C) ; C^ := -1 ; A^ := StrToFloat (Edit1.Text) ; B^ := StrToFloat (Edit2.Text) ; C^ := A^ / B^ ; Edit3.Text := FloatToStrF (C^ , ffFixed , 1 , 2) ; Dispose (A) ; Dispose (B) ; Dispose (C) ; Except ShowMessage ( ' O denominador não pode ser zero! ' ) ; End ;end;

Execute a aplicação, repita a digitação dos valores como você já fez acima.Feche o aplicativo.

Neste caso, qualquer execução que gere um erro em tempo de execução será protegido pelo bloco TRY / EXCEPT / END.

Você pode estar se perguntando neste momento: Por que não utilizar o If / Then para testar se o valor do denominador é igual a zero, antes de executar a divisão?

Page 106: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 106 Todos os direitos reservados.

Simples: porque toda a vez que a manipulação for executada, o comando If / Then testará se a condição é ou não verdadeira. Isso significa que a performance do código é diminuída. Ao contrário, se você utilizar o bloco TRY / EXCEPT / END, não haverá condição a ser testada, aumentando a performance do código.

O código acima ainda necessita de uma alteração pois, se houver uma divisão por zero, a procedure ShowMessage é executada, porém não é impresso o valor -1 como resultado final, e nem os ponteiros sofrem o Dispose. Para corrigir tal problema, vamos aninhar o bloco TRY / EXCEPT / END num bloco TRY / FINALLY / END.

Reescreva o código OnClick acima com:

procedure TForm1.Button1Click(Sender: TObject);Var A , B , C : ^ Extended ;begin Try Try New (A) ; New (B) ; New (C) ; C^ := -1 ; A^ := StrToFloat (Edit1.Text) ; B^ := StrToFloat (Edit2.Text) ; C^ := A^ / B^ ; Except ShowMessage ( ' O denominador não pode ser zero! ' ) ; End ; Finally Edit3.Text := FloatToStrF (C^ , ffFixed , 1 , 2) ; Dispose (A) ; Dispose (B) ; Dispose (C) ; End ;end;

Execute a aplicaçãoDigite os valores: 10 e 2 e clique o botão. Veja o resultado: 5.00 . Digite agora os valores: 10 e 0 (zero) e clique o botão.Feche o aplicativo.

O bloco de proteção TRY / EXCEPT / END utiliza a RTL (Run-Time Library), que contém exceções definidas na unit SysUtils, sendo que essas exceções descendem de Exception, uma exceção de caráter genérico. Exception provê uma string para a mensagem cuja exceção foi enviada pela RTL.

Page 107: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 107 Todos os direitos reservados.

Quando você simplesmente utiliza TRY / EXCEPT / END como mostrado acima, você perde um pouco do refinamento possível no tratamento de uma exceção, isto é, você pode saber, num dado momento, qual o tipo de exceção que está ocorrendo, alertar o usuário sobre o tipo de erro que o mesmo está cometendo, ou que está acontecendo no sistema. E essa mensagem de alerta pode ser sensível ao contexto da exceção (ser uma mensagem descritiva do problema e uma possível solução).

Para tratar uma exceção como dito acima, devemos conhecer os tipos de exceção enviadas por RTL:

1. E / S2. Heap3. Matemática Inteira4. Matemática de Ponto-Flutuante5. Tipos Incompatíveis6. Conversão7. Hardware

1) E / S (Entrada / Saída - ou I / O - Input / Output)

Ocorrre por exemplo quando se tenta acessar um arquivo ou um dispositivo de saída.

- EIntOutError: contém uma propriedade denominada ErrorCode que indica qual o tipo de erro ocorrido

2) Heap

Ocorre quando se tenta alocar ou acessar memória dinâmica.

- EOutOfMemory: indica que não há espaço suficiente no Heap (memória global, onde são alocadas as variáveis dinâmicas) para completar a operação requisitada.

- EInvalidPointer: indica que a aplicação tentou dispor de um ponteiro que está fora do Heap. Geralmente este ponteiro já sofreu um comando Dispose.

3) Matemática Inteira (EIntError)

- EDivByZero: divisão por zero

- ERangeError: número ou expressão fora do limite (vide no Help online do Delphi, a diretiva de compilação {$R} - coloque o cursor sobre a letra R e pressione a tecla F1)

- EIntOverflow: overflow numa operação inteira (por exemplo: o valor atribuído a uma variável inteira extrapola o limite que ela pode conter)

4) Matemática de Ponto-Flutuante (EMathError)

- EZeroDivide: divisão por zero

Page 108: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 108 Todos os direitos reservados.

- EInvalidOp: operação inválida

- EOverflow: overflow

- EUnderFlow: underflow (o inverso do overflow)

5) Tipos Incompatíveis

- EInvalidCast: ocorre quando você tenta ligar um objeto a um tipo diferente do dele com o operador AS.

6) Conversão

- EConvertError: ocorre quando você tenta converter dados com as funções: IntToStr, StrToInt, StrToFloat etc.

7) Hardware (EFault)

-EGPFault: General Protection Fault, geralmente causado por um ponteiro ou um objeto não inicializado.

-EStackFault: acesso ilegal a um segmento da pilha

-EPageFault: o gerenciador de memória do Windows não foi capaz de usar o arquivo de swap corretamente

-EInvalidOpCode: instrução indefinida, como dado ou memória não inicializada.

-EBreakPoint: interrupção por Breakpoint

-ESingleStep: interrupção por passo simples

Assim sendo, na divisão por zero da manipulação acima, poderíamos utilizar um dos códigos abaixo:

Try

Except trata a exceçãoEnd ;

Try

Except On Exception Do trata a exceçãoEnd ;

Try

Except On EMathError Do trata a exceçãoEnd ;

Try

Except On EZeroDivide Do trata a exceçãoEnd ;

Vamos reescrever novamente a manipulação OnClick anterior:

procedure TForm1.Button1Click(Sender: TObject);Var

Page 109: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 109 Todos os direitos reservados.

A , B , C : ^ Extended ; begin Try Try New (A) ; New (B) ; New (C) ; A^ := StrToFloat (Edit1.Text) ; B^ := StrToFloat (Edit2.Text) ; C^ := A^ / B^ ; Except On EZeroDivide Do begin ShowMessage ( ' O denominador não pode ser zero! ' ) ; C^ := -1 ; end ; End ; Finally Edit3.Text := FloatToStrF (C^ , ffFixed , 1 , 2) ; Dispose (A) ; Dispose (B) ; Dispose (C) ; End ;end;

Execute a aplicação e repita os passos acima para a digitação de valores Feche a aplicação. Para que fique clara a explicação deste capítulo, vamos refazer mais uma vez a

manipulação OnClick anterior, alterando a parte de tratamento das exceções (Except) com o código abaixo:

Except On EZeroDivide Do ShowMessage ( ' O denominador não pode ser zero! ' ) ; On EConvertError Do ShowMessage ( ' Operação Inválida! ' ) ; End ;

Execute a aplicação Digite os valores: 10 e 2 e clique o botão Digite os valores: 10 e 0 e clique o botão. Veja a mensagem de erro. Digite no primeiro edit box o valor: 10 e no outro edit box algo que não seja

um número (uma letra por exemplo). Veja a mensagem de erro. Feche a aplicaçãoAlgumas vezes, você necessitará enviar uma mensagem de erro mais técnica ao

usuário. Nestes casos, você irá "instanciar" um objeto temporário de exceção e utilizar a propriedade Messsage dele.

Page 110: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 110 Todos os direitos reservados.

Altere a manipulação de evento OnClick acima (somente o trecho de Except) com o código:

Except On E : Exception Do

MessageDlg ( ' Aconteceu o seguinte erro: ' + Chr (13) + E.Message , mtError , [mbOK] , 0 ) ;End ;

Execute a aplicação Digite os valores: 10 e 2 e clique o botão Digite os valores: 10 e 0 e clique o botão. Veja a mensagem de erro. Digite no primeiro edit box o valor: 10 e no outro edit box algo que não seja

um número (uma letra por exemplo). Veja a mensagem de erro. Feche a aplicação

Obs2.: Nunca destrua um objeto temporário de exceção, pois a aplicação faz o mesmo, e neste caso ocorre um erro fatal.

Há casos em que você terá que manipular de maneira específica uma determinada exceção, e prever os casos em que outras exceções possam ocorrer. Neste caso, você pode utilizar a cláusula ELSE, como mostrado abaixo:

ExceptOn E : EZeroDivide Do MessageDlg ( ' Aconteceu o seguinte erro: ' + Chr (13) + E.Message , mtError , [mbOK] , 0 ) ;Else ShowMessage ( ' Erro Ignorado ! ' ) ;

End ;

E nos casos em que você precise parar uma operação sem enviar mensagem de erro (exceção silenciosa, como é chamada), você utilizará a procedure Abort , como mostrado abaixo:

For i := 1 To 100 Do If i > StringGrid1.RowCount Then Abort Else begin

Há também a possibilidade de você gerar um erro em tempo de execução, como por exemplo:

procedure TForm1.Button1Click (Sender : Tobject) ;

Page 111: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 111 Todos os direitos reservados.

Var SenhaCorreta : String ;Begin SenhaCorreta := '123456' ; If Edit1.Text <> SenhaCorreta Then

Raise ESenhaErrada.Create ( ' Senha Incorreta ' ) ;

A palavra reservada Raise tem por função "levantar" a exceção criada (Create) com a mensagem 'Senha Incorreta'. Note que, levantar uma exceção é diferente de utilizar um comando If / Then, pois com esse comando não há interrupção do código, o que ocorre com a exceção, e essa interrupção pode ser tratada com um dos blocos de proteção estudados acima.

Obs3.: Para fazer este código funcionar, você tem que declarar ESenhaErrada como uma classe descendente da classe Exception (a declaração deve vir após o end; da declaração de TForm1), como mostrado abaixo:

unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type TForm1 = class(TForm) Edit1: TEdit;private { Private declarations } public { Public declarations } end;

ESenhaErrada = Class (Exception) ;

var Form1: TForm1;

11. Listas de Strings

Trabalha-se com listas de strings quando manipula-se:

Page 112: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 112 Todos os direitos reservados.

- Itens de um ListBox ou ComboBox- Linhas e um texto num Memo- Lista de fontes suportadas pelo vídeo- Linha ou coluna de um StringGrid

Em tempo de execução você utiliza listas de strings para:

- Manipular strings- Carregar e salvar strings- Criar uma nova lista de strings

11.1. Manipulando strings

a) Contando o número de strings:

Comece uma nova aplicação Coloque um Label e altere seu caption para: Total de Fontes Coloque um Edit Box ao lado do Label e apague a sua propriedade Text Coloque um Button e manipule seu evento OnClick com:

procedure TForm1.Button1Click (Sender : TObject) ;begin Edit1.Text := IntToStr ( Screen.Fonts.Count ) ;end;

Execute a aplicação e dê um clique no botão Feche a aplicação

Como você pode ver pelo Help online do Delphi, a propriedade Fonts é do tipo TStrings, e tem a quantidade de strings na sua lista apontada pela propriedade Count.

b) Acessando strings:

Você pode acessar cada string de uma lista através da propriedade Strings, especificando, entre colchetes, a posição onde a mesma encontra-se , observando que este índice é baseado em zero, ou seja, a posição da primeira string da lista é igual a zero, e não, igual a um.

Comece uma nova aplicação Coloque um Memo, entre em Lines e apague a palavra Memo1 Coloque um Button e manipule seu evento OnClick com:

procedure TForm1.Button1Click (Sender : TObject) ;Var

Page 113: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 113 Todos os direitos reservados.

i : Integer ;begin For i := 0 To Screen.Fonts.Count - 1 Do Memo1.Lines.Add ( Format ( '%d - %s ' , [ i+1 , Screen.Fonts.Strings [ i ] ] ) ) ;end;

Execute a aplicação e dê um clique no botão Feche a aplicação

c) Determinar a posição da string

A função IndexOf devolve um inteiro referente à posição onde encontra-se a string desejada, que deve ser especificada por inteiro, pois IndexOf não procura trechos de strings. Caso a string não seja encontrada, IndexOf retorna o valor -1.

Comece uma nova aplicação Coloque um Memo, entre em Lines e apague a palavra Memo1 Coloque dois Button e manipule os eventos OnClick deles com:

procedure TForm1.Button1Click ( Sender: TObject ) ;Var i : Integer ;begin For i := 0 To Screen.Fonts.Count - 1 Do Memo1.Lines.Add ( Format ( ' %s ' , [ Screen.Fonts.Strings [ i ] ] ) ) ;end;

procedure TForm1.Button2Click ( Sender: TObject ) ;begin Edit1.Text := IntToStr ( Memo1.Lines.IndexOf ( ' Symbol ' ) ) ;end;

Obs1.: Como IndexOf exige que a string seja escrita por inteiro, não utilize espaço em branco entre os apóstrofes do parâmetro da função IndexOf ou da função Format.

Execute a aplicação e dê um clique no botão Feche a aplicação

d) Adicionando uma string a uma lista

i) Adicionando uma string S na posição P: Insert ( ( P - 1 ) , S ) . Lembre-se que a posição de uma lista é baseada em zero.

Page 114: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 114 Todos os direitos reservados.

Por exemplo, para inserir a string 'Alo!' na posição 3ª posição de uma lista, faça: Insert ( 2 , 'Alo!' ) .

ii) Adicionando uma string S ao final da lista: Add ( S ) e Append ( S ) .Add é uma função que retorna a posição (baseada em zero) onde a string é adicionada.A procedure Append faz o mesmo que Add sem retornar a posição.

Comece uma nova aplicação Coloque um Label , dois Botões e um Memo no Form Apague a palavra Memo1 do componente Memo1 (propriedade Lines) Manipule o evento OnClick dos botões com:

procedure TForm1.Button1Click ( Sender: TObject ) ;Var i : Integer ;begin For i := 0 To Screen.Fonts.Count - 1 Do Memo1.Lines.Add ( Format ( '%d - %s ' , [ i+1 , Screen.Fonts.Strings [ i ] ] ) ) ;end;

procedure TForm1.Button2Click(Sender: TObject);begin Label1.Caption := IntToStr ( Memo1.Lines.Add ( ' Nenhuma ' ) ) ;end;

Execute a aplicação Dê um clique em Button1 Dê um clique em Button2 Feche a aplicação

e) Movendo uma string

Especifique o índice corrente e o índice destino. Por exemplo, para mover a 1ª string para a 3ª posição, faça: Move ( 0 , 2 )

Altere a manipulação OnClick de Button2 acima para:

procedure TForm1.Button2Click(Sender: TObject);begin Memo1.Lines.Move ( 0 , 2 ) ;end;

Execute a aplicação Dê um clique em Button1 Dê um clique em Memo1 e pressione Ctrl-Home (para ir ao início da

listagem)

Page 115: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 115 Todos os direitos reservados.

Dê um clique em Button2 Dê novo clique em Button2 Feche a aplicação

f) Apagando uma string

Passe para a procedure Delete a posição (baseada em zero) da string a apagar. Por exemplo, para apagar a terceira string de um Memo, faça: Delete ( 2 ).

Outro exemplo, para apagar a fonte Arial (ou qualquer outra fonte que esteja instalada em seu sistema), faça:

Comece uma nova aplicação Coloque um Memo, entre em Lines e apague a palavra Memo1 Coloque dois Button e manipule os eventos OnClick deles com:

procedure TForm1.Button1Click ( Sender: TObject ) ;Var i : Integer ;begin For i := 0 To Screen.Fonts.Count - 1 Do Memo1.Lines.Add ( Format ( '%s' , [ Screen.Fonts.Strings [ i ] ] ) ) ;end;

procedure TForm1.Button2Click(Sender: TObject);begin With Memo1.Lines Do If IndexOf ( 'Arial' ) > -1 Then Delete ( IndexOf ( 'Arial' ) ) ;end;

Obs2.: Como IndexOf exige que a string seja escrita por inteiro, não utilize espaço em branco entre os apóstrofes do parâmetro da função IndexOf ou da função Format.

Execute a aplicação Dê um clique em Button1 Dê um clique em Memo1 e pressione Ctrl-Home (para ir ao início da

listagem) Dê um clique em Button2. A fonte Arial ( ou a fonte escolhida por você é

apagada da listagem de Memo1) Feche a aplicação

g) Copiando uma lista de strings para outra

Page 116: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 116 Todos os direitos reservados.

Comece uma nova aplicação Coloque um Memo, entre em Lines e apague a palavra Memo1 Coloque um ComboBox (aba Standard)

Apague a palavra ComboBox1 na propriedade Text

Coloque um Button e manipule o evento OnClick dele com:

Page 117: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 117 Todos os direitos reservados.

procedure TForm1.Button1Click ( Sender: TObject ) ;begin ComboBox1.Items := Memo1.Lines ;end;

Obs3.: Preste bem atenção: o plural de Item, em inglês, é Items (com "m") e não Itens (com "n").

Execute a aplicação Dê um clique na seta preta de ComboBox1. Veja que não há qualquer item Digite em Memo1 o seguinte:

À vista (Dinheiro ou cheque)Cartão de CréditoCarnê

Dê um clique em Button1 Dê novo clique em ComboBox1. A lista de strings de Memo1 foi copiada para

a lista de strings de ComboBox1. Feche a aplicação

Obs4.: Dê um clique no componente ComboBox1 e depois dê um clique na propriedade Items. Como você pode ver, esta propriedade também é do tipo TSTrings. Assim, quando você atribui à propriedade Lines (do tipo TStrings) de Memo1 a propriedade Items (do tipo TStrings), você está copiando todas as strings daquela propriedade para esta.

h) Adicionando itens adicionais ao final de uma lista:

Para adicionar uma lista de strings ao final de uma lista, utilize a procedure

Adicione um segundo Botão ao Form Manipule seu evento OnClick com

procedure TForm1.Button2Click(Sender: TObject);begin ComboBox1.Items.AddStrings ( Memo1.Lines ) ;end;

Execute a aplicação Digite em Memo1 o seguinte:

Page 118: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 118 Todos os direitos reservados.

À vista (Dinheiro ou cheque)Cartão de CréditoCarnê

Dê um clique em Button1 Agora, digite em Memo1 o seguinte (coloque 5 espaços em branco no início

de cada item):

30 dias60 dias90 dias

Dê um clique em Button2 Dê novo clique em ComboBox1. A segunda lista de strings de Memo1 foi

copiada para o final da lista de strings de ComboBox1. Feche a aplicação

i) Manipulando item a item

Altere a manipulação OnClick de Button1 acima com:

procedure TForm1.Button1Click ( Sender: TObject ) ;Var i : Integer ;begin For i := 0 To Memo1.Lines.Count - 1 Do Memo1.Lines [ i ] := UpperCase ( Memo1.Lines [ 1 ] ) ; ComboBox1.Items := Memo1.Lines ;end;

Execute a aplicação Digite em Memo1 o seguinte:

À vista (Dinheiro ou cheque)Cartão de CréditoCarnê

Dê um clique em Button1 Dê novo clique em ComboBox1. Os itens de Memo1 foram convertidos para

maiúscula antes de serem copiados para a lista de strings de ComboBox1. Feche a aplicação

11.2. Carregando e salvando strings

a) Carregando uma lista de strings de um arquivo:

Page 119: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 119 Todos os direitos reservados.

LoadFromFile ( 'Nome_do_Arquivo' )

b) Salvando uma lista de strings em um arquivo:

SaveToFile ( 'Nome_do_Arquivo' )

Vamos fazer uma aplicação que faça o backup do arquivo Autoexec.bat, supondo existir este arquivo no diretório raiz do drive C: .

Comece uma nova aplicação Coloque dois Botões e um Memo no Form Altere a propriedade WordWrap de Memo1 de True para False Manipule o evento OnClick dos botões com:

procedure TForm1.Button1Click(Sender: TObject);begin Memo1.Clear ; Memo1.Lines.LoadFromFile ( 'C:\Autoexec.bat' ) ;end;

procedure TForm1.Button2Click(Sender: TObject);begin Memo1.Lines.SaveToFile ( 'Meu Autoexec.bat' ) ;end;

Execute a aplicação Dê um clique em Button1. Você passa a visualizar o arquivo Autoexec.bat Altere algumas linhas de Memo1 Dê um clique em Button2. Você salvou o arquivo modificado no diretório

corrente com o novo nome: Meu Autoexec.bat. Feche a aplicação

Obs5.: Verifique no Windows Explorer que o arquivo: Meu Autoexec.bat encontra-se no diretório corrente. Se você estiver executando o projeto de dentro do Delphi, encontrará o arquivo Meu Autoexec.bat no diretório onde é gerado o arquivo executável da sua aplicação:

C:\Arquivos de Programas\Borland\Delphi 3\Bin .

Caso você queira salvar o arquivo num diretório diferente deste, basta especificar junto ao nome, o diretório desejado, por exemplo: C:\Temp\Meu Autoexec.bat , faz com que o arquivo seja salvo no diretório C:\Temp (caso exista, obviamente).

12. Janelas de Diálogo

Comece uma nova aplicação

Page 120: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 120 Todos os direitos reservados.

Adicione um Memo e um PopupMenu ao Form

Dê um

clique duplo em PopupMenu1 (ou um clique simples nas reticências da sua propriedade Items)

Altere o primeiro item de menu:- Caption: &Abrir- SortCut: Ctrl+A

Altere o segundo item de menu:- Caption: &Salvar- SortCut: Ctrl+B

Altere o terceiro item de menu:- Caption: Salvar &como ...

Altere o quarto item de menu (lembre que o hífen é o traço separador) :- Caption: -

Altere o quinto item de menu:- Caption: Sai&r

Altere a propriedade PopupMenu de Form1 para PopupMenu1 Adicione ao Form um componente OpenDialog (Aba Dialogs)

Adicione ao Form um componente SaveDialog (Aba Dialogs)

Dê um clique nas reticências da propriedade Filter de OpenDialog1:

Page 121: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 121 Todos os direitos reservados.

Aparecendo o Filter Editor, digite os filtros desejados, como abaixo:

Dê um clique no botão OK . Repita a operação acima para o componente SaveDialog1 Altere a propriedade Title de OpenDialog1 para Abrir Altere a propriedade Title de SaveDialog1 para Salvar como...

Manipule o evento OnClick do item de menu Abrir com:

procedure TForm1.Abrir1Click(Sender: TObject);

Page 122: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 122 Todos os direitos reservados.

begin Try If OpenDialog1.Execute Then Memo1.Lines.LoadFromFile (OpenDialog1.FileName) ; Except ShowMessage ('Erro ao carregar o arquivo!') ; End ;end;

Manipule o evento OnClick do item de menu Salvar com:

procedure TForm1.Salvar1Click(Sender: TObject);begin Try Memo1.Lines.SaveToFile (OpenDialog1.FileName) ; Except ShowMessage ('Erro ao salvar o arquivo!') ; End ;end;

Manipule o evento OnClick do item de menu Salvar como... com:

procedure TForm1.Salvarcomo1Click(Sender: TObject);begin Try If SaveDialog1.Execute Then Memo1.Lines.SaveToFile (SaveDialog1.FileName) ; Except ShowMessage ('Erro ao salvar o arquivo!') ; End ;end;

Manipule o evento OnClick do item de menu Sair com:

procedure TForm1.Sair1Click(Sender: TObject);begin Close ;end;

Manipule o evento OnCloseQuery de Form1 com:

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);begin CanClose := MessageDlg ('Sair!',mtConfirmation,[mbYes,mbNo],0) = mrYes ;end;

Execute a aplicação, dê um clique com o botão direito do mouse Abra um arquivo, salve-o com nome diferente (Salvar como...) Feche a aplicação

Page 123: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 123 Todos os direitos reservados.

Obs1.: O parâmetro CanClose tem por função permitir o fechamento da janela (CanClose igual a True) ou não (CanClose igual a False). Sendo assim, o valor de retorno da função MessageDlg é quem vai decidir o fechamento da janela. Se esse valor de retorno for igual a mrYes, CanClose recebe True e a janela é então fechada; caso contrário, CanClose recebe False e o fechamento é cancelado.É de se observar que, toda janela que está para ser fechada, gera um evento OnCloseQuery daquela janela.

Obs2.: Caso você queira, altere a propriedade DefaultExt de SaveDialog1 para txt, o que fará com que os arquivos sejam salvos com essa extensão, caso você não especifique extensão diferente. Para salvar o arquivo com extensão diferente de txt, selecione Todos os Arquivos (*.*) no combobox Salvar como tipo: e digite o nome do arquivo seguido da extensão desejado. Por exemplo, para salvar o arquivo hipotético

C:\JANELAS DE DIÁLOGO.TXTcomo

C:\Delphi 3\JANELAS DE DIÁLOGO.DAT

faça como abaixo:

Obs3.: A manipulação do item de menu Salvar utiliza o FileName de OpenDialog1 pois supõe-se que o usuário queira salvar o arquivo com o mesmo nome com o qual ele foi aberto. O que pode (e deve) ser feito aqui, é desabilitar este item de menu enquanto não tiver um arquivo carregado (para não salvar uma tela em branco num arquivo existente). Consulte a função FileExists no Help online do Delphi.

13. Gráficos

Há três maneiras de se obter imagens gráficas no Delphi:

Page 124: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 124 Todos os direitos reservados.

a. inserir desenhos em tempo de designb. criá-los em tempo de designc. criá-los em tempo de execução

Quando você desenha, você o faz por meio da propriedade CANVAS do objeto. O próprio Canvas é um objeto, e possui quatro importantes propriedades:

a. Pen : desenho de linhasb. Brush : preenchimento de desenhosc. Font : escrita de texto e escolha da fonted. Array de pixels : representação da imagem

Você deve ter em mente que, em um ambiente gráfico, não existe sentido em se falar em caracteres pura e simplesmente, mas nos pixels que formam determinado caractere. Isto é definido pela fonte, pelo seu tamanho, suas características (negrito, itálico, sublinhado, etc.). Por isso, toda a vez que você estiver observando uma janela, raciocine que são pixels arranjados em diferentes cores o que você, na verdade, tem.

13.1. Manipulando pixels

a. Ler: Cada pixel corresponde a uma cor

Comece uma nova aplicação Coloque um Edit Box e um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Edit1.Font.Color := Canvas.Pixels [10,15] ;end ;

Execute a aplicação Escreva algo em Edit1 e verifique a cor da fonte (clWindowText, que deve ser

igual a preto) Dê um clique em Button1 e observe a nova cor da fonte (clBtnFace, que deve

ser igual a cinza) Feche a aplicação.

Obs1.: Quando você clica o botão, a cor da fonte de Edit1 é alterada com a cor do pixel que está na posição: coluna = 10 e linha = 15. Aqui nós estamos utilizando a propriedade Canvas do Form.

b. Escrever

Comece uma nova aplicação

Page 125: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 125 Todos os direitos reservados.

Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);Var N : Integer ;begin Randomize ; For N := 1 To 10 Do Canvas.Pixels [ Random ( ClientWidth ) , Random ( ClientHeight ) ] := clRed ;end;

Execute a aplicação Dê um clique em Button1 e observe a alteração da cor de vários pixels na tela Dê vários cliques no botão, maximize a janela e observe a área sem "pontos

vermelhos". Dê novos cliques no botão e observe. Feche a aplicação.

Obs2.: A função Random gera valores aleatórios entre 0 e um limite inteiro, tal que:

X := Random ( Limite ) ;

gera valores entre 0 e o Limite, ou seja:

0 X Limite

Caso não seja especificado um limite, o valor retornado por Random, é um valor Real entre 0 e 1, ou seja:

X := Random ;

gera valores entre 0 e o 1, ou seja:

0 X 1

Obs3.: A procedure Randomize inicializa o gerador de números aleatórios.

Obs4.: ClientWidth é o comprimento (em pixels) e ClientHeight é a altura (em pixels) da área do Form cliente, sendo essa área a área utilizável dentro dos limites formados pela borda da janela.

13.2. Manipulando a caneta com Pen

TPen descreve os atributos de uma caneta quando se desenha uma imagem em Canvas.

Page 126: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 126 Todos os direitos reservados.

a. Movendo a caneta com MoveTo

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.MoveTo ( 0 , 0 ) ; { 0 , 0 é o canto superior esquerdo }end;

Execute a aplicação Dê um clique em Button1 e observe que aparentemente nada acontece. Feche a aplicação.

b. Desenhando uma linha com LineTo

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.MoveTo ( 0 , 0 ) ; Canvas.LineTo ( 300 , 80 ) ;end;

Execute a aplicação Dê um clique em Button1 e observe a linha formada. Feche a aplicação.

c. Desenhando várias linhas com LineTo

Comece uma nova aplicação Manipule evento OnMouseMove de Form1 com:

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);begin Canvas.LineTo ( X , Y ) ;end;

Execute a aplicação e veja que, para onde você movimenta o mouse, uma linha contínua é desenhada.

Feche a aplicação.d. Configurando a caneta

TPen tem 4 propriedades :

Page 127: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 127 Todos os direitos reservados.

- Color- Width- Style- Mode

A cor da caneta pode ser qualquer cor válida para o ambiente (vide a propriedade Color de Form1).A espessura da caneta deve ser um valor Integer maior ou igual a 1.O estilo da caneta pode ser um dos seguintes:

- psSolid: linha sólida- psDash: linha cheia de tracinhos- psDot: linha cheia de pontinhos- psDashDot:linha alternando tracinhos e pontinhos- psDashDotDot: linha que alterna uma combinação dos estilos psDash e psDot- psClear: linha transparente (nenhuma linha é desenhada)- psInsideFrame: linha sólida, porém podendo utilizar uma cor não contida na

tabela de cores válidas para o ambiente

São vários os modos possíveis para a caneta, e que irão influenciar a cor da caneta. Abaixo são listados alguns desses modos:

- pmBlack: sempre preto- pmWhite: sempre branco- pmNop: sem caneta (No Pen)- pmNot: cor inversa à "cor de fundo" de Canvas- pmCopy: cor especificada na propriedade Color- pmNotCopy: cor inversa à cor especificada na propriedade Color

Comece uma nova aplicação Coloque 6 RadioButton no Form, sem se preocupar em alinhá-los, como

mostrado abaixo (preste bem atenção nas posições dos componentes):

Page 128: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 128 Todos os direitos reservados.

Selecione RadioButton1, RadioButton2 e RadioButton3 (um debaixo do outro, como mostrado acima).

Obs5.: Para selecionar os três componentes, mantenha a tecla Shift pressionada e dê um clique em cada componente ou, então, posicione o cursor do mouse numa posição próxima à radioButton1 e, com o botão esquerdo do mouse pressionado, arraste-o em torno dos três componentes, de tal forma que uma caixa pontilhada englobe os componentes.

Clique sobre um deles com o botão direito do mouse e depois no item Align No groupbox Horizontal clique em Left sides No groupbox Vertical clique em Space equally Clique o botão OK. Verifique que os componentes estão agora alinhados Dê um clique no Form para cancelar a seleção dos componentes Selecione RadioButton4, RadioButton5 e RadioButton6 Repita a operação acima apenas para o alinhamento horizontal (Left sides),

não se preocupando com o alinhamento vertical Dê um clique no Form para cancelar a seleção dos componentes Selecione RadioButton1 e RadioButton4 (que devem estar na mesma linha) Clique sobre um deles com o botão direito do mouse e depois no item Align No groupbox Vertical clique em Tops Clique em Ok Repita a operação acima para os demais, alinhando-os dois a dois pelo topo Altere os captions dos RadioButton para:

- RadioButton1: pmBlack- RadioButton2: pmWhite- RadioButton3: pmNop- RadioButton4: pmNot- RadioButton5: pmCopy- RadioButton6: pmNotCopy

Manipule o evento OnClick de cada um deles com:

procedure TForm1.RadioButton1Click(Sender: TObject);begin Canvas.Pen.Mode := pmBlack ;end;

procedure TForm1.RadioButton2Click(Sender: TObject);begin Canvas.Pen.Mode := pmWhite ;end;

procedure TForm1.RadioButton3Click(Sender: TObject);begin Canvas.Pen.Mode := pmNop ;end;

Page 129: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 129 Todos os direitos reservados.

procedure TForm1.RadioButton4Click(Sender: TObject);begin Canvas.Pen.Mode := pmNot ;end;

procedure TForm1.RadioButton5Click(Sender: TObject);begin Canvas.Pen.Mode := pmCopy ;end;

procedure TForm1.RadioButton6Click(Sender: TObject);begin Canvas.Pen.Mode := pmNotCopyend;

Manipule o evento OnActivate de Form1 com:

procedure TForm1.FormActivate(Sender: TObject);begin Canvas.Pen.Style := psDash ; Canvas.Pen.Width := 5 ; Canvas.Pen.Color := clRed ;end;

Manipule o evento OnMouseMove de Form1 com:

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);begin Canvas.LineTo ( X , Y ) ;end;

Execute a aplicação e movimente o mouse Clique num dos RadioButton (para alterar o modo da caneta) e movimente

novamente o mouse. Experimente os outros modos da caneta Feche a aplicação.

e. Desenhando retângulos com Rectangle

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.Rectangle ( 10 , 10 , ClientWidth Div 2 , ClientHeight Div 2 ) ;end;

Page 130: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 130 Todos os direitos reservados.

Execute a aplicação Dê um clique em Button1 e observe a formação do retângulo. Feche a aplicação.

f. Desenhando retângulos de quinas arredondadas com RoundRect

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.RoundRect ( 10 , 10 , ClientWidth Div 2 , ClientHeight Div 2 , 50 , 50 ) ;end;

Execute a aplicação Dê um clique em Button1 e observe a formação do novo retângulo. Feche a aplicação.

Obs6.: O 5º e o 6º parâmetros informam a RoundRect que "arredonde" as quinas como seções de um círculo com 50 pixels de diâmetro. Experimente outros valores.

g. Desenhando elipses com Ellipse

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.Ellipse ( 10 , 10 , ClientWidth Div 2 , ClientHeight Div 2 ) ;end;

Execute a aplicação Dê um clique em Button1 e observe a formação da elipse. Feche a aplicação.

h. Desenhando polígonos com Polygon

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.Polygon ( [ Point ( 10 , 10 ) , Point ( 150 , 10 ) , Point ( 10 , 100 ) ] ) ;end;

Page 131: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 131 Todos os direitos reservados.

Execute a aplicação Dê um clique em Button1 e observe a formação do triângulo. Feche a aplicação.

i. Desenhando gráfico de pizza com Pie

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.Pie ( 10 , 10 , 200 , 200 , 61 , 3 , 200 , 61 ) ;end;

Execute a aplicação Dê um clique em Button1 e observe a formação de uma "fatia gorda" da pizza. Feche a aplicação.

Obs7.: Na verdade, se você quiser montar um gráfico de pizza, você tem que montá-la fatia a fatia. A procedure Pie tem como argumentos:

Canvas.Pie ( X1, Y1, X2, Y2, X3, Y3, X4, Y4 ) ;

- X1, Y1, X2, Y2 : coordenadas do retângulo delimitador da elipse- X3, Y3, X4, Y4 : coordenadas das linhas que, cruzadas, definem o centro

da elipse

j. Escrevendo no Form com TextOut

Comece uma nova aplicação Coloque um botão no Form Manipule evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);begin Canvas.TextOut ( 10 , 10 , ' Alo Você! ' ) ;end;

Execute a aplicação Dê um clique em Button1 e observe a string 'Alo Você!' escrita em Form1. Feche a aplicação.

Obs8.: Canvas tem ainda muitas propriedades úteis para a parte gráfica. Pesquise mais no Help online do Delphi.

Page 132: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 132 Todos os direitos reservados.

14. Classe e Objeto

Até o momento, você já manipulou eventos, alterou propriedades e executou ações com a sua aplicação. Você está manipulando características de um objeto. Vamos entender mais um pouco sobre isso.

Quando você está criando um programa, e você quer armazenar um valor de salário (com duas casas decimais), você declara uma variável do tipo real. Este tipo, real, permite a você:

- somar- subtrair- dividir- multiplicar- imprimir os resultados com nenhuma, uma ou várias casas decimais

E tudo o mais que um tipo real permita. Mas preste atenção: o tipo real permite isto, e somente isto. Você não pode, por exemplo, criar uma linha de comando deste tipo:

Real := 3.0 ;

E por que não? Porque real é um tipo que você associa a uma variável. A variável, que for do tipo real, ela sim, poderá receber um valor, como mostra abaixo:

VarX : Real ;

BeginX := 3.0 ;

Assim sendo, uma variável serve para armazenar valores compatíveis com o tipo utilizado na sua declaração, e esta variável tem o conjunto de operações restrito ao tipo especificado, ou seja, variáveis do tipo string, digamos, não podem sofrer a operação de multiplicação, e assim por diante.

14.1. Classe

Pode-se definir Classe como sendo uma estrutura que contém um número fixo de atributos, quais sejam: propriedades, campos e métodos. Sua visibilidade deve ser global (não pode ser declarada em uma procedure).

Isto significa dizer "a grosso modo" que Classe é uma definição de características e comportamentos, semelhante à idéia do Tipo explicada acima.

São várias, entretanto, as diferenças entre Tipo e Classe, mas a maior delas é que Tipo é uma definição estática e Classe pode ser alterada através do recurso de Herança. Com isso, uma Classe que seja criada por herança de outra, "herda" toda a estrutura da Classe Ancestral e, se necessário, pode implementar novas características, fazendo-se diferente da Classe Ancestral. Ou seja: uma vez inventada uma Classe, não será preciso reinventar a roda, pois essa Classe pode servir de Classe Básica para outras.

Page 133: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 133 Todos os direitos reservados.

Por exemplo: toda a vez que você começa uma aplicação, o Delphi cria a seguinte estrutura:

type TForm1 = class(TForm) private { Private declarations } public { Public declarations } end;

Ou seja, já existe uma Classe Ancestral denominada TForm que será a Classe Básica.

Obs1.: O Delphi começa o nome de todas as classes com a letra T, pois para o Delphi uma Classe é um tipo de dado (um tipo especial), e nós seguiremos essa notação.

Ela possui, maneira resumida, o seguinte:

- Propriedades:

Caption Color Height Width Name Menu PopupMenu Visible

- Procedures e Functions:

Fechamento (Close) Minimização Maximização Redimensionamento Arraste

- Eventos:

OnActivate OnClose OnCloseQuery OnMouseMove

Sendo assim, TForm1 possui também todas essas características, pois ela é uma Classe Herdada da Classe TForm, através cláusula Class, como mostrado abaixo:

TForm1 = class ( TForm )

Page 134: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 134 Todos os direitos reservados.

Por hipótese, vamos considerar que você colocou no seu form (Form1) um componente Edit Box e um componente Label. Analise novamente o código-fonte:

type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; private { Private declarations } public { Public declarations } end;

Você pode observar que, além de todas as características citadas acima, TForm1 possui agora duas novas características que a diferencia da Classe Ancestral (TForm). E você vai agregando tantas modificações à TForm1 quantas forem necessárias. E toda a vez que você precisar começar uma aplicação ou, adicionar um novo Form ao projeto, a Classe Básica TForm estará lá para ser herdada, evitando que você escreva código-fonte para definir o óbvio, como, por exemplo: uma janela deve ser retangular, deve ter as propriedade tais e tais, deve sofrer fechamento, etc.

14.2. Objeto

Uma vez definida a Classe, para que você possa manipular propriedades, rotinas e eventos, você tem que instanciar a Classe, isto é, você tem que criar um Objeto dessa Classe. A "grosso modo", um Objeto está para a sua Classe, como uma Variável está para seu Tipo.

Retorne ao código-fonte anterior e veja a cláusula:

var Form1: TForm1;

Neste trecho de código, foi criado o Objeto Form1 da Classe TForm1.Relembrando o início do capítulo, você viu que não se pode realizar a operação:

Real := 3.0 ;

porque real é um tipo que você associa a uma variável. Mas o código abaixo é válido:

VarX : Real ;

BeginX := 3.0 ;

Analogamente, o código abaixo é um código inválido:

TForm1.Color := clBlue ;

pois TForm1 é uma classe que você associa a um objeto.

Page 135: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 135 Todos os direitos reservados.

Já o código abaixo é válido:

Form1.Color := clBlue ;

pois o objeto Form1 "existe" em tempo de execução e se comporta de acordo com as características definidas pela sua Classe (Form1 é um objeto da classe TForm1).

14.3. Método

Uma Classe tem uma estrutura muito parecida com um registro, mas a maior diferença entre os dois tipos, é que uma Classe além de definir campos, pode definir, também, sub-rotinas (procedures e/ou functions) que atuem sobre esses campos.

Aos campos damos o nome de Propriedades e às rotinas damos o nome de Método.

Assim sendo, quando você utiliza a rotina Close para fechar Form1, você está utilizando, na verdade, o método Close de Form1. Por exemplo, executar o comando:

Close ;equivale a utilizar:

Form1.Close ;

Por que ambas as versões? Porque se você não especificar o objeto "proprietário" do método, o Delphi assume como objeto "proprietário" o Form declarado na Unit sendo editada (neste caso, Unit1 e, por conseqüência, Form1).

Isto significa dizer que, um método age sobre as propriedades pertencentes ao seu objeto, somente, sendo específico a ele, quer dizer, um método Clear de Edit1 apagará somente o campo Text de Edit1, não realizando qualquer operação sobre o campo Text de Edit2, ou sobre qualquer outra propriedade de qualquer outro objeto.

Esta característica é útil para que você possa realizar certas operações apenas em dados que são preparados para recebê-las.

Vamos supor que você está desenvolvendo um sistema comercial, que necessita de um módulo contábil, que embuta, entre outras tarefas, o cálculo mensal da folha de pagamentos.

Geralmente, o que nós temos é uma firma que comercializa determinada gama de produtos, e que em função da apuração mensal das vendas, calcula o salário de parte dos funcionários (geralmente vendedores). Já a gerência ganha um adicional de gratificação de chefia, calculado em cima de um salário básico (salário do pessoal administrativo) ou de um salário fixo e mais adicionais. Os demais, ganham somente o salário básico, sem gratificações ou adicionais.

Outra observação a ser feita, é que a matrícula dos funcionários são calculadas pelo seu número de entrada, consistindo de 3 dígitos numéricos, e um 4º dígito, calculado pelo resto da divisão por 10 da soma dos 3 primeiros dígitos.

As regras explicadas acima são, então:

- Administrativo : cálculo simples, igual a um padrão de 100 valores monetários- Gerência : inicialmente é igual ao administrativo, porém ganha n % sobre esse

valor, sendo n variável a cada mês- Vendas : inicialmente é igual ao administrativo, porém ganha adicional de 25%

sobre as vendas efetuadas individualmente

Page 136: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 136 Todos os direitos reservados.

Comece uma nova aplicação Clique em File - New Selecione Unit e dê um clique em OK

Aparece o seguinte cabeçalho:

unit Unit2;

interface

implementation

end.

Clique em File - Save All Digite: uExemplo_de_Classe quando aparecer o quadro: Save Unit1 As

e clique o botão Salvar, para salvar Unit1 com o novo nome.

Page 137: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 137 Todos os direitos reservados.

Salve a Unit2 com o nome: uClasses Salve o projeto (Project1) com o nome: pExemplo_de_Classe Na unit uClasses, você deve declarar as classes definidas anteriormente,

abaixo da cláusula Interface:

unit uClasses;

interface

typeTFuncionario = Class (TObject)private FNome : String ; FMat : String ; FSalario : Extended ; function Confere_Matricula ( Const M : String ) : Boolean ; function GetMat : String ; procedure SetMat ( Const Value : String ) ;public property Nome : String Read FNome Write FNome ; property Matricula : String Read GetMat Write SetMat ; property Salario : Extended Read FSalario Write FSalario ;end ;

TAdministrativo = Class (TFuncionario)privatepublic procedure Calcula_Salario ;end ;

TGerencia = Class (TFuncionario)private FAdicional : Extended ;public property Adicional : Extended Read FAdicional Write FAdicional ; procedure Calcula_Salario ;end ;

TVenda = Class (TFuncionario)privatepublic procedure Calcula_Salario ( Vendas_Efetuadas : Extended ) ;end ;

Page 138: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 138 Todos os direitos reservados.

implementation

function TFuncionario.Confere_Matricula ( Const M : STring ): Boolean ;Var Dv, i : Integer ;begin Dv := 0 ; For i := 1 To 3 Do Dv := Dv + StrToInt ( M [ i ] ) ; Dv := Dv Mod 10 ; Result := M [ 4 ] = IntToStr ( Dv ) ;end ;

function TFuncionario.GetMat : String ;begin Result := FMat ;end ;

procedure TFuncionario.SetMat ( Const Value : String ) ;begin If Confere_Matricula ( Value ) Then FMat := Value Else begin ShowMessage ( 'Matrícula Inválida! ' ) ; FSalario := -1 ; FMat := '' ; end ; end ;

procedure TAdministrativo.Calcula_Salario ;begin FSalario := FSalario ;end ;

procedure TGerencia.Calcula_Salario ;begin FSalario := FSalario * ( 1 + fAdicional / 100 ) ;end ;

procedure TVenda.Calcula_Salario ( Vendas_Efetuadas : Extended ) ;begin FSalario := FSalario + Vendas_Efetuadas * 0.25 ;end ;

end.

Page 139: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 139 Todos os direitos reservados.

Retorne ao Form1 Coloque, nele, os componentes abaixo, com as respectivas alterações:

- Form1: Caption: Exemplo de uso de classesName: fmClasses

- Label1: Caption: Nome do empregado- Edit1: Text: deixar em branco

CharCase: ecUpperCaseName: edbNome

- Label2: Caption: Matrícula- Edit2: Text: deixar em branco

Name: edbMatricula- Label3: Caption: Salário-Base ( R$ )- Edit3: Text: deixar em branco

Name: edbSal_Base- Label4: Caption: deixar em branco- Edit4: Text: deixar em branco

Name: edbProdutividadeVisible: False

- Label5: Caption: Salário ( R$ )- Edit5: Text: deixar em branco

Name: edbSalario

- RadioButton1: Caption : AdministrativoName: rbAdm

- RadioButton2: Caption : GerênciaName: rbGer

- RadioButton3: Caption : VendasName: rbVen

- Button1: Caption: Salário

O Form deve estar parecido com:

Page 140: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 140 Todos os direitos reservados.

Manipule o evento OnClick de rbAdm com:

procedure TfmClasses.rbAdmClick(Sender: TObject);begin If Sender = rbAdm Then begin Label4.Caption := '' ; edbProdutividade.Visible := False ; end Else begin edbProdutividade.Visible := True ; If Sender = rbGer Then Label4.Caption := 'Adicional ( % ) ' Else If Sender = rbVen Then Label4.Caption := 'Vendas Efetuadas ( R$ ) ' end ;end;

Dê um clique na setinha preta da manipulação OnClick de rbGer e, logo em seguida, dê um clique na manipulação de evento rbAdmClick

Manipule o evento OnClick de Button1 com:

procedure TfmClasses.Button1Click(Sender: TObject);Var

Repita a mesma operação para rbVen

Page 141: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 141 Todos os direitos reservados.

Admin : TAdministrativo ; Ger : TGerencia ; Ven : TVenda ; VEfet : Extended ;begin If rbAdm.Checked Then begin Try Admin := TAdministrativo.Create ; Admin.Nome := edbNome.Text ; Admin.Matricula := edbMatricula.Text ; Admin.Salario := StrToFloat ( edbSal_Base.Text ) ; Admin.Calcula_Salario ; edbSalario.Text := Format (' %1.2f ' , [ Admin.Salario ] ) ; Finally Admin.Free ; End ; end Else If rbGer.Checked Then begin Try Ger := TGerencia.Create ; Ger.Nome := edbNome.Text ; Ger.Matricula := edbMatricula.Text ; Ger.Salario := StrToFloat ( edbSal_Base.Text ) ; Ger.Adicional := StrToFloat ( edbProdutividade.Text ) ; Ger.Calcula_Salario ; edbSalario.Text := Format (' %1.2f ' , [ Ger.Salario ] ) ; Finally Ger.Free ; End ; end Else If rbVen.Checked Then begin Try Ven := TVenda.Create ; Ven.Nome := edbNome.Text ; Ven.Matricula := edbMatricula.Text ; Ven.Salario := StrToFloat ( edbSal_Base.Text ) ; VEfet := StrToFloat ( edbProdutividade.Text ) ; Ven.Calcula_Salario ( VEfet ) ; edbSalario.Text := Format (' %1.2f ' , [ Ven.Salario ] ) ; Finally Ven.Free ; End ; end ;end ;

Page 142: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 142 Todos os direitos reservados.

Abaixo da cláusula Implementation da unit uExemplo_de_classe, digite:

uses uClasses ;

Execute a aplicação Acontece um erro de compilação na linha que contém a função IntToStr. Dê

um clique sobre a função e de um toque na tecla F1 (invocando o Help online do Delphi). Veja que esta função está na unit SysUtils e para utilizá-la, você deve digitar:

uses SysUtils ;

abaixo da cláusula Implementation . Execute novamente a aplicação Novo erro de compilação, agora na procedure ShowMessage que, pelo Help

online você verifica estar na unit Dialogs. Altere a cláusula uses acima para adicionar a unit Dialogs .

Obs1.: Neste ponto, deveremos ter a claúsula uses igual a:

implementation

uses SysUtils , Dialogs ;

Digite seu nome e a matrícula 1236 (1+2+3 = 6 ; o resto da divisão de 6 por 10 é igual a 6)

Digite 100 no campo Salário-base Clique no radiobutton Administrativo Clique o botão e observe que aparece o valor 100,00 no campo Salário Clique agora o radiobutton Gerência Digite o valor 200 no campo Adicional Clique o botão Salário e observe o valor que aparece: 300,00, pois 100,00

aumentado 200% é igual a 300,00 . Clique agora o radiobutton Vendas Clique o botão Salário e observe agora o novo valor do campo Salário: 150,00

pois 25% de 200,00 (conteúdo do campo Vendas Efetuadas) é igual a 50,00 que somados aos 100,00 de Salário-Base perfazem 150,00.

Altere agora a matrícula para 1234 Clique o botão Salário. Observe que após o clique no botão da janela com a

mensagem de erro é efetuado o cálculo normal do salário (operação que deveria ser interrompida com uma entrada inválida de matrícula)

Feche a aplicaçãoVamos comentar o código-fonte desde o início.

Page 143: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 143 Todos os direitos reservados.

a. Definindo a classe básica (ancestral de todas as outras, pois independente do cargo ocupado pelo empregado: administrativo, gerência ou venda, ele é um funcionário da firma, e possui pelo menos: nome, matrícula e salário).

TFuncionario = Class (TObject)private FNome : String ; FMat : String ; FSalario : Extended ; function Confere_Matricula ( Const M : String ) : Boolean ; function GetMat : String ; procedure SetMat ( Const Value : String ) ;public property Nome : String Read FNome Write FNome ; property Matricula : String Read GetMat Write SetMat ; property Salario : Extended Read FSalario Write FSalario ;end ;

Podemos ver que define-se uma propriedade pela palavra reservada property seguido do nome e de duas cláusulas: Read , que deverá ser seguida de um nome de variável de manipulação (a qual é chamada de campo) de atribuição à propriedade ou de uma função de entrada, seguido da cláusula Write , que deverá ser seguida de um nome de variável de manipulação (também chamada de campo) de leitura do conteúdo da propriedade ou de uma procedure de saída.

Propriedades são declaradas na seção public, pois supõe-se querer utilizar essas propriedades fora do escopo da unit declaradora da classe.

A propriedade em si, não é manipulável nesta parte, e por isso se faz necessário utilizar campos para ler / escrever valores na / da propriedade. E esses campos deverão ter o mesmo tipo da propriedade, sendo declarados na seção private da classe, pois somente a classe ancestral, e seus descendentes, poderão visualizar e manipular os campos. Outras units somente terão acesso à propriedade do objeto que será instanciado. Tudo que é declarado na seção private não é visível fora do escopo da unit declaradora da classe.

Por convenção, o nome do campo (Field, em inglês) inicia pela letra F seguido do nome da propriedade. Assim, o campo FNome manipula os valores da propriedade Nome, bem como, FMat manipula os valores da propriedade Matricula.

Quando utilizar um campo para manipular o valor da propriedade diretamente, e quando utilizar uma sub-rotina para manipular esse valor?

Quando você for simplesmente manipular o valor da propriedade, utilize o campo, ao invés de declarar uma sub-rotina. Porém, se você tiver que realizar a verificação da consistência do valor sendo entrado (por exemplo, a verificação da matrícula), utilize a sub-rotina. É obvio que você, independente de ter ou não que verificar a consistência do valor atribuído à propriedade, pode utilizar a sub-rotina para entrada e saída desse valor.

No exemplo acima, GetMat e SetMat terão por função manipular o valor de FMat que é o valor associado à propriedade Matricula. Observe que, tanto o campo FMat como os cabeçalhos das sub-rotinas (GetMat e SetMat) são declarados na seção private, pois outras units devem ter acesso à propriedade, não à implementação interna do que faz GetMat ou SetMat, caso contrário, alguém pode burlar o sistema de segurança e inventar uma senha falsa. Por isso, o desenvolvedor pode atribuir o valor do

Page 144: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 144 Todos os direitos reservados.

edit box edbMatricula à propriedade Matricula, mas não tem acesso ao cálculo interno para saber se a matrícula é ou não verdadeira.

Pelo mesmo motivo, a função Confere_Matricula tem seu cabeçalho declarado na seção private. Observe que o parâmetro tem a cláusula Const precedendo o nome do parâmetro. Isto foi feito, porque o parâmetro não precisa ser alterado e, por isso, a utilização de um parâmetro Const faz com que o processamento seja muito mais veloz do que se tivéssemos utilizado a cláusula.

b. Definindo a classe descendente: TAdministrativo

TAdministrativo = Class (TFuncionario)privatepublic procedure Calcula_Salario ;end ;

Aqui, somente declaramos o método que irá computar o salário do funcionário, pois as propriedades requeridas por esta classe já foram definidas em TFuncionario.

c. Definindo a classe descendente: TGerencia

TGerencia = Class (TFuncionario)private FAdicional : Extended ;public property Adicional : Extended Read FAdicional Write FAdicional ; procedure Calcula_Salario ;end ;

Esta classe, TGerencia, além das propriedades herdadas de TFuncionario, declara também a propriedade Adicional, além do método Calcula_Salario, que irá computar o salário da gerência, utilizando metodologia diferente da metodologia utilizada pela classe TAdministrativo.

d. Definindo a classe descendente: TVenda

TVenda = Class (TFuncionario)privatepublic procedure Calcula_Salario ( Vendas_Efetuadas : Extended ) ;end ;

Vemos aqui, uma modificação do método Calcula_Salario que, ao invés de trabalhar com uma propriedade, utiliza um parâmetro para a implementação do método.

O ideal é que você trabalhe de maneira padronizada, utilizando somente um modelo de programação, ou seja, se você declarou o método de um jeito, utilize o mesmo jeito para outras classes que implementem o método com o mesmo nome.

e. Implementando os métodos: a seção Implementation

Page 145: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 145 Todos os direitos reservados.

A seção Interface, como o nome diz, serve de interface para outras units e aplicações, sendo uma área considerada global pelo projeto. E, por isso, a classe deve ser declarada nessa seção. pois uma classe não pode ter escopo local, e sim, global.

Já a seção Implementation serve para implementar código-fonte visível apenas localmente (invisível para as outras units), quais sejam métodos ou sub-rotinas (não necessariamente atreladas a uma classe).

Cada método deve ser implementado utilizando cabeçalho idêntico ao contido na declaração da classe, com a adição do nome da classe ao nome do método, separados pelo caractere ponto ( . ), como mostrado abaixo:

function TFuncionario.Confere_Matricula ( Const M : STring ): Boolean ;

Observe novamente o uso da cláusula Const antecedendo o nome do parâmetro, fazendo com que a performance do método seja melhorado em termos de velocidade.

A implementação do método TFuncionario.Confere_Matricula é muito simples, pois ele nada mais faz do que somar os três primeiros dígitos da matrícula e comparar o resto da divisão desta soma por 10 com o quarto caractere da matrícula (que na função é chamada de dígito verificador: Dv), e se eles foram diferentes, retornar o valor booleano False, caso contrário, True:

function TFuncionario.Confere_Matricula ( Const M : STring ): Boolean ;Var Dv, i : Integer ;begin Dv := 0 ; For i := 1 To 3 Do Dv := Dv + StrToInt ( M [ i ] ) ; Dv := Dv Mod 10 ; Result := M [ 4 ] = IntToStr ( Dv ) ;end ;

Já o método TFuncionario.GetMat simplesmente atribui à propriedade Matricula o conteúdo do campo FMat . Métodos que são declarados na seção Read da cláusula property utilizam, por notação, a palavra Get seguido do nome da propriedade:

function TFuncionario.GetMat : String ;begin Result := FMat ;end ;

O método SetMat é o oposto do método GetMat, pois sua função é atribuir ao campo de manipulação do conteúdo da propriedade. Por notação, seu nome inicia pela palavra Set seguido do nome da propriedade:

procedure TFuncionario.SetMat ( Const Value : String ) ;

Page 146: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 146 Todos os direitos reservados.

begin If Confere_Matricula ( Value ) Then FMat := Value Else begin ShowMessage ( ' Matrícula Inválida! ' ) ; FSalario := -1 ; FMat := '' ; end ; end ;

Aqui você pode ver a utilização do método Confere_Matricula, impedindo o usuário de digitar um valor inválido de matrícula.

Neste ponto, lembramos que o código produziu o salário normalmente, independente de a matrícula estar ou não correta, o que convenhamos não pode ocorrer. Altere o bloco do Else de:

Else begin ShowMessage ( ' Matrícula Inválida! ' ) ; FSalario := -1 ; FMat := '' ; end ;

para:

Else Raise Erro.Create ( ' Matrícula Inválida! ' ) ;

Neste caso, acontecerá um erro em tempo de execução, e o processamento terminará.

Execute novamente a aplicação Acontece o erro de compilação: Undeclared identifier , alertando para o fato

que você não declarou a variável de exceção. Como visto acima, tente alterar o cabeçalho da procedure para:

procedure TFuncionario.SetMat ( Const Value : String ) ;type Erro = class ( Exception ) ;begin If Confere_Matricula ( Value ) Then FMat := Value Else Raise Erro.Create ( ' Matrícula Inválida! ' ) ;end ;

Execute novamente a aplicação. Veja o novo erro do compilador. Isto significa que você não pode declarar uma classe com escopo local. Classes devem ser declaradas na seção Interface da unit. Assim sendo, retire as linhas de declaração da classe da seção de declaração de tipos locais à procedure, fazendo com que a mesma fique igual a:

Page 147: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 147 Todos os direitos reservados.

procedure TFuncionario.SetMat ( Const Value : String ) ;begin If Confere_Matricula ( Value ) Then FMat := Value Else Raise Erro.Create ( ' Matrícula Inválida! ' ) ;end ;

e reescreva essas linhas abaixo da cláusula type na seção Interface (acima da declaração da classe TFuncionario), como mostrado abaixo:

interface

type

Erro = class ( Exception ) ;

TFuncionario = Class (TObject)private

Execute novamente a aplicação Acontece novamente o erro de compilação: Undeclared identifier , desta vez

porque você não declarou a unit que contém a definição da classe ancestral Exception. Pelo Help online do delphi, podemos ver que a unit responsável por Exception é SysUtils. Escreva, então, logo após a cláusula Interface, a linha de comando: uses SysUtils ; e tente nova compilação. Acontece então o erro de compilação: Identifier redeclared, sugerindo o fato de você já ter declarado um identificador (variável, tipo, constante, units, etc.) e estar tentando declarar alguma outra coisa com o mesmo nome da primeira. E isto acontece, porque você já declarou a unit SysUtils na cláusula uses da área de Implementation, não podendo haver declaração da mesma unit na área de Interface:

interface

uses SysUtils ;

e

implementation

uses SysUtils , Dialogs ;

Altere a cláusula uses da seção Implementation para:

implementation

Page 148: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 148 Todos os direitos reservados.

uses Dialogs ;

e deixe a cláusula uses de Interface do jeito que ela está, pois o que é declarado em Interface (área global) é visto por toda a unit (isto significa que IntToStr poderá ser utilizada na seção Implementation normalmente, pois as rotinas da unit SysUtils serão visíveis por toda a unit, tanto da área global - Interface - como da área local - Implementation).

Execute novamente a aplicação Digite a matrícula 1234 e observe que, após o aviso de erro, nada mais é

processado. Feche a aplicação

Continuando a explicação inicial, o método TAdministrativo.Calcula_Salario não realiza cálculo algum, atribuindo ao campo FSalario (que manipula o conteúdo da propriedade Salario) o mesmo valor do campo. Mas por que? Porque, apesar de não haver cálculo, pode ser que no futuro venha a ter, e isso facilitará sobremaneira o cálculo. Além disso, o programador deixa de se preocupar como é calculado o salário do pessoal administrativo, e se por ventura alguma modificação tiver que ser feita, só será no método abaixo:

procedure TAdministrativo.Calcula_Salario ;begin FSalario := FSalario ;end ;

O pessoal da gerência utiliza o salário-base como piso de cálculo e, em cima este salário, acresce-se n % de adicional:

procedure TGerencia.Calcula_Salario ;begin FSalario := FSalario * ( 1 + fAdicional / 100 ) ;end ;

E o pessoal de vendas, ganha porcentagem (25%) de comissão:

procedure TVenda.Calcula_Salario ( Vendas_Efetuadas : Extended ) ;begin FSalario := FSalario + Vendas_Efetuadas * 0.25 ;end ;

f. Simplificando a manipulação de eventos

Você deve estar lembrado que nós utilizamos como base a manipulação de evento OnClick de rbAdm para os radiobutton rbGer e rbVen. O que o código faz, é evitar que você tenha que escrever código espalhado por várias manipulações, evitando que

Page 149: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 149 Todos os direitos reservados.

uma mudança de código-fonte nas várias manipulações envolvidas, demande um grande trabalho de clique de mouse e digitação.

O uso do parâmetro Sender aqui, é para que o código a ser manipulado dependa do objeto que está sofrendo a manipulação:

procedure TfmClasses.rbAdmClick(Sender: TObject);begin If Sender = rbAdm Then begin Label2.Caption := '' ; edbProdutividade.Visible := False ; end Else begin edbProdutividade.Visible := True ; If Sender = rbGer Then Label2.Caption := 'Adicional ( % ) ' Else If Sender = rbVen Then Label2.Caption := 'Vendas Efetuadas ( R$ ) ' end ;end;

g. Utilizando as classes em outras units

Esta é a hora de verificar se o que você declarou, produz resultados satisfatórios: a hora de instanciar o objeto. Note que, o objeto é declarado como sendo de uma determinada classe, mas só existe (memória só é alocada para ele) quando você invoca o método Create (esse método é herdado de TObject). Uma vez criado o objeto, você pode utilizar

procedure TfmClasses.Button1Click(Sender: TObject);Var Admin : TAdministrativo ; Ger : TGerencia ; Ven : TVenda ; VEfet : Extended ;begin If rbAdm.Checked Then begin Try Admin := TAdministrativo.Create ;

Após utilizar o objeto, você deve desalocá-lo da memória (sim, objetos são ponteiros de memória, que você cria em tempo de execução, e destrói também em tempo de execução). Utilize, para isso, o método Free (não utilize o método Destroy, pois se o ponteiro estiver apontando para Nil, haverá um erro em tempo de execução, e seu sistema "desabará") :

Page 150: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 150 Todos os direitos reservados.

procedure TfmClasses.Button1Click(Sender: TObject);Var Admin : TAdministrativo ; Ger : TGerencia ; Ven : TVenda ; VEfet : Extended ;begin If rbAdm.Checked Then begin Try Admin := TAdministrativo.Create ; Admin.Nome := edbNome.Text ;

Admin.Matricula := edbMatricula.Text ; Admin.Salario := StrToFloat ( edbSal_Base.Text ) ; Admin.Calcula_Salario ; edbSalario.Text := Format (' %1.2f ' , [ Admin.Salario ] ) ; Finally Admin.Free ; End ; end Else If rbGer.Checked Then

Código semelhante é utilizado para instanciar o objeto Ger e o objeto Ven.

h. Código-fonte completo:

h1. Unit uClasses:

unit uClasses ;

interface

uses SysUtils ;

type

Erro = class ( Exception ) ;

TFuncionario = Class ( TObject )private fNome : String ; fMat : String ; fSalario : Extended ; function Confere_Matricula ( Const M : String ) : Boolean ;

Page 151: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 151 Todos os direitos reservados.

function GetMat : String ; procedure SetMat ( Const Value : String ) ;public property Nome : String Read fNome Write fNome ; property Matricula : String Read GetMat Write SetMat ; property Salario : Extended Read fSalario Write fSalario ;end ;

TAdministrativo = Class ( TFuncionario )privatepublic procedure Calcula_Salario ;end ;

TGerencia = Class ( TFuncionario )private fAdicional : Extended ;public property Adicional : Extended Read fAdicional Write fAdicional ; procedure Calcula_Salario ;end ;

TVenda = Class (TFuncionario)privatepublic procedure Calcula_Salario ( Vendas_Efetuadas : Extended ) ;end ;

implementation

uses Dialogs ;

function TFuncionario.Confere_Matricula ( Const M : STring ) : Boolean ;Var Dv, i : Integer ;begin Dv := 0 ; For i := 1 To 3 Do Dv := Dv + StrToInt ( M [ i ] ) ; Dv := Dv Mod 10 ; Result := M [ 4 ] = IntToStr ( Dv ) ;end ;

function TFuncionario.GetMat : String ;begin Result := fMat ;end ;

procedure TFuncionario.SetMat ( Const Value : String ) ;begin If Confere_Matricula ( Value ) Then FMat := Value Else Raise Erro.Create ( ' Matrícula Inválida! ' ) ;

Page 152: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 152 Todos os direitos reservados.

end ;

procedure TAdministrativo.Calcula_Salario ;begin fSalario := fSalario ;end ;

procedure TGerencia.Calcula_Salario ;begin fSalario := fSalario * ( 1 + fAdicional / 100 ) ;end ;

procedure TVenda.Calcula_Salario ( Vendas_Efetuadas : Extended ) ;begin fSalario := fSalario + Vendas_Efetuadas * 0.25 ;end ;

end .

h2. Unit uExemplo_de_classe:

unit uExemplo_de_Classe;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls ;

type TfmClasses = class (TForm) edbNome: TEdit; edbMatricula: TEdit; rbAdm: TRadioButton; rbGer: TRadioButton; rbVen: TRadioButton; Label1: TLabel; Label2: TLabel; Label3: TLabel; edbSal_Base: TEdit; Button1: TButton; edbProdutividade: TEdit; edbSalario: TEdit; Label4: TLabel; Label5: TLabel; procedure Button1Click(Sender: TObject); procedure rbAdmClick(Sender: TObject); private { Private declarations } public

Page 153: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 153 Todos os direitos reservados.

{ Public declarations } end;

var fmClasses: TfmClasses;

implementation

uses uClasses ;

{$R *.DFM}

procedure TfmClasses.Button1Click(Sender: TObject);Var Admin : TAdministrativo ; Ger : TGerencia ; Ven : TVenda ; VEfet : Extended ;begin If rbAdm.Checked Then begin Try Admin := TAdministrativo.Create ; Admin.Nome := edbNome.Text ; Admin.Matricula := edbMatricula.Text ; Admin.Salario := StrToFloat ( edbSal_Base.Text ) ; Admin.Calcula_Salario ; edbSalario.Text := Format (' %1.2f ' , [ Admin.Salario ] ) ; Finally Admin.Free ; End ; end Else If rbGer.Checked Then begin Try Ger := TGerencia.Create ; Ger.Nome := edbNome.Text ; Ger.Matricula := edbMatricula.Text ; Ger.Salario := StrToFloat ( edbSal_Base.Text ) ; Ger.Adicional := StrToFloat ( edbProdutividade.Text ) ; Ger.Calcula_Salario ; edbSalario.Text := Format (' %1.2f ' , [ Ger.Salario ] ) ; Finally Ger.Free ; End ; end Else If rbVen.Checked Then begin Try Ven := TVenda.Create ; Ven.Nome := edbNome.Text ; Ven.Matricula := edbMatricula.Text ;

Page 154: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 154 Todos os direitos reservados.

Ven.Salario := StrToFloat ( edbSal_Base.Text ) ; VEfet := StrToFloat ( edbProdutividade.Text ) ; Ven.Calcula_Salario ( VEfet ) ; edbSalario.Text := Format (' %1.2f ' , [ Ven.Salario ] ) ; Finally Ven.Free ; End ; endend;

procedure TfmClasses.rbAdmClick(Sender: TObject);begin If Sender = rbAdm Then begin Label2.Caption := '' ; edbProdutividade.Visible := False ; end Else begin edbProdutividade.Visible := True ; If Sender = rbGer Then Label2.Caption := 'Adicional ( % ) ' Else If Sender = rbVen Then Label2.Caption := 'Vendas Efetuadas ( R$ ) ' end ;end;

end.

h3. Projeto pExemplo_de_classe:

program pExemplo_de_Classe;

uses Forms, uClasses in 'uClasses.pas', uExemplo_de_Classe in 'uExemplo_de_Classe.pas' {fmClasses};

{$R *.RES}

begin Application.Initialize; Application.CreateForm(TfmClasses, fmClasses); Application.Run;end.

i. Distribuindo a unit:

Já lhe foi explicado que, os aplicativos construídos em Delphi, são compostos por um projeto (.DPR) e várias units (.PAS). Uma unit pode ou não ser uma base de um form (você construiu acima uma unit sem form: uClasses.PAS ; ela serviu apenas para declarar as classes). Quando você compilou o programa, o Delphi gerou para você um

Page 155: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 155 Todos os direitos reservados.

arquivo de nome: uClasses.DCU. Como mostra sua extensão: Delphi Compiled Unit , este arquivo é o resultado da compilação de uClasse.PAS. É este arquivo que você entregará ao usuário (desenvolvedor). Na documentação você deve explicar que, para utilizar a sua unit, o usuário (desenvolvedor) deverá declarar na cláusula uses o nome da sua unit:

uses uClasses ;

como você fez no capítulo anterior.

Utilizando o Windows Explorer, você pode ver que são vários os arquivos envolvidos na confecção do aplicativo:

Arquivos temporários: são aqueles que têm um til ( ~ ) como primeiro caractere

da extensão, como: uExemplo_de_Classe.~df . Estes arquivos, após a conclusão do

projeto, podem ser apagados para livrar espaço em disco.

Page 156: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 156 Todos os direitos reservados.

Arquivo executável (Aplicativo): tem o mesmo nome do projeto, porém com extensão .EXE , como: pExemplo_de_Classe.exe.

Units compiladas (Delphi Compiled Unit): são o código-objeto (equivalente) do Delphi. Uma unit compilada tem extensão: .DCU , como: uClasses.dcu e o mesmo nome da unit que contém o código-fonte (units Pascal). Podem ser distribuídas comercialmente, permitindo ao usuário-desenvolvedor utilizar as rotinas por você criadas, sem ter acesso ao código-fonte. Bem como, permite o desenvolvimento de uma ou mais rotinas muito utilizadas em seus projetos, sem a necessidade de reescrever código.

Arquivo de Definição de Formulário (Delphi Form File): é o arquivo que contém uma definição de tudo aquilo que o form contém: nome do form, componentes, manipulações de evento, etc. Tem o mesmo nome da unit que contém o código-fonte (unit Pascal), porém com extensão .DFM , como: uExemplo_de_Classe.dfm.

Units (Delphi Pascal Unit): são os arquivos que contém o código-fonte da unit. Têm extensão .PAS , como: uClasses.pas . O nome do arquivo é o mesmo nome utilizado no cabeçalho unit no código-fonte. Por exemplo, o arquivo uClasses.pas inicia pelo cabeçalho:

unit uClasses;

fazendo com que a distribuição seja facilitada, pois o usuário-desenvolvedor que utilizar a sua unit, poderá fazê-lo apenas declarando na clausula uses o nome do arquivo .DCU que ele obtiver.

Projeto (Delphi Project File): é o elo de ligação entre as várias units que compõe o projeto. Tem extensão .DPR , como: pExemplo_de_Classe.dpr , sendo esse nome utilizado para nomear o código-executável, além de servir como caption para várias janelas de diálogo (execute novamente o aplicativo desenvolvido no capítulo anterior e digite uma matrícula inválida, 1234, por exemplo. Clique o botão e observe que a janela de diálogo traz em seu caption, o nome pExemplo_de_Classe.

Arquivo de Recursos (Resources): é o arquivo que contém as definições dos recursos utilizados pelo projeto, tais como: ícones, bitmaps e cursores. Tem o mesmo nome do projeto, porém com a extensão: .RES , como: pExemplo_de_Classe.res.

Arquivo de Opções do Projeto (Delphi Options File): é um arquivo texto que contém as opções utilizadas pelo Delphi no gerenciamento do projeto. Tem o mesmo

Page 157: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 157 Todos os direitos reservados.

nome do projeto, porém com extensão .DOF, como: pExemplo_de_Classe.dof . Você pode alterar esse arquivo de dentro do Delphi, clicando em Project - Options...

Na janela de opções, você pode selecionar o form principal do seu projeto (main form), ou seja, o form que aparece inicialmente quando o aplicativo é executado (no nosso caso, só temos um form, e por isso somente seu nome aparece: fmClasses):

Page 158: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 158 Todos os direitos reservados.

Clicando na aba Application, você pode configurar o ícone do seu aplicativo:

Clicando na aba VersionInfo, você pode introduzir informações pessoais ao seu projeto. Dê um clique no checkbox Include version information in project :

Na chave (Key) Comments digite: Exemplo de utilização de Classes no campo valor (Value). Clique o botão OK e recompile a aplicação. No Windows Explorer, vá até a pasta que contém o aplicativo que você acaba de produzir, e clique com o botão direito do mouse sobre o ícone deste aplicativo. Clique no item Propriedades e depois clique na aba Versão. Veja que as informações por você alteradas, aparecem no quadro de informação da versão do aplicativo. Utilize o Help online do Delphi para maiores detalhes.

Page 159: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 159 Todos os direitos reservados.

14.4. Métodos estáticos, virtuais e dinâmicos - Polimorfismo

Métodos que são simplesmente declarados em uma classe, são ditos estáticos. Se uma classe declara um método estático e uma classe descendente declara o mesmo método, o código executado pode não ser o esperado, como ilustra o exemplo abaixo:

Comece uma nova aplicação Altere a unit1 com o código abaixo (não reescreva o código em itálico):

unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;

TClasse1 = class (TObject) procedure Mostra ; end;

TClasse2 = class (TClasse1) procedure Mostra ; end;

var Form1: TForm1;

implementation

{$R *.DFM}

procedure TClasse1.Mostra ;begin ShowMessage ( 'Método da classe 1' ) ;end ;procedure TClasse2.Mostra ;begin ShowMessage ( 'Método da classe 2' ) ;end ;

end.

Page 160: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 160 Todos os direitos reservados.

Coloque um botão no form Manipule o evento OnClick do botão com:

procedure TForm1.Button1Click(Sender: TObject);Var Classe : TClasse1 ;begin Try Classe := TClasse1.Create ; Classe.Mostra ; Finally Classe.Free ; End ;

Try Classe := TClasse2.Create ; Classe.Mostra ; Finally Classe.Free ; End ;end;

Obs1.: Na declaração das classes TClasse1 e TClasse2 você notou a ausência das cláusulas private e public. Isso significa dizer que, na ausência dessas cláusulas, o que está declarado tem escopo igual a "public".

Obs2.: Como TClasse2 é descendente de TClasse1, você pode declarar uma variável como sendo uma instância de TClasse1 e instanciá-la de TClasse2, como mostra o código acima.

Execute a aplicação Clique o botão e observe que as janelas de mensagem trazem como aviso:

Método da Classe1. Feche a aplicação

O que ocorreu poderia ter sido evitado de duas maneiras:

- Utilizando uma variável Classe1 para instanciar TClasse1 e uma variável Classe2 para instanciar TClasse2.

- Utilizar override de método

a. Variáveis diferentes

Para tanto, basta alterar a seção Var da manipulação OnClick de Button1para:

Var Classe1 : TClasse1 ; Classe2 : TClasse2 ;

Page 161: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 161 Todos os direitos reservados.

e instanciar cada classe com sua variável, ou seja:

procedure TForm1.Button1Click(Sender: TObject);Var Classe1 : TClasse1 ; Classe2 : TClasse2 ;begin Try Classe1 := TClasse1.Create ; Classe1.Mostra ; Finally Classe1.Free ; End ;

Try Classe2 := TClasse2.Create ; Classe2.Mostra ; Finally Classe2.Free ; End ;end;

b. Override de método: Polimorfismo

Outra solução é fazer override de método. Para tanto, coloca-se após a declaração do método na classe ancestral, a diretiva virtual (ou dynamic). Na classe descendente, após a declaração do método, coloca-se a diretiva override, fazendo o que é chamado de polimorfismo, isto é, um mesmo método comportando-se de maneira diferente dependendo da classe a qual ele pertence.

Na seção interface da unit1, altere a declaração das classes com:

TClasse1 = class (TObject) procedure Mostra ; virtual ; end;

TClasse2 = class (TClasse1) procedure Mostra ; override ; end;

Execute novamente a aplicação e observe que, agora, as janelas demensagem trazem os avisos corretos.

Feche a aplicação.

Obs3.: Métodos virtual e dynamic são idênticos, a não ser pelo fato que, métodos virtuais causam aumento no código-executável, ao passo que métodos dinâmicos causam um aumento no tempo de processamento. Em geral, métodos virtuais são mais eficientes num "override"; porém, se a declaração da classe (ou das classes) envolver muitos métodos virtuais, deve-se utilizar métodos dinâmicos.

Page 162: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 162 Todos os direitos reservados.

Obs4.: Há também a situação que, ao invés de substituir o método da classe ascendente, o método da classe descendente tem que executar também aquele código. Por exemplo, se o método da classe ascendente realiza um determinado cálculo, e o método da classe descendente realiza não só aquele cálculo, como também outros dois cálculos, você tem que utilizar a diretiva inherited. Vamos modificar o código acima:

Coloque entre chaves (comentário), a instanciação de TClasse1, como mostrado abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var Classe : TClasse1 ;begin

{ Try Classe := TClasse1.Create ; Classe.Mostra ; Finally Classe.Free ;

End ;}

Try Classe := TClasse2.Create ; Classe.Mostra ; Finally Classe.Free ; End ;

end;

Execute a aplicação Dê um clique no botão. Observe que só aparece o aviso: Método da Classe 2 Feche a aplicação Adicione a palavra inherited ao método Mostra da TClasse2:

procedure TClasse2.Mostra ;begin Inherited ; ShowMessage ( 'Método da classe 2' ) ;end ;

Execute a aplicação Dê um clique no botão e observe que os avisos: Método da Classe 1 e

Método da Classe 2 aparecem, um após o outro, comprovando que o código escrito em TClasse1.Mostra foi executado também.

Feche a aplicação

Page 163: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 163 Todos os direitos reservados.

14.5. TypeCasting e operadores de Classe: IS e AS

O Operador IS compara um objeto e uma classe, e resulta True (verdadeiro) se o objeto é daquela classe; caso contrário, retorna False (falso). Geralmente é utilizado com o comando If / Then.

Já o operador AS referencia um objeto como sendo de uma determinada classe.Por exemplo, o código abaixo faz com que o pressionar da tecla Enter passe de

um componente TEdit para outro. Para isso, seguiremos os seguintes passos:

a. Verificar se o controle ativo (ActiveControl) é um edit box (TEdit)b. Se for, verificar se a tecla Enter, cujo código ASCII é 13 foi pressionadac. Se foi, armazenar na variável "i" a ordem do componente no form (todo

componente tem uma propriedade denominada TabOrder; verifique no Object Inspector). O primeiro TabOrder é igual a 0 (zero).

d. Incrementar i até que o componente naquela ordem seja um TEdit. Se o valor de i for igual ao número de componentes do form, inicializar i com 0 (lembre que para n componentes, TabOrder vai de 0 até ComponentCount - 1, pois o TabOrder do primeiro componente é 0)

e. Dar o foco ao componente naquela posição

Vamos então colocar isto em prática.

Comece uma nova aplicação Coloque um memo e 6 edit box no form Altere a propriedade KeyPreview de Form1 para True

Obs5.: Isto garante que, ao pressionar de uma tecla, independente do controle ativo, Form1 receberá o código ASCII na variável Key.

Manipule seu evento OnKeyPress com:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);Var i : Integer ;begin If ActiveControl is tEdit Then If Key = #13 Then begin

i := ActiveControl.TabOrder ; Repeat Inc ( i ) ; If i = ComponentCount Then i := 0 ; Until Components [ i ] is TEdit ;

Components [ i ].SetFocus ; end ;end;

Page 164: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 164 Todos os direitos reservados.

Execute a aplicação. Acontece um erro em tempo de compilação, pois Components é do tipo TComponents que por sua vez não possui um método SetFocus. Para solucionar o problema, você relizará um TypeCasting, fazendo uma referenciação do objeto apontado por Components [i] como sendo da classe TEdit que, este sim, possui um método denominado SetFocus.

Altere a manipulação de evento acima para:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);Var i : Integer ;begin If ActiveControl is tEdit Then If Key = #13 Then begin i := ActiveControl.TabOrder ; Repeat Inc ( i ) ; If i = ComponentCount Then i := 0 ; Until Components [ i ] is TEdit ;

(Components [ i ] as TEdit ).SetFocus ; end ;end;

Execute a aplicação, dê um clique em Memo1, digite alguma coisa e pressione a tecla Enter. Dê um clique em Edit1, digite alguma coisa e pressione a tecla Enter. Pressione a teclaa Enter novamente. Verifique que, se o componente ativo for um edit box, o controle passa para o próximo edit box.

Feche a aplicação

Obs6.: Uma maneira rápida de alterar o TabOrder dos componentes do form, é clicando com o botão direito do mouse sobre o form e depois clicando no item TabOrder

Page 165: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 165 Todos os direitos reservados.

Quando aparecer o Tab Order Editor, você poderá ordenar os componentes no form da forma como você achar mais conveniente (isto fará você alterar a propriedade TabOrder de todos os componentes envolvidos, já que dois componentes não podem ter o mesmo TabOrder):

Obs7.: Para que um componente

possa ser acessado com a tecla Tab, a sua propriedade TabStop deve ser True; caso contrário, o componente só será acessível através do mouse. Independente de TabStop estar com True ou False, todo componente continua tendo um TabOrder.

Obs8.: TypeCast direto também pode ser feito, de tal maneira que a linha de comando:

(Components [ i ] as TEdit ).SetFocus ;

poderia ter sido substituída pela linha de comando:

TEdit (Components [ i ]).SetFocus ;

Recomenda-se não utilizar a segunda forma, pois em outras situações onde seja necessário um TypeCasting, se o objeto que está sendo referenciado não seja da classe respectiva, nada acontecerá, podendo ser desastroso o resultado de tal operação. Já a primeira forma (com o operador as), na hipótese de uma conversão impossível, acontece o erro EInvalidCast (em tempo de execução).

Obs9.: Como o padrão estabelecido pela Microsoft® para alternar entre componentes é a tecla Tab, utilize esta alteração do padrão com certa cautela, pois o sistema que você fizer poderá produzir resultados catastróficos (ou não produzir resultado

algum) caso, numa atualização hipotética do sistema operacional, a Microsoft®

destine nova função para a tecla Enter.

Diminui o TabOrder do componente selecionado

Aumenta o TabOrder do componente selecionado

Page 166: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 166 Todos os direitos reservados.

15. Arquivos em disco

Para você poder trabalhar com um arquivo em disco, você tem que declarar uma variável que seja de um dos tipos: TextFile, File Of <tipo> ou File. Após isso, você tem que associar a variável a um arquivo em disco, iniciar o uso dessa variável (o que equivale a abrir o arquivo em disco para manipulação) e, finalmente, fechar o arquivo.

15.1. Arquivos TextFile

São arquivos que armazenam linhas de caracteres ASCII.

Comece uma nova aplicação Coloque um memo no form e apague o conteúdo da propriedade Lines Coloque um botão no form e manipule o evento OnClick com:

procedure TForm1.Button1Click(Sender: TObject);Var Arq : TextFile ; i : Integer ;begin AssignFile ( Arq , 'C:\Leia.txt' ) ; Try Rewrite ( Arq ) ; For i := 0 To ( Memo1.Lines.Count - 1 ) Do Writeln ( Arq , Memo1.Lines.Strings [ i ] ) ; Finally CloseFile ( Arq ) ; End ;end;

Execute a aplicação Digite algumas linhas em Memo1 Clique o botão Feche a aplicação Vá ao Windows Explorer e veja que o arquivo Leia.txt está armazenado na

pasta C:\ , com o conteúdo daquilo que você digitou em Memo1.

Obs1.: A procedure Rewrite cria o arquivo em disco, caso o mesmo não exista no momento da execução da procedure.

Obs2.: Para abrir um arquivo existente em disco, utilize a procedure Reset . Porém, se no momento da execução de Reset o arquivo a ser aberto não exista na pasta especificada, acontece um erro em tempo de execução. Esse problema pode ser resolvido de dois modos: bloco TRY / EXCEPT / END ou através da função IORESULT (da unit System).

Page 167: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 167 Todos os direitos reservados.

a. Bloco de proteção

Você deve alterar a manipulação acima para:

procedure TForm1.Button1Click(Sender: TObject);Var Arq : TextFile ; i : Integer ;begin AssignFile ( Arq , 'C:\Leia.txt' ) ; Try Try Reset ( Arq ) ; Except Rewrite ( Arq ) ; End ; For i := 0 To ( Memo1.Lines.Count - 1 ) Do Writeln ( Arq , Memo1.Lines.Strings [ i ] ) ; Finally CloseFile ( Arq ) ; End ;end;

b. Função IORESULT

Essa função retorna um valor inteiro que identifica o status da última operação de E / S (Entrada / Saída) realizada. Caso não tenha ocorrido erro algum, IORESULT retorna o valor 0 (zero). Deve-se utilizar com IORESULT, a diretiva de compilação {$I}, que "desliga" erros de E / S, como mostrado abaixo:

procedure TForm1.Button1Click(Sender: TObject);Var Arq : TextFile ; i : Integer ;begin AssignFile ( Arq , 'C:\Leia.txt' ) ; Try

{ $I- } Reset ( Arq ) ; { $I+ } If IORESULT <> 0 Then Rewrite ( Arq ) ; For i := 0 To ( Memo1.Lines.Count - 1 ) Do Writeln ( Arq , Memo1.Lines.Strings [ i ] ) ; Finally CloseFile ( Arq ) ; End ;

Page 168: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 168 Todos os direitos reservados.

end; Comece uma nova aplicação Coloque um memo, um botão e um opendialog (aba Dialogs) no form Altere o filtro de OpenDialog1 para ler arquivos texto e todos os arquivos Manipule o evento OnClick de Button1 com:

procedure TForm1.Button1Click(Sender: TObject);Var Arq : TextFile ; Linha : String ; i : Integer ;begin If OpenDialog1.Execute Then AssignFile ( Arq , OpenDialog1.FileName ) ; Try Try Reset ( Arq ) ; Except Rewrite ( Arq ) ; End ; i := 0 ; While Not EOF ( Arq ) Do begin Readln ( Arq , Linha ) ; Memo1.Lines.Strings [ i ] := Linha ; Inc ( i ) ; end ; Finally CloseFile ( Arq ) ; End ;end;

Obs3.: Todo arquivo aberto em disco tem, além de um número de manipulação (este número é chamado Handle do arquivo), um ponteiro que indica em que ponto do arquivo o aplicativo que o abriu encontra-se. A cada leitura de uma linha, o ponteiro é deslocado para a posição seguinte. Quando esse ponteiro alcança uma posição além do fim (end) do arquivo (file), a função Eof retorna o valor booleano True. Sendo assim, a linha de comando:

While Not EOF ( Arq ) Do

garante que o processamento continua enquanto não for fim de arquivo (EOF = End Of File). Utilize o Help online do Delphi para maiores detalhes sobre a manipulação de arquivos de texto.

Page 169: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 169 Todos os direitos reservados.

15.2. Arquivos File Of

São arquivos que armazenam dados de um mesmo tipo (registros do aquivo), em um formato próprio do Object Pascal, podendo ser File Of: Integer, Real, Record etc.

Arquivos File Of ao contrário dos arquivos texto, arquivos typed estão abertos para operações de leitura e escrita (gravação) ao mesmo tempo, utilizando a procedure Seek para acessar um determinado registro do arquivo, além de utilizar as procedures Read para ler e Write para escrever.

Comece uma nova aplicação Coloque um memo, três botões e um opendialog (aba Dialogs) no form Coloque três edit box (para escrever nome, endereço e salário) Altere o filtro de OpenDialog1 para ler arquivos .DAT e todos os arquivos Manipule o evento OnClick de Button1 com:

procedure TForm1.Button1Click(Sender: TObject);begin If Not OpenDialog1.Execute Then OpenDialog1.FileName := 'Sem Nome.DAT' ;end;

Manipule o evento OnClick de Button2 com:

procedure TForm1.Button2Click(Sender: TObject);Type Reg = Record Nome : String [50] ; Endereco : String [100] ; Salario : Extended ; End ;Var Arq : File Of Reg; R : Reg ; Linha : String ; i : Integer ;begin AssignFile ( Arq , OpenDialog1.FileName ) ; Try Try Reset ( Arq ) ; Except Rewrite ( Arq ) ; End ; R.Nome := Edit1.Text ; R.Endereco := Edit2.Text ; R.Salario := StrToFloat ( Edit3.Text ) ;

Page 170: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 170 Todos os direitos reservados.

Seek ( Arq, FileSize ( Arq ) ) ; Write ( Arq , R ) ; Finally CloseFile ( Arq ) ; End ;end;

Manipule o evento OnClick de Button3 com:

procedure TForm1.Button3Click(Sender: TObject);Type Reg = Record Nome : String [50] ; Endereco : String [100] ; Salario : Extended ; End ;Var Arq : File Of Reg; R : Reg ; Linha : String ; i : Integer ;begin AssignFile ( Arq , OpenDialog1.FileName ) ; Try Try Reset ( Arq ) ; Except Rewrite ( Arq ) ; End ; i := 0 ; While Not EOF ( Arq ) Do begin Read ( Arq , R ) ; Memo1.Lines.Add ( 'Nome: ' + R.Nome ) ; Memo1.Lines.Add ( 'Endereço: ' + R.Endereco ) ; Memo1.Lines.Add ( 'Salario: R$ ' + FloatToStr (R.Salario) ) ; Memo1.Lines.Add ( '' ) ; // Pula uma linha Inc ( i ) ; end ; Finally CloseFile ( Arq ) ; End ;end;

Clique em button1 e digite um nome no campo Nome do Arquivo: da janela de diálogo Abrir.

Rode o aplicativo. Digite n1 em edit1, e1 em edit2 e 1,00 em edit3 e clique em button1. Repita este procedimento mais duas vezes.

Page 171: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 171 Todos os direitos reservados.

Clique em button3. Verifique que só aparece a última digitação. Feche a aplicação.

Obs.: Cada vez que você abre o arquivo para escrita e leitura, o ponteiro do arquivo é posicionado no primeiro registro, o que faz com que a cada entrada você sobrescreva o dado anterior. Para evitar que isso aconteça, você pode:

- Criar o arquivo Arq como sendo uma variável global e abriando-a somente uma vez (conseqüentemente, fechando-a a penas uma vez), o que faz com que a cada operação de escrita, o ponteiro avance uma posição à frente. Para ler do início, deve-se executar a procedure Seek, especificando a posição 0 (zero), correspondente ao primeiro registro do arquivo: Seek (Arq, 0)

- A cada clique em button2, executa-se o a procedure Seek, especificando o final do arquivo com a função FileSize (que retorna o tamanho de registros do arquivo): Seek (Arq, FileSize (Arq)) como mostrado abaixo:

procedure TForm1.Button2Click(Sender: TObject);Type Reg = Record Nome : String [50] ; Endereco : String [100] ; Salario : Extended ; End ;Var Arq : File Of Reg; R : Reg ; Linha : String ; i : Integer ;begin AssignFile ( Arq , OpenDialog1.FileName ) ; Try Try Reset ( Arq ) ; Except Rewrite ( Arq ) ; End ; R.Nome := Edit1.Text ; R.Endereco := Edit2.Text ; R.Salario := StrToFloat ( Edit3.Text ) ;

Seek ( Arq, FileSize ( Arq ) ) ; Write ( Arq , R ) ; Finally CloseFile ( Arq ) ; End ;end;

Page 172: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 172 Todos os direitos reservados.

15.3. Arquivos File

Arquivo Untyped não é muito usado em programas aplicativos, mas pode ser útil em operações de cópia de arquivos (como em cópias de segurança ou, backup).

Vamos supor que você esteja trabalhandoem C:\Diretorio com dois arquivos de dados de nomes: CADASTRO.DB e CADASTRO.PX . Para fazer um backup dos dois arquivos você pode manipular o evento OnClick do botão com:

Var oCadDB, oCadPX, dCadDB, dCadPX : File ; QIL,QIE:Integer ; { QIL = Quant_Info_Lida ; QIE = Quant_Info_Escrita } Buffer : Array [1..1024] of Byte;begin Screen.Cursor := crHourGlass ; AssignFile (oCadDB , 'C:\Diretorio\Cadastro.Db') ; // oCad.Db Origem AssignFile (oCadPX , 'C:\Diretorio\Cadastro.Px') ; AssignFile (dCadDB , 'C:\Diretorio\Cadastro.Dbk') ; // dCad.Dbk Destino AssignFile (dCadPX , 'C:\Diretorio\Cadastro.Pxk') ; Try Reset (oCadDB,1) ; Reset (oCadPX,1) ; Rewrite (dCadDB,1) ; Rewrite (dCadPX,1) ; BlockRead (oCadDB, Buffer,SizeOf(Buffer),QIL) ; While QIL > 0 Do begin BlockWrite (dCadDB, Buffer, QIL, QIE) ; BlockRead (oCadDB, Buffer,SizeOf(Buffer),QIL) ; end ; BlockRead (oCadPX, Buffer,SizeOf(Buffer),QIL) ; While QIL > 0 Do begin BlockWrite (dCadPX, Buffer, QIL, QIE) ; BlockRead (oCadPX, Buffer,SizeOf(Buffer),QIL) ; end ; Finally CloseFile (oCadDB) ; CloseFile (oCadPX) ; CloseFile (dCadDB) ; CloseFile (dCadPX) ; Screen.Cursor := crDefault ; End ;end ;

Obs1.: Com essa rotina, cada byte do arquivo de origem vai sendo lido e escrito no arquivo de destino, até que a quantidade de bytes lidos do arquivo de origem

Page 173: Delphi

Delphi 3.0™

- Apostila registrada para: Professor José Luiz A. Rosa - 1998 - Universidade Estácio de Sá 173 Todos os direitos reservados.

(QIL) seja igual a zero, quando então é finalizado que não há mais informação a ser lida.

Obs2.: Altere C:\Diretorio com o nome do diretório que contém os arquivos de dados.