Você está na página 1de 162

Apostila de Delphi 4

Indice

APOSTILA DE DELPHI 4 ....................................................................................... 1

1 CURSO DE DELPHI 4.0 - APOSTILA 1 ........................................................... 3

2 CURSO DE DELPHI 4.0 - APOSTILA 2 ......................................................... 11

3 CURSO DE DELPHI 4.0 - APOSTILA 3 ......................................................... 19

4 CURSO DE DELPHI 4.0 - APOSTILA 4 ......................................................... 29

5 CURSO DE DELPHI 4.0 - APOSTILA 5 ......................................................... 38

6 CURSO DE DELPHI 4.0 - APOSTILA 6 ......................................................... 44

7 CURSO DE DELPHI 4.0 - APOSTILA 7 ......................................................... 54

8 CURSO DE DELPHI 4.0 - APOSTILA 8 ......................................................... 59

9 CURSO DE DELPHI 4.0 - APOSTILA 9 ......................................................... 69

10 CURSO DE DELPHI 4.0 - APOSTILA 10 .................................................... 78

11 CURSO DE DELPHI 4.0 - APOSTILA 11 .................................................... 88

12 CURSO DE DELPHI 4.0 - APOSTILA 12 .................................................. 108

13 CURSO DE DELPHI 4.0 - APOSTILA 13 .................................................. 118

14 CURSO DE DELPHI 4.0 - APOSTILA 14 .................................................. 130

15 CURSO DE DELPHI 4.0 - CONEXÃO DELPHI COM O MS-ACCESS...... 139

16 CURSO DE DELPHI 4.0 - PRINCIPAIS INSTRUÇÕES EM SQL.............. 141

17 CURSO DE DELPHI 4.0 - PROGRAMAÇÃO ORIENTADA A OBJETOS 153


1 Curso de Delphi 4.0 - Apostila 1

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• PASCOA2G.BMP

Prefácio
Salve, para você que está começando e participando deste curso, primeiramente gostaria de avisar
que o curso é totalmente prático, com exercícios e truques que lhe ajudarão a senão dominar pelo menos a
desvendar os mistérios desse maravilhoso ambiente. Deixa eu dar um conselho que eu aprendi a duras penas,
tente sempre que acontecer algum erro, mostrá-lo para um colega que conheça também Delphi. Uma vez
fiquei quase dois dias com um erro me incomodando, imprimi, revi linha a linha até que finalmente pedi para
que um amigo do lado olhasse meu programa em menos de 1 segundo ele descobriu o erro, era um simples
comando IF que tinha construído errado. Existe uma frase para o Delphi que sempre utilizo quando começo
meus cursos é assim:

Tudo o que parece difícil na verdade é fácil


Tudo o que parece fácil na verdade é muito mais fácil.

Isso sempre funcionou com o Delphi. Um abraço e bom trabalho.

Solicito que quando você encontrar a seguinte simbologia ☞ Importante pare e leia com a maior
atenção, pois ali você encontrará uma dica valiosa que poderá lhe ajudar a esclarecer várias dúvidas.

O Delphi é um ambiente de Desenvolvimento totalmente Baseado na Orientação a Objetos, não é


puro (discutiremos isso no apêndice referente a Orientação a Objetos) mas por enquanto você precisa apenas
saber que ele é uma ferramenta com um incrível poder na construção tanto de softwares complexos, quanto de
sistemas de manipulação a bancos de dados.

Para o nosso primeiro contato com a ferramenta, selecionei algo prático, fácil, útil e até mesmo
bonitinho, um cartão eletrônico, você poderá mandar para seus amigos um simples executável com uma
mensagem, vou criar aqui um para a Páscoa mas é possível aproveitar a idéia para outros eventos também tais
como Natal, Aniversários, nascimentos e assim vai. Vamos começar então:

Conhecendo o Ambiente
Abra o Delphi, bem aí está seu ambiente de trabalho, vamos a uma rápida explicação, o Delphi é
composto por quatro ambientes de trabalho:

1. Parte superior composta pelo Menu, Component Pallete e Botões de Acesso Rápido
(Speed Button): é exatamente o conjunto que está suspenso na área aberta, o Menu (localizado no topo)
dá acesso as opções, a Component Pallete (localizado na parte superior direita) contém todos os objetos
(divididos em classes) que você utilizará para realizar seus projetos, e os Botões de Acesso Rápido
(localizado na parte superior esquerda) que são uma abreviação dos comandos do menu.

Uma novidade do Delphi 4.0 é que todos eles estão colocados em janelas auto-arrastáveis, então é
possível modificar as possições entre eles ou criar janelas suspensas basta para isso que você clique no canto
(dessas partes duplas) segure e arraste.

2. Object Inspector: é uma janelinha lateral (chamada como a tecla F11) que contém as propriedades e os
eventos dos objetos selecionados.

3. Form: este objeto será sua prancheta de trabalho é nessa janela em branco (seria melhor dizer em cinza)
que criaremos nossa comunicação entre o sistema e os nossos usuários.

4. Code Editor: é a área localizada atrás do "Form", ela foi dividida em dois ambientes, uma parte que
funcionará como índice, nos mostrandos os objetos existentes, as bibliotecas utilizadas e as variáveis ou
constantes disponíveis, elém dos procedimentos e funções criadas e uma outra que conterá nossas o código
propriamente dito (em linguagem Object Pascal), diferentemente das outras linguagens visuais, no Delphi
você tem a capacidade de visualizar todo o código do seu formulário e não apenas uma determinada parte.
Projeto 1 - Cartão Eletrônico
Bem, agora que estamos familiarizados com o ambiente, vamos começar como uma receita de bolo,
siga um passo atrás do outro, mas antes de começar, crie uma pasta que abrigará seu projeto, para padronizar
vamos criar uma pasta com o nome CursoDelphi e dentro dela criaremos uma nova pasta chamada Cartão, e
coloque nela o .BMP enviado:

1. Na Component Pallete localize uma página chamada Additional e dentro dessa página de um clique no
objeto Image (acredito que seja o sexto) e dê um clique no Form. (automaticamente o Delphi criou um
quadrado quadriculado que representa o objeto Image1).

2. Olhe na Object Inspector e verifique as propriedades do objeto Image1 criado, e altere as seguintes
propriedades:

2.1. AutoSize: True (Fará com que o tamanho do objeto fique automaticamente do tamanho da
figura selecionada)
2.2. Picture: Clique nos "..." (ou dê um duplo clique em cima do objeto criado) e localize o arquivo
.BMP enviado (Seleciona determinada figura)

3. Vá na Object Inspector e localize o objeto Form1 (basta clicar no Combo Box para seleciona-lo), e altere
as seguintes propriedades:

3.1. BorderStyle: bsDialog (Fará com que a janela fique no formato padrão de uma janela de
mensagens)
3.2. Caption: Feliz Páscoa (Conteúdo da tarja do formulário)
3.3. Color: clBlack (Cor do formulário para preto)
3.4. Font: Clique nos "..." e faça as seguintes alteções na janela de Fonts:
3.41. Cor: Branco
3.42. Tamanho: 10
3.4. Name: F_Cartao (Nome interno do formulário)
3.5. Position: poScreenCenter (Fará com que o formulário fique sempre centralizado quando for
executado)

☞ Importante - Após alterarmos a Cor (propriedade Color) e a Fonte (propriedade Font) todos os outros
objetos criados em cima deste Form, automaticamente herdarão essas alterações.

4. Dê uma salvadinha no seu projeto, para tanto, no menu vá em File | Save All...:
4.1. Aonde aparece Unit1.pas (o Delphi está se referindo do nome do formulário) mude para
fCartao.PAS
4.2. Aonde aparece Project1.dpr (o Delphi está se referindo do nome do projeto - que será o nome
do executável final) mude para Cartao.DPR

5. Na Component Pallete localize uma página chamada Standard e dentro dessa página localize o objeto
Label (acredito que seja o terceiro) pressione a tecla SHIFT e clique no objeto (deve ter ficado um
quadriculado azul em volta do objeto, como se ficasse marcado) e dê oito cliques no Form - um abaixo do
outro e na área preta. (automaticamente o Delphi criou oito objetos chamados respectivamente Label1,
Label2, Label3, Label4, Label5, Label6, Label7 e Label8)

6. Quando terminar clique dentro da Component Pallete na setinha para poder desmarcar o objeto Label.

7. Dê uma comparadinha no desenho para ver como está ficando:

Bom, todos os objetos que serão visíveis já estão aí, agora vamos criar dois objetos que servirão
apenas como meros auxiliares:

7. Na Component Pallete na mesma página Standard clique no objeto Memo (acredito que seja o quinto) e
dê um clique no Form (automaticamente o Delphi criou um quadrado que representa o objeto Memo1).

8. Olhe na Object Inspector e verifique as propriedades do objeto Memo1 criado, e altere as seguintes
propriedades:

8.1. Font: Clique nos "..." e faça as seguintes alteções na janela de Fonts:
8.11. Cor: Preto
8.12. Tamanho: 8
8.2. Lines: Clique nos "..." e copie o seguinte texto:

Recebe, Oh Senhor,
em sua gloria eterna
e envolve com paz e amor
este sacrifício em incenso,
que sobe clamando por justiça
por todos os meninos assassinados
pelos pobres que morrem de fome
pelas mulheres violentadas
pelo povo roubado e explorado.

E perdoa, Oh Senhor,
perdoa o Brasil,
seu presidente estratosférico,
seus deputados escondidos,
seus senadores omissos,
sua igreja distraída,
seus militares fantoches,
sua polícia ausente,
perdoa nós todos, Senhor,
perdoa a mim e a meu irmão
que nada fizemos,
que não agimos,
e que não vimos
a imagem de seu filho
Cristo na Cruz.

Ou digite um outro texto que mais lhe agradar, mas anote o número de linhas (neste aqui temos 25
linhas)

8.3. Visible: False (Não mostrará o objeto em tempo de execução)

9. Na Component Pallete na página System clique no objeto Timer (acredito que seja o primeiro) e dê um
clique no Form (automaticamente o Delphi criou um quadradinho com um relógio, que por sinal é uma cópia
do desenho do objeto). A propriedade Interval controla a velocidade do objeto.

Codificando
Tudo pronto, agora é só meter a mão no programa, mas vamos devagar, a idéia do cartão, se você
ainda não entendeu, é que ao ser executado a mensagem que está guardada dentro do objeto Memo1 rolará
entre os oito labels (como se tivesse subindo) para isso foi criado um Temporizador (Objeto Timer1), que é
ativado a cada segundo (através da propriedade Interval, medida em milésimos de segundo) que simulará o
movimento entre os labels. Então vamos começar a brincadeira:

10. Pressione a tecla F12, até você ter acesso a Code Editor, sugiro que você maximize a área para trabalhar
melhor, localize as seguintes linhas:

private
{ Private declarations }
public
{ Public declarations }
end;

e altere para o seguinte:

private
NumLinha: Integer;
public
{ Public declarations }
end;
Você acaba de criar uma variável particular (Private) do tipo inteira (Integer) que servirá apenas a
este formulário, sendo criada e destruída junto com ele.

11. Localize na Object Inspector o objeto F_Cartao, mude para a página de eventos (Events) e localize o
evento OnShow, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a
chamada ao evento e o transferirá para a Code Editor, insira o seguinte código:

procedure TF_Cartao.FormShow(Sender: TObject);


var
i : Integer;
begin
for i := ComponentCount - 1 downto 0 do
if (Components[I] is TLabel) then
(Components[I] as TLabel).Caption := '';
NumLinha := 0;
end;

Neste evento que é disparado assim que o formulário se inicia, limparemos os oito Labels para isso
simplesmente utilizaremos uma string vazia, use aspas simples (nunca duplas) e sem espaços entre elas, para
chamar os oito labels utilizaremos a variável ComponentCount para contar quantos componentes tem o
formulário, verificamos quais deles são label's e estes limparemos e iniciarmos a nossa variável NumLinha
com 0.

☞Importante - Muitos dos procedimentos que o Delphi cria automaticamente (através dos eventos)
requisitam a passagem de um objeto do tipo TObject (Sender: TObject), isso faz você saber quem foi que
ativou tal evento, se foi por ação de um mouse ou de um clique num botão, e assim vai.

Aqui foi preciso rastrear todos os componentes do formulário através do comando Components[n],
aonde n é o número de cada componente. Isto é iniciado do 0 (assim como todo Array no Delphi começa do
0, ex: Lines, Items...), então é preciso criar um FOR que vai do 0 até o (número total de componente-1)
porque o primeiro é o 0 isto explicasse imaginando uma lista de 10 números começados pelo 0, vc terá
0,1,2,3,4,5,6,7,8,9 então o último número será o número total da sua lista - 1.

☞Importante - Claro que ao invés de usarmos:


for i := ComponentCount - 1 downto 0 do
if (Components[I] is TLabel) then
(Components[I] as TLabel).Caption := '';

poderiamos muito bem utilizar:

Label1.Caption := '';
Label2.Caption := '';
Label3.Caption := '';
Label4.Caption := '';
Label5.Caption := '';
Label6.Caption := '';
Label7.Caption := '';
Label8.Caption := '';

Mas isso além de ficar um tantinho mais inchado, fica muito deselegante, é verdade que estamos
tratando apenas com 8 objetos label's mas e se amanhã utilizamos 20 ou 30 ?? Além do que isso pode-se dizer
que é o primeiro passo para um recurso de MacroSubstituição, como foi utilizado com o TLabel, pode
também ser utilizado para o TEdit, TEditMask , TDBText ou qualquer outro que você deseje.
12. Localize na Object Inspector o objeto Timer1, mude para a página de eventos (Events) e localize o
evento OnTimer, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a
chamada ao evento e o transferirá para a Code Editor, entre os intervalos begin e end escreva:

procedure TF_Cartao.Timer1Timer(Sender: TObject);

function Monta : String;


begin
result := Memo1.Lines[NumLinha];
inc(NumLinha);
if NumLinha > 30 then NumLinha := 0;
end;

begin
NumLinha := NumLinha - 7;
Label1.Caption := Monta;
Label2.Caption := Monta;
Label3.Caption := Monta;
Label4.Caption := Monta;
Label5.Caption := Monta;
Label6.Caption := Monta;
Label7.Caption := Monta;
Label8.Caption := Monta;
end;

Neste evento é que está toda a jogada do programa, note que dentro da procedure colocamos uma
função interna Monta que nos retornará o conteúdo de uma determinada linha do objeto Memo1, note que
trabalhamos com 8 label's, então:

☞Importante - Note que existe uma variável chamada Result ela é uma variável definida pela própria
função (no caso tipo String), poderíamos aqui usar dois nomes ou Monta ou a palavra chave Result, ambos
os nomes apontam para a mesma variável que tem como função fazer a devolução da String definida pela
função (para maiores referências veja a apostila Programação Orientada a Objetos)

no primeiro segundo que passar:


Label1 até Label7 = Branco e o Label8 com o conteúdo da primeira linha do objeto Memo1.

No próximo segundo que passar:


Label1 até Label6 = Branco, Label7 com o conteúdo da primeira linha do objeto Memo1 e o Label8 com o
conteúdo da segunda linha do objeto Memo1.

No próximo segundo que passar:


Label1 até Label5 = Branco, Label6 com o conteúdo da primeira linha do objeto Memo1 e o Label7 com o
conteúdo da segunda linha do objeto Memo1 e Label8 com o conteúdo da terceira linha do objeto Memo1

E assim vai aumentando segundo após segundo, até um total de 30 segundos, note aqui que são 25
linhas, aumentei mais 5 para ter um intervalo entre a última linha e o começo de uma nova montagem quando
a variável monta linha é novamente reiniciada a zero.

Note que para adicionar 1 a variável NumLinha utilizo a função interna INC, esta função também
pode ser: Inc(variável, [quanto]) aonde "quanto" representa o número que você quer adicionar a variável, se
não for enviado será por default 1. Isto seria o correspondente: variável := variável + quanto; e só de
curiosidade o contrário da função INC é a função DEC.

☞Importante - os brancos são conseguidos pesquisando valores negativos dentro da propriedade Lines do
objeto Memo1. Note que eu faço [NumLin := NumLin - 7] como resultado disto teremos primeiramente o
valor -7, depois -6, e assim vai até chegar a 0 no primeiro segundo.

☞ Importante - aqui não adianta tentar usar o recurso da ComponentCount pois pode avacalhar na hora da
montagem, então é preferível fazer o lote da montagem dos oito label's na mão mesmo.

Enviando o projeto para um Amigo


Prontinho agora basta apenas você compilar o projeto, vá ao menu nas opções Project | Compile...
(ou pressione CTRL+F9 e prontinho é só mandar o executável gerado para sua(seu) namorada(o), parente,
colega ou amigo(a), acredito que deva caber num único disquete (Atenção: Não precisa mandar o .BMP o
Delphi já se encarrega de guardá-lo no executável).

Realizando uma pequena otimização


Anote antes desses passos qual foi o tamanho em Bytes que ficou o seu executável.

1. Uma coisa que você pode (e deve fazer) é ir em Project | Options... na página Application atribua um
título (Title) e um novo ícone (Icon) ao seu projeto, depois vá na página Compiler e desmarque todas as
opções do Grupo Debugging (elas só servem para quando você estiver testando o aplicativo).

2. No início do programa do seu formulário deixe apenas as seguintes bibliotecas:

unit fCartao;

interface

uses
Windows, Classes, Controls, ExtCtrls, StdCtrls, Forms;

3. Dê uma compilada final escolhendo as opções Project | Build All

Compare agora o tamanho do seu executável final. Mas não se preocupe esses macetes você
aprenderá ao longo do nosso curso. (Atenção: também não precisa mandar o Ícone que você escolheu para seu
projeto o Delphi também se encarrega de colocá-lo no executável).

Finalmente
Na próxima apostila começaremos a desvendar os segredos dos bancos de dados.
2 Curso de Delphi 4.0 - Apostila 2

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• BRASIL.BMP
• NORTE.BMP
• NORDESTE.BMP
• SUL.BMP
• SULDESTE.BMP
• CENTRO.BMP

Prefácio
Salve, após a construção de um Cartão você pode estar pensando o que virá a seguir ? Acertou se
pensou no acesso a Banco de Dados, afinal o maior mistério com o Delphi é como ele trata Bancos de Dados.
Uma das grandes vantagens do Delphi é o seu relacionamento com os diversos bancos de dados atualmente
existentes, e o Delphi é um dos poucos ambientes que consegue fazer essa conexão de forma rápida e prática.

Mas antes de nos enveredarmos no conceito de Banco de Dados vamos criar a nossa capa do
aplicativo, garanto que você achará bastante interessante o que estamos prestes a começar a desenvolver.

Vamos a uma rápida explicação o que é este projeto. Inicialmente será mostrado o mapa do Brasil
para que o usuário possa escolher determinada região, após a escolha de uma região o usuário poderá dentro
desta escolher qual o estado ele deseja ter uma pequena descrição, eu vou alargar um pouco e dar também a
possibilidade de impressão da região escolhida.

Projeto 2 - Mapa Eletrônico (1a. Parte)


Bem, agora vamos começar nosso projeto (note que eu sempre falo a palavra Projeto ao invés de
Sistema, em Orientação a Objetos não existem Sistemas e sim Projetos então acostume-se com isso) agora
que já ficamos familiarizados com o Delphi este projeto será um pouco diferente criarei apenas uma parte
dele caberá a você a conclusão do resto do projeto, Ok ? Então vamos meter a mão na massa:

1. Abra o Delphi, como se isso já não fosse óbvio.

2. Na Component Pallete localize uma página chamada Additional e dentro dessa página de um clique no
objeto Image (acredito que seja o sexto) e dê um clique no Form. (automaticamente o Delphi criou um
quadrado quadriculado que representa o objeto Image1).

3. Olhe na Object Inspector e verifique as propriedades do objeto Image1 criado, e altere as seguintes
propriedades:
3.1. AutoSize: True (Fará com que o tamanho do objeto fique automaticamente do tamanho da
figura selecionada)
3.2. Picture: Clique nos "..." e localize o arquivo BRASIL.BMP enviado (Seleciona determinada
figura)

4. Vá na Object Inspector e localize o objeto Form1 (basta clicar no Combo Box para selecioná-lo), e altere
as seguintes propriedades:

4.1. BorderStyle: bsDialog (Fará com que a janela fique no formato padrão de uma janela de
mensagens)
4.2. Caption: Mapa Eletrônico (Conteúdo da tarja do formulário)
4.3. Name: F_Mapa (Nome interno do formulário)
4.4. Position: poScreenCenter (Fará com que o formulário fique sempre centralizado quando for
executado)

5. Dê uma salvadinha no seu projeto, para tanto, no menu vá em File | Save All...:

5.1. Aonde aparece Unit1.pas (o Delphi está se referindo do nome do formulário) mude para
fMapa.PAS
5.2. Aonde aparece Project1.dpr (o Delphi está se referindo do nome do projeto - que será o nome
do executável final) mude para Mapa.DPR

6. Na Component Pallete localize uma página chamada Standard e dentro dessa página localize o objeto
Label (acredito que seja o terceiro) clique no objeto e dê um clique no Form e altere as seguintes
propriedades:
6.1. Font: Clique nos "..." e faça as seguintes alteções na janela de Fonts:
6.11. Cor: Castanho
6.12. Estilo: Negrito
6.2. Caption: Clique sobre a Região a consultar (Conteúdo que será mostrado)

7. Na Component Pallete localize uma página chamada Additional e dentro dessa página localize o objeto
Image (acredito que seja o sexto) pressione a tecla SHIFT e clique no objeto (deve ter ficado um
quadriculado azul em volta do objeto, como se ficasse marcado) e dê cinco cliques no Form - de preferência
um em cada região, e altere as propriedades Name e Hint de cada um para, respectivamente:

Name - Hint
ImgNorte - Mostra os estados da Região Norte
ImgNordeste - Mostra os estados da Região Nordeste
ImgCentro - Mostra os estados da Região Centro-Oeste
ImgSudeste - Mostra os estados da Região Sudeste
ImgSul - Mostra os estados da Região Sul

☞Importante - A próxima modificação tem a ver com Orientação a Objetos o termo é


POLIMORFISMO, isso significa que vários objetos (mesmo diferentes) possuem propriedades idênticas
entre si, por exemplo a propriedade Caption de um objeto Form possui (basicamente) a mesma função da
propriedade Caption de um objeto Label.

8. Clique no objeto ImgNorte segure a tecla SHIFT e clique em ImgNordeste, ImgCentro, ImgSudeste e
ImgSul (o que eu queria era que todos os cinco objetos ficassem marcados simultaneamente), altere agora a
propriedade ShowHint para True. (Note que na Object Inspector não aparece o nome do objeto) e a
propriedade Cursor para crHandPoint (isso fará com que o cursor em cima da figura seja alterado para uma
mãozinha apontando).

☞ Importante - Isso pode ser usado para alterar diversas propriedades de objetos diferentes, praticaremos
isso posteriormente.
9. Quando terminar clique em qualquer região do formulário para desmarcar os objetos.

10. Para terminar nosso primeiro formulário desse projeto vá para a Component Pallete localize uma página
chamada Additional e dentro dessa página localize o objeto BitBtn (acredito que seja o primeiro) clique no
objeto e dê um clique no Form e altere as seguintes propriedades:
10.1. Kind: bkClose, isso fez com que três importantes propriedades se alterassem:
10.11. Caption: assumiu o valor &Close.
10.12. Glyph: ganhou uma imagem padrão de uma portinha de saída
10.13. Modal Result: apesar de não ter sofrido alteração internamente foi disparado uma
Flag que fará com que quando este botão seja clicado o formulário se encerre automaticamente.
10.2. Caption: &Fechar (apenas para "aportuguesar"o nosso aplicativo).

11. Dê uma comparadinha no desenho para ver como ficou:

Bom, este será o nosso primeiro formulário, de uma série de sete, sua função é simples, ele mostrará
o mapa do Brasil e ao ser clicar em qualquer parte de uma determinada região ele disparará o mapa respectivo
desta.

Codificando o mapa
A codificação é um tanto simples, mas pretendo aqui ensinar também alguns macetes interessantes,
aperte a tecla F12 até que você tenha a janela da Code Editor aberta e localize para mim as seguintes linhas:

ImgSul: TImage;
ImgSudeste: TImage;
private

Inclua a seguinte chamada a um procedimento antes da parte private:

ImgSul: TImage;
ImgSudeste: TImage;
procedure ChamaRegiao(Sender: TObject);
private

Agora localize a linha:

implementation

{$R *.DFM}

end.

E faça as seguintes alterações

implementation

{$R *.DFM}
uses
fNorte, // Chama o mapa da Região Norte
fNordeste, // Chama o mapa da Região Nordeste
fSul, // Chama o mapa da Região Sul
fSudeste, // Chama o mapa da Região Sudeste
fCentro; // Chama o mapa da Região Centro-Oeste

procedure TF_Mapa.ChamaRegiao(Sender: TObject);

// Chama os outros Formulários


procedure CriaForm(aFormClass: TFormClass);
begin
with aFormClass.Create(Application) do
try
ShowModal;
finally
Free;
end;
end;

begin
if (Sender = ImgNorte) then CriaForm(TF_Norte) else
if (Sender = ImgCentro) then CriaForm(TF_Centro) else
if (Sender = ImgNordeste) then CriaForm(TF_Nordeste) else
if (Sender = ImgSul) then CriaForm(TF_Sul) else
if (Sender = ImgSudeste) then CriaForm(TF_Sudeste);
end;

end.

Antes de explicar esse procedimento deixa eu comentar porque criei uma nova declaração USES
(note que na terceira linha da Unit - lá em cima) já tem um comando assim, este comando serve para
identificar minhas unidades externas, antes da palavra chave IMPLEMENTATION assim que o formulário é
gerado tudo é compilado e salvaguardado em áreas de memória prontos para serem utilizados, ou seja, a Unit
Windows (se você reparar ela está lá em cima) e jogada para uma área de memória, mas em compensação a
Unit fNorte (que criaremos posteriormente) não é armazenada. Assim eu estou preservando vários blocos de
memória para serem utilizados apenas quando realmente forem necessários.

Prontinho agora vamos explicar essa procedure linda e maravilhosa que foi montada de propósito
para você entenda algumas artimanhas da linguagem Pascal, antes de fazê-la poderiamos simplesmente em
cada objeto TImage clicarmos no evento OnClick e para cada um colocarmos o seguinte código: (por
exemplo para o objeto da Região Norte)

begin
F_Norte := TF_Norte.Create(Application);
F_Norte.ShowModal;
F_Norte.Free;
end;

Isso funcionaria perfeitamente bem mas como são cinco objetos precisariamos repetir isso cinco
vezes (imagine se fossem uns 20 ou 30), e isso já não é tão bom assim em Pascal. Outra coisa que poderiamos
fazer é, criamos um procedimento particular (lá no Private) para todas os outros procedimentos então ficaria
assim:

private
procedure CriaForm(aFormClass: TFormClass);
public
.
.
.
// Depois do comando uses

procedure TF_Mapa.CriaForm(aFormClass: TFormClass);


begin
with aFormClass.Create(Application) do
try
ShowModal;
finally
Free;
end;
end;

e em cada objeto TImage clicarmos no evento OnClick e para cada um colocarmos o seguinte código: (por
exemplo para o objeto da Região Norte)

begin
CriaForm(TF_Norte);
end;

Isso também funcionaria perfeitamente bem mas como são cinco objetos precisariamos repetir isso
cinco vezes (imagine novamente se fossem uns 20 ou 30), mas agora o pior que e serão vários procedimentos
que teremos que olhar caso dê algum erro e isso já não é tão bom assim em Pascal. Então resolvi fazer da
maneira como eu coloquei.

Criei um único procedimento ChamaRegiao que receberá uma variável do tipo TObject (lembra da
apostila anterior ? É o objeto que chama o procedimento) e para este procedimento coloquei um outro
procedimento interno, chamado CriaForm.

Para ativar todo o conjunto aperte novamente a tecla F12 (para mostrar o formulário) e dê um clique
simples sobre o objeto ImgNorte aperte a tecla F11 (para chamar a Object Inspector), vá para a página de
eventos e para o evento OnClick, selecione atraves do Combo (aquela setinha apontada para baixo) o
procedimento ChamaRegiao. Repita os mesmos passos com as outras imagens das outras regiões.

Este formulário já está pronto, vamos agora ver o que acontece com cada região. (Obs. Não adianta
tentar rodar que ele deve acusar erro que as outras unidades ainda não existem.
Primeira Região
Apenas para guiá-los mostrarei como criar o mapa da Região Sul (só tem três estados e não deve me
dar muito trabalho :)) você deverá criar os formulários para as outras regiões. Observe que é quase tudo igual
ao primeiro formulário criado.

A partir do Menu Principal clique em File | New Form e será disponibilizado um novo formulário,
vamos aos passos:

12. Na Component Pallete localize uma página chamada Additional e dentro dessa página de um clique no
objeto Image (acredito que seja o sexto) e dê um clique no Form. (automaticamente o Delphi criou um
quadrado quadriculado que representa o objeto Image1).

13. Olhe na Object Inspector e verifique as propriedades do objeto Image1 criado, e altere as seguintes
propriedades:

13.1. AutoSize: True (Fará com que o tamanho do objeto fique automaticamente do tamanho da
figura selecionada)
13.2. Picture: Clique nos "..." e localize o arquivo SUL.BMP enviado (Seleciona determinada
figura)

14. Vá na Object Inspector e localize o objeto Form1 (basta clicar no Combo Box para selecioná-lo), e
altere as seguintes propriedades:

14.1. BorderStyle: bsDialog (Fará com que a janela fique no formato padrão de uma janela de
mensagens)
14.2. Caption: Estados da Região Sul (Conteúdo da tarja do formulário)
14.3. Name: F_Sul (Nome interno do formulário)
14.4. Position: poScreenCenter (Fará com que o formulário fique sempre centralizado quando for
executado)

15. Dê uma salvadinha no seu projeto, para tanto, no menu vá em File | Save All...:

15.1. Aonde aparece Unit1.pas (o Delphi está se referindo do nome do formulário) mude para
fSul.PAS

16. Na Component Pallete localize uma página chamada Standard e dentro dessa página localize o objeto
Label (acredito que seja o terceiro) clique no objeto e dê um clique no Form e altere as seguintes
propriedades:
16.1. Font: Clique nos "..." e faça as seguintes alteções na janela de Fonts:
6.11. Cor: Castanho
6.12. Estilo: Negrito
16.2. Caption: Clique sobre o Estado a consultar (Conteúdo que será mostrado)

17. Na Component Pallete localize uma página chamada Additional e dentro dessa página localize o objeto
Image (acredito que seja o sexto) pressione a tecla SHIFT e clique no objeto (deve ter ficado um
quadriculado azul em volta do objeto, como se ficasse marcado) e dê cinco cliques no Form - de preferência
um em cada região, e altere as propriedades Name e Hint de cada um para, respectivamente:

Name - Hint
ImgPR - Descreve o estado do Paraná
ImgSC - Descreve o estado de Santa Catarina
ImgRS - Descreve o estado do Rio Grande do Sul

18. (Praticando o polimorfismo novamente) Clique no objeto ImgPR segure a tecla SHIFT e clique em
ImgSC e ImgRS, altere agora a propriedade ShowHint para True e Cursor para crHandPoint.

19. Quando terminar clique em qualquer região do formulário para desmarcar os objetos.

20. Para terminar nosso primeiro formulário desse projeto vá para a Component Pallete localize uma página
chamada Additional e dentro dessa página localize o objeto BitBtn (acredito que seja o primeiro) clique no
objeto e dê um clique no Form e altere as seguintes propriedades:
20.1. Kind: bkClose, isso fez com que três importantes propriedades se alterassem:
20.2. Caption: &Fechar (apenas para "aportuguesar"o nosso aplicativo).

21. Dê uma comparadinha no desenho para ver como ficou:

Agora cabe a você criar mais quatro formulários, são eles respectivamente:

Nome Interno Nome Externo Figura a usar


F_Norte fNorte NORTE.BMP
F_Nordeste fNordeste NORDESTE.BMP
F_Centro fCentro CENTRO.BMP
F_Sudeste fSudeste SUDESTE.BMP

☞ Importante - Chamei de Nome Interno a propriedade Name dos formulários e Nome Externo como
será o nome que você deve salvar cada formulário. Note que a única diferença entre eles está num simples
apostrofe "_", isso facilita muito quando queremos lembrar o nome que precisamos utilizar.

☞ Importante - Infelizmente com o Delphi não existe outro componente mais poligonal que o tImage, mas
tem uma notícia boa o Delphi respeitará o objeto tImage criado por último, então você pode colocar uns
sobre os outros. Comigo aqui acabei conseguindo montar com uma exatidão fora do normal, até eu me
assustei. Uma Dica: Para a região Centro-Oeste crie primeiro o Objeto do estado de Goiás e dentro dele
coloque o objeto do estado do Distrito Federal.

Tirando os formulários do Auto-Create


O Delphi cria automaticamente todos os formulários que utilizamos, mas isso gera um tanto de
prejuízo as áreas de memória (é óbvio que um projeto com 7 ou até 10 não é um caso sério, mas um projeto
com 50 ou 70 já começa a dar uns erros muito estranhos) então lembra-se do procedimento CriaForm ele vai
exatamente criar os nosso formulários para utilizarmos e depois destruí-los.

Mas precisamos dizer para o Delphi que não queremos que ele faça o serviço de Auto-Create, para
tanto vá (a partir do menu principal) em View | Project Manager, esta janelinha é a que controla todas as
unidades do seu projeto. Clique no botão Options. Selecione a página Forms lá você verá dois objetos
ListBox, do lado esquerdo são os Auto-Create Forms e do lado direito estão os Available forms ou
simplesmente formulários disponíveis.

Então selecione os formulários: F_Norte, F_Nordeste, F_Centro, F_Sudeste e F_Sul e clique no


botão com o sinal > isso fará com que eles sejam despachados para o outro lado. Não faça o procedimento
com o F_Mapa, ele é o nosso Menu e ele precisa realmente ser criado automaticamente assim que o usuário
iniciar o processo.

Prontinho, agora execute o projeto e veja como ele está ficando.

Finalmente
Existem várias maneiras de se mostrar o estado escolhido mas a que eu achei mais interessante
utiliza o QuickReport (que vem com o Delphi) para fazer o serviço. Mas faremos isto apenas na próxima
apostila.
3 Curso de Delphi 4.0 - Apostila 3

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• BASICO.MDB

Prefácio
Salve, na última apostila começamos a montar nosso pequeno mapa eletrônico, agora vamos concluí-
lo.

Antes de recomeçarmos precisamos entender como funciona a conexão entre o Delphi e o Banco de
Dados. Isto é realizado através de um conjunto de bibliotecas que a Inprise chamou de BDE (Borland
DataBase Engine) ela trabalha assim como um ODBC de ligação, mas com a grande vantagem que para
determinados bancos o acesso é totalmente nativo, isso significa que a conversa entre sua Aplicação e o
Banco não recebe interferencias externas a não ser do BDE (mas isso até o antigo Clipper precisava de suas
ligações para seus acessos com os bancos xBase).

Ilustradamente o acesso funciona da seguinte maneira:

A coisa acontece da seguinte forma, a sua aplicação através dos objetos contidos na Component
Pallete (localizado na parte superior direita) e na página chamada Data Access estão todos os objetos que
fazem esta primeira conexão entre o Aplicativo e o BDE e este se comunica com o Banco de Dados.

☞Importante - Note que eu não especifiquei qual o Banco de Dados, então salvaguardando algumas
regras do próprio banco (tais como o nome das tabelas, formas de SQL) poderemos utilizar para nossa
aplicação qualquer banco que acharmos mais fácil de manipularmos (tais como dBase, Access, Paradox...) e
ao final (antes de entregar a aplicação para o usuário) fazermos um último teste com o banco de dados
escolhido por ele (Oracle, SQL Server, Interbase, Sybase...) para isso não precisaremos modificar uma
única linha de código do nosso aplicativo.

☞Importante - A conexão com o MS-Access funciona da seguinte forma: Entre o BDE e o Banco de
Dados existe um aplicativo a mais de conexão, chamado DAO, a sigla significa Data Access Objects, é um
conjunto de bibliotecas para o desenvolvimento com o banco de dados MS-Access, e pertence a Microsoft,
para ter o direito de uso e distribuição do produto você deve adquirir quaisquer das ferramentas de
desenvolvimento da Microsoft.

Iniciando na Prática
Bem se você ainda não fez, aconselho que você dê uma olhada no apêndice identificado por
CONEXAO e faça as alterações sugeridas nele.

Junto com essa apostila você está recebendo um banco de dados (formato MS-Access 97). Para
padronizar vamos criar uma pasta com o nome CursoDelphi e dentro dela criaremos uma nova pasta
chamada Federação coloque dentro desta tudo que você recebeu. Graficamente então temos:

Abra agora o aplicativo BDE Administrator e crie um Alias para o banco de dados enviado. Se
você não sabe como fazer vou dar uma canja siga os passos abaixo:

1. A partir do BDE Administrator aberto vá em Object | New... (ou simplesmente CTRL+N) e modifique a
janelinha que aparece para:

e pressione a tecla OK.

2. Mude o nome do seu novo alias para AlFedera

☞Importante - Apesar de ser permitido não coloque acentos no seu Alias e procure não ultrapassar os oito
caracteres isso além de manter a compatibilidade entre o Delphi 32 Bits e o Delphi 16 Bits também evita uma
série de confusões.

3. Altere a propriedade DATABASE NAME para C:\CursoDelphi\Federação\basico.mdb e confirme as


alterações em Object | Apply (ou simplesmente CTRL+A, ou ainda clique no quarto botão da barra de
ferramentas)

4. Teste seu novo alias clicando em Object | Open (ou simplesmente clique no primeiro botão da barra de
ferramentas) seu alias deve formar um quadradinho luminoso em volta do objeto, conforme a figura a seguir:

5. Feche-o em em Object | Close (ou simplesmente clique novamente no primeiro botão da barra de
ferramentas)

Se você está confuso com tudo isso não fique retorne aquela figura inicial sobre a conexão, pode-se
dizer que estamos exatamente criando o quadradinho do BDE. O Alias é simplesmente uma conexão que se
fará entre seu Aplicativo e o Banco de Dados

Trabalhando com o TDatabase


Antes de começarmos abra novamente o seu projeto, para isso a partir do Menu Principal clique em
File | Open localize o arquivo Mapa.DPR.

No formulário F_Mapa e coloque um objeto DataBase (que se encontra na Component Pallete na


página Data Access) e altere as seguintes propriedades:
AliasName para AlFedera (aquele que foi criado na apostila anterior)
DataBaseName para dnFedera (nome da base de dados)
Name para nmFedera

Este objeto é o que fará a segunda conexão com o nosso banco de dados, para lembrar a vocês:

1a. Conexão: Entre o Banco de Dados e o Alias


2a. Conexão: Entre o Alias e o objeto tDataBase
3a. Conexão: Entre o objeto tDataBase e os objetos DB (tTable, tQuery, tStoreProc)
4a. Conexão: Entre os objetos DB com os objetos que o usuário utilizará (todos os que estão na página
DataControls e alguns outros).

Se você quer simular como será essa segunda conexão, altere a propriedade Connected do objeto
para true e será mostrada a seguinte janela:

Clique no botao Ok e prontinho seu banco estará conectado, mas vamos evitar que essa janelinha
apareça quando o usuário for usar nosso aplicativo, antes volte a propriedade Connected do objeto para false,
na página de eventos de um duplo clique no evento OnLogin e vamos as alterações:

procedure TF_Mapa.nmFederaLogin(Database: TDatabase; LoginParams: TStrings);


begin
LoginParams.Values['USER NAME'] := '';
LoginParams.Values['PASSWORD'] := '';
end;

Agora precisamos simular as alterações de Conexão para tanto, chame o objeto F_Mapa, e dê um
duplo clique no evento OnShow para abrirmos esta conexão:

procedure TF_Mapa.FormShow(Sender: TObject);


begin
nmFedera.Connected := True;
end;

Para fechar a conexão quando terminar nosso sistema. dê um duplo clique no evento OnClose:

procedure TF_Mapa.FormClose(Sender: TObject; var Action: TCloseAction);


begin
nmFedera.Connected := False;
end;

☞Importante - Aqui executaremos mais um termo da Orientação a Objetos (lembram-se do


POLIMORFISMO), o termo é AÇÃO, isso significa que um evento qualquer é disparado quando outro
evento é acionado, ou seja é como um efeito cascata. O que acontece aqui é que quando o usuário executar o
sistema esse disparará o evento OnShow do formulário e este disparará o evento OnLogin do objeto
TDataBase.

Sobre o Quick Report


O Quick Report é o gerador oficial do Delphi, deixa eu abrir aqui um pequeno parenteses, quando
surgiu o Delphi, era uma das melhores ferramentas RAD para se trabalhar com bancos de dados, perfeito até
hoje na construção e desenvolvimento de softwares, mas como todo paraíso tem seu inferno, o Delphi
também tinha o seu, a geração de relatórios, na época do Delphi 1.0 a ferramenta para gerá-los era o Report
Smith, mas era claro que ele não dava conta do recado por diversos motivos, entre eles destacam-se:

- Era preciso carregar um Run-Time do Report Smith juntamente com o projeto


- Os relatórios ficavam separados do executável principal
- Relatórios muito complexos eram uma Via-Crucis fazê-los
- Relatórios muito simples demoravam uma eternidade para rodá-los

Então os Delphianos da época procuravam alternativas, entre elas aqui vale destacar:

- Report Crystal
- Report Builder
- Biblioteca Printers (do próprio Delphi)

Esta última deu origem a vários geradores de relatórios e o principal surgido foi o Quick Report que
se tornou um mero coadjuvante do Delphi 2.0 fazendo parceria com o Report Smith e em pouco tempo
tornou-se óbvio que o Quick era muito superior ao Smith tanto que a partir da versão 3.0 resolveu-se não
mais distribuir o Report Smith tornando o Quick o gerador oficial do Delphi.

Não pretendo dizer aqui que o Quick é o melhor gerador de relatórios que existe para o Delphi,
acredito sempre que a melhor ferramenta é aquela que você domina e conhece, em listas de discussão é
comum você ver coisas como:

- O Quick é ruim
- É difícil de construir algo nele
- Relatórios complicados são impossíveis fazê-los
- entre milhares de outras coisas

Aí, todos colocam milhares de substitutos, mas veja bem, a própria Inprise abriu mão de um gerador
dela (caso do Report Smith) para trocar por um de uma empresa de terceiro (QuSoft AS). Será que isso tudo
foi porque o Quick é ruim ? Acho que muitas vezes quando não conhecemos ou tentamos aprender uma
ferramenta, acabamos não fazendo o essencial que é ver primeiro como a ferramenta trabalha, o Quick é um
gerador de relatórios totalmente orientado a objetos, e isso não é muito fácil de assimilarmos. Então para
ajudá-los sempre tentarei utilizá-lo como uma ferramenta não só para gerar relatórios, mas também para:

- Formulários de Consultas
- Importações em .TXT e .HTML
- Relatórios Analíticos
- Fichas de Caixa, Balancetes e Outros.

Vocês verão que esse terrível monstro horroroso de duzentas cabeças (que cada dia cresce uma) na
verdade não passa de um horroroso monstro terrível de duzentas e uma cabeças. Bem vamos deixar de
ladainha e começar a trabalhar.

Construindo o formulário para uma região genérica


Não pretendo aqui construir um formulário para cada região (teve gente que suspirou de alívio), mas
sim um único que servirá para qualquer região que o nosso usuário clicar. Vamos aos passos:

1. A partir do Menu Principal clique em File | New Form e será disponibilizado um novo formulário e altere
logo a propriedade name para F_Estado.

2. Dê logo uma salvadinha no seu projeto, para tanto, no menu vá em File | Save All...:

2.1. Aonde aparece Unit1.pas (o Delphi está se referindo do nome do formulário) mude para
fEstado.PAS

3. Na Component Pallete ache uma página entitulada QReport nela estão todos os objetos utilizados pelo
Quick, localize o objeto chamado QuickRep, clique nele e em seguida click no formulário.

☞ Importante - Foi criado nesse momento nossa área de trabalho, o Quick 1.0 (distribuído com o Delphi
2.0) não criava esta área branca que vc está vendo, ele se resumia a apenas alargar as proporções do
formulário (propriedade Width e Height) para o tamanho de uma página da impressora.

4. Vamos para a Object Inspector e altere a propriedade Name para QrEstado

☞ Importante - Qualquer gerador de relatório trabalha por seções, pois nossos (e qualquer) relatórios tem
essas seções, são elas: Cabeçalho, Título da Página, Rodapé da Página, Página Inicial, Última Página, Linhas
Detalhes, e assim vai, vamos criar essas seções, o Quick as chama de Bandas.

5. Na Component Pallete na página QReport, localize o objeto chamado QrBand, clique nele e em seguida
click dentro do objeto do QrEstado criado anteriormente.

6. Vamos para a Object Inspector e altere as seguintes propriedades:

6.1. Name para BdCabPagina


6.2. BandType para rbPageHeader - Essa é a propriedade que controla os tipos das seções no caso
escolhemos uma Banda de Cabeçalho de Página, ela aparecerá em todas as páginas.

Dentro do Quick devemos usar os objetos do Quick (isso parece óbvio mas muita gente esquece
disso) o correspondente ao objeto Label do Delphi que mostra um texto fixo no Quick é o QrLabel.

7. Na Component Pallete na página QReport, localize o objeto chamado QrLabel, clique nele e em seguida
click dentro do objeto da objeto BdCabPagina criado anteriormente .

8. Vamos para a Object Inspector e altere as seguintes propriedades:

8.1. Name para lbTitulo


8.2. Alignment para taCenter (alinhamento centralizado)
8.3. AlignToBand para True - Isso fará com o que foi definido na propriedade Alignment seja
estendido para a banda (Então o QrLabel se alinhará centralizado dentro da banda)
8.4. Font: Clique nos "..." e faça as seguintes alteções na janela de Fonts:
8.41. Cor: Azul-Marinho
8.42. Estilo: Negrito
8.43. Tamanho: 16
8.44. Fonte: Times New Roman
8.5. Caption para Estado do Brasil

9. Na Component Pallete na página QReport, localize o objeto chamado QrBand, clique nele e em seguida
click dentro do objeto do QrEstado (não é dentro daquela primeira banda criada).

10. Vamos para a Object Inspector e altere as seguintes propriedades:

10.1. Name para BdDetalhe


10.2. BandType para rbDetail - Essa é a propriedade que controla os tipos das seções no caso
escolhemos uma Banda de Detalhe, ela será replicada a cada registro e dê uma esticadinha para baixo nela,
aumentando o tamanho (ou a propriedade Height)

11. Agora eu vou precisar dentro desta banda de seis (6) objetos QrLabel (é só apertar o objeto enquanto
você segura a tecla SHIFT - O objeto vai ficar com a marcação azul e dê seis click's) dentro do objeto
BdDetalhe, agora altere a propriedade Caption de cada um respectivamente:

Sigla:
Nome:
Capital:
Núm.Município:
Região:
Descrição:

12. Agora marque todos os seis objetos (lembra-se) e aproveitando o Polimorfismo altere a propriedade Font,
clique nos "..." e faça as seguintes alteções na janela de Fonts:
12.1. Cor: Castanho
12.2. Estilo: Negrito
12.3. Fonte: Times New Roman

13. Continue com os objetos marcados e a partir do menu principal vá em View | Alignment Palette será
mostrada a seguinte janela:

Clique então no último botão da primeira linha. Todos eles serão organizados à direita.

☞Importante - Vamos a uma rapidinha sobre os alinhamentos, isso só serve para dois ou mais objetos
marcados:

Primeira Linha: à esquerda, centraliza verticalmente, tamanho vertical, espaçamento vertical e à direita.
Segunda Linha: Superior, centraliza horizontalmente, tamanho horizontal, espaçamento horizontal e inferior

14. Faremos agora a 3a. Conexão. Vamos para a página Data Access e localize o objeto Query. Click nele e
clique dentro do formulário e altere as seguinte propriedades:
14.1. DataBaseName para dnFedera (isto só aparecerá se o formulário F_Mapa estiver aberto)
14.2. SQL, clique nos "..." e faça escreva:
select * from Federacao
14.3. Name para QryEstado

☞ Importante - Se você não conhece SQL (Structure Query Language) aconselho que você compre um
bom livro, ou veja a apostila referente aos comandos básicos.

15. Está é a 4a. Conexão. Voltemos para a página QReport e localize o objeto QrDBText, precisaremos de
seis (6) objetos dentro do objeto BdDetalhe

16. Agora marque todos os seis objetos e aproveitando o Polimorfismo altere as seguintes propriedades:

16.1. Font, clique nos "..." e faça as seguintes alteções na janela de Fonts:
16.11. Cor: Azul
16.13. Fonte: Times New Roman
16.2. DataSet para QryEstado

17. Marque agora cada objeto e altere a propriedade DataField de cada um respectivamente:

SIG_UF
NOM_ESTADO
NOM_CAPITAL
NUM_MUNICIPIO
NOM_REGIAO
DES_REGIAO

18. Uma das principais facilidades do Quick é quanto a campos Memo (como é o caso do campo
DES_REGIAO) altere as seguintes propriedades (do objeto QRDBText6 - marcado com a propriedade
DataField em DES_REGIAO)
18.1. AutoSize para False (cancela o esticamento automatico horizontal)
18.2. AutoStretch para True (permite que o objeto se estique verticalmente)
18.3. WordWrap para True (só para confirmar - permite que o objeto quebre as linhas)

19. Agora estique esse objeto até o final, acredito que a propriedade Width deve ficar em torno de 625

20. Vamos conectar o objeto QrEstado (TQuickRep) com o objeto QryEstado (TQuery), para tanto localize
o objeto QrEstado e altere a propriedade DataSet para QryEstado.

Está pronto, compare como ficou:


☞ Importante - Uma enorme vantagem do Quick é você poder ver como fica seu relatório final mesmo
sem precisar rodar o sistema, para tanto faça o seguinte:

1. No objeto QryEstado altere a propriedade Active para True.


2. Clique no objeto QrEstado e em seguida clique com o botão direito e será mostrado um menu e dentro
dele clique em Preview.
3. Novamente no objeto QryEstado altere a propriedade Active para False.

Codificando a Primeira Região


Apenas para guiá-los mostrarei como criar os códigos do mapa da Região Sul você deverá criar os
códigos para as outras regiões. Observe que novamente é quase tudo igual.

Abra o formulário F_SUL e aperte a tecla F12 até que você tenha a janela da Code Editor aberta e
localize para mim as seguintes linhas:

ImgSC: TImage;
ImgRS: TImage;
private

Inclua a seguinte chamada a um procedimento antes da parte private:

ImgSC: TImage;
ImgRS: TImage;
procedure MostraEstado(Sender: TObject);
private

Agora localize a linha:

implementation

{$R *.DFM}
end.

E faça as seguintes alterações:

implementation

{$R *.DFM}
uses
fEstado; // Mostra o Estado

procedure TF_Sul.MostraEstado(Sender: TObject);

procedure Mostra(Estado: String);


begin
F_Estado := TF_Estado.Create(Application);
with F_Estado do begin
with QryEstado do begin
SQL.Clear;
SQL.Add('SELECT * FROM FEDERACAO WHERE (SIG_UF = ''' + Estado + ''')'); // Atenção é
tudo aspas simples
Open;
end;
QrEstado.Preview;
QryEstado.Close;
Free;
end;
end;

begin
if (Sender = ImgPR) then Mostra('PR') else
if (Sender = ImgSC) then Mostra('SC') else
if (Sender = ImgRS) then Mostra('RS');
end;

end.

Prontinho veja que o procedimento que eu construí aqui é igualzinho ao do F_Mapa, óbvio salvo
alguns comandos.

Criei um único procedimento MostraEstado que receberá uma variável do tipo TObject e para este
procedimento coloquei um outro procedimento interno, chamado Mostra que realizará os seguintes passos:

1. Criação do Formulário F_Estado;


2. Organização do SQL para o estado selecionado criando a Query;
3. Mostra na tela do relatório (note que não preciso do comando SHOWMODAL do formulário, e sim
PREVIEW do objeto QuickRep);
4. Fecha a Query; e
5. Eliminação do F_Estado da memória.

Para ativar todo o conjunto aperte novamente a tecla F12 (para mostrar o formulário) e dê um clique
simples sobre o objeto ImgPR aperte a tecla F11 (para chamar a Object Inspector), vá para a página de
eventos e para o evento OnClick, selecione atraves do Combo (aquela setinha apontada para baixo) o
procedimento MostraEstado. Repita os mesmos passos com as outras imagens dos outros estados.

☞Importante - No comando SQL.Add('SELECT * FROM FEDERACAO WHERE (SIG_UF = ''' +


Estado + ''')'); esses três plicks ( ''' ) é tudo simples, nenhum é aspas duplas ( " ). Pois dentro de uma string
cada dois plicks simples ( '' ) conseguimos um plicks ( ' ), confuso né, mas veja só, se fizermos:

VariavelString := 'Nome : Nando';

A VariavelString terá em seu conteúdo o valor Nome : Nando, agora se fizermos:

VariavelString := 'Nome : ''Nando''';

A VariavelString terá em seu conteúdo o valor Nome : 'Nando'. Eu apenas acrescentei mais dois
plicks simples entre a palavra Nando.

Tirando o formulário F_Estado do Auto-Create


Vá (a partir do menu principal) em View | Project Manager. Clique no botão Options. Selecione a
página Forms lá você verá dois objetos ListBox, do lado esquerdo são os Auto-Create Forms e do lado
direito estão os Available forms ou simplesmente formulários disponíveis.

Então selecione os formulários: F_Estado e clique no botão com o sinal > e despache-o para o lado
aonde estão os outros isolando novamente o nosso Menu pois lembrando que ele precisa ser criado
automaticamente assim que o usuário iniciar o processo.

Prontinho, agora execute o projeto e bom divertimento com seu mapa eletrônico. Na próxima
aprenderemos como distribuí-lo e gerar alguns macetes para otimização.

Finalmente
Agora precisamos arrumar, empacotar e distribuir nosso projeto, mas isto só será feito na próxima
apostila.
4 Curso de Delphi 4.0 - Apostila 4

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• GEOGRAPH.ICO
• SETUP1.BMP
• SETUP2.BMP
• SETUP3.BMP
• SPLASH.BMP
• LOGO.BMP

Prefácio
Salve, na última apostila montamos nosso segundo aplicativo o Mapa Eletrônico, o interessante é
com ele é que calmamente começamos a desvendar os segredos do trabalho com o Delphi associado a Bancos
de Dados, repararam como a maior parte dos livros evita em falar sobre o assunto ? O máximo com um
aplicativo que arranha a superfície deste fantástico mundo. O problema é que o assunto é muito mais do que
se pode imaginar, pois o Delphi tem milhares de possibilidades para realizar esta tarefa.

O maior problema com o Delphi (depois de entendê-lo) é como distribuir seus aplicativos gerados,
quando ele é independente de tratamento de banco de dados, tudo bem é só mandar o executável (.EXE) mas
o problema começa quando ele utiliza o BDE, aí a coisa complica um pouco, mas acredito que após essa parte
você começará a dominar uma importante ferramenta de distribuição para seus aplicativos.

Preparando o sistema para o Empacotamento


Antes de gerarmos nossos discos de instalação vamos fazer algumas alterações no projeto então abra
novamente o seu projeto, para isso a partir do Menu Principal clique em File | Open localize o arquivo
Mapa.DPR.

Agora, a partir do Menu Principal, clique em Project | Options e vamos realizar dois serviços aqui:

1. Na página Application coloque o Título do nosso projeto (Mapa Eletrônico) e localize o


ícone enviado (Geograph.ico).

2. Na página Compiler desmarque todas as opções dos grupos Debugging e Messages e


clique no botão OK.

Novamente a partir do Menu Principal, clique em Project | Build All para gerarmos o executável
final, prontinho agora feche o Delphi confirmando as modificações realizadas no projeto.
Utilizando o Install Shield
No Delphi 1.0 para distribuir o BDE era uma complicação, existia um diretório no CD do Delphi
chamado REDIST, nele estava (dividido para caber em disquetes de 1.44 Mb) o BDE. Ou seja, você se
deslocava até a máquina do seu Cliente (que iria instalar o sistema) criava um diretório, colocava o
executável, as tabelas, e instalava o BDE, depois criava o alias, testava e pronto estava instalado. Com um
certo tempo as pessoas aprenderam a gerar o Alias automático. Mas ainda assim era um tanto primitivo,
principalmente quando você precisava mandar tudo para que o próprio cliente instalasse.

Com o Delphi 2.0 surgiu o InstallShield que foi mais aprimorado ainda nessa versão, ele é um
produto da Stirling Technologies. Que acompanha também o Delphi 3.0 e o Delphi 4.0. Um aviso, não tente
utilizar o InstallShield que vem com o Delphi 2.0 para aplicações do Delphi 3.0 ou 4.0, nem vice-versa,
apesar de todos serem de 32 Bits são de versões totalmente diferentes.

O InstallShield não é que nem o Quick Report, você precisa instalá-lo em separado (ele vem no
próprio CD do Delphi), após sua instalação e execução, você acabará com a seguinte janela:

Esta é a tela inicial para a criação do seu projeto .IWZ, informe o nome do projeto, o tipo (no caso de
versões registradas) e o diretório que será criado, após isso aperte o botão Create e iremos para a janela de
construção do projeto:
Esta tela foi dividida em nove grandes grupos, para explicar melhor vamos analizar grupo a grupo
enquanto fazemos as alterações para a geração do nosso pacote.

1. Set the Visual Design


Neste grupo estão as informações iniciais do instalador:

Na primeira parte (Application Information) você deve informar o nome da aplicação (mapa),
localizar o executável que deverá ser instalado (C:\...\Mapa.EXE), a versão (1.0) e o nome da sua empresa
(Curso). Note que nesta parte é montado o Diretório que será instalado o sistema final
(<ProgramFilesDir>\Curso\Mapa).

Na segunda parte (Main Window) é a tela principal da instalação, aqui você escolherá o título
principal (Mapa Eletrônico), o Logotipo da sua Empresa (localize o BitMap Enviado: Logo.BMP), a posição
em que o logotipo ficará (Top Right - Em cima a direita) e a cor de fundo (Dithered Blue - degradê em azul).

Na terceira parte (Features) preste muita atenção que este é o momento mais difícil, aqui você
escolherá se o usuário pode ou não desinstalar automaticamente o projeto. Prontinho pode dar OK.

☞Importante - Assim como o Logo.BMP você notará que no decorrer dessa montagem colocaremos
vários Bitmap's, você mesmo poderá gerá-los mas lembre-se que o InstallShield aceita apenas imagens com
no máximo 16 cores.

2. Select InstallShield Objects for Delphi


Esta é o grupo que mais confunde as pessoas, mas com um pouquinho de atenção a gente chega lá,
aqui você definirá qual tipo de BDE será instalado, o tipo do SQL Links ou se deseja carregar qualquer dos
pacotes de objetos do Delphi.

Na primeira parte (General) são as informações principais, marque o BDE, (Observação: O SQL
Links, serve apenas para conexão com bancos do tipo MS-SQL, SyBase padrão DB-Lib, InterBase,
Oracle, Informix, DB2 e SyBase padrão CT-Lib e os pacotes de objetos servem apenas para o caso de
compilações parciais), clique no botão Settings...

BDE Instalation Type - Aqui você define seu tipo de banco de dados, infelizmente o
Install não possui permissão para a distribuição da DAO 3.5, que é a responsável pela conexão nativa com o
MS-Access, ista permissão é adquirida apenas com a compra de qualquer ferramenta de desenvolvimento
Microsoft, teremos então que colocar na mão todos os arquivos necessários, marque Partial BDE
Installation e clique no botão Avançar.

BDE Driver Types - não escolha nenhum, deixe todos desmarcados.

Query Engine Types - Marque a opção SQL Engine isto fará com que o BDE reconheça e
envie para o gerenciados de banco de dados os comandos de SQL e clique no botão Avançar.

BDE Alias - Step 1 of 4 - Clique no botão New e informe o nome do nosso Alias
(AlFedera)

BDE Alias - Step 2 of 4 - Esta e a tela mais enigmática do Install, nela você deve informar
se quer que seu BDE seja configurado para aplicações Win16/Win32 ou somente Win32, mas aqui ele não se
refere a possibilidade de instalação para Windows 3.x ele apenas está se referindo ao .CFG salvo (que é o
arquivo de configuração do BDE 32, então deixe desmarcado e sigamos em frente.

BDE Alias - Step 3 of 4 - Aqui está todo o pulo do gato sobre a construção do BDE, em
Alias Name ele mostrará o Nome do seu alias, em Path é o local que seu banco deverá ser instalado, agora
vamos pensar um pouquinho, mas se o usuário mudar o destino ? Aqui usaremos uma variável do Install,
coloque: [Program Files]\ que será o diretório em que ficará sua aplicação. No Type selecione MSAccess. E
finalmente escreva na lista de parâmetros opcionais para o Alias o seguinte:

DATABASE NAME=[Program Files]\Basico.mdb

BDE Alias - Step 4of 4 - Aqui você precisa apenas clicar no botão Concluir para finalizar
todas as inclusões no BDE.

Na segunda parte (Advanced) você verá todas as bibliotecas que serão instaladas, apenas clique no
botão OK e vamos em frente.

3. Specify Components and Files


Neste grupo você dirá o que o Install realmente levará no pacote:

Na primeira parte (Group and Files) faça as seguintes inclusões:

Na pasta Program Files aperte o botão Insert Files, localize e arraste o arquivo
BASICO.MDB (clicando com o mouse sobre ele, segurando e levando) para dentro desta pasta.

Na pasta BDE/IDAPI Files localize e arraste o arquivo IDDA3532.DLL, pode fechar o


Windows Explorer.

Vamos agora criar algumas pastas necessárias para a instalação do DAO, clique no botão
Add Group e coloque as seguintes informações:

Group Name: DAOSystem


Destination Directory: <WINSYSDIR>
Com o auxílio do botão Insert Files arraste os seguintes arquivos para esta pasta:
C:\Windows\System\MSJTER35.DLL C:\Windows\System\MSJINT35.DLL
C:\Windows\System\MSVCRT40.DLL C:\Windows\System\MSJET35.DLL
C:\Windows\System\VBAJET32.DLL C:\Windows\System\VBAR332.DLL
C:\Windows\System\OLEAUT32.DLL C:\Windows\System\STDOLE2.TLB
C:\Windows\System\ODBCJT32.DLL C:\Windows\System\ODBCJI32.DLL
C:\Windows\System\ODBCTL32.DLL C:\Windows\System\MSJT3032.DLL
C:\Windows\System\MSJINT32.DLL C:\Windows\System\VEN2232.OLB
C:\Windows\System\MSVCRT20.DLL C:\Windows\System\MSWNG300.DLL
C:\Windows\System\MSRD2X32.DLL C:\Windows\System\VBDB32.DLL
C:\Windows\System\MFC40.DLL C:\Windows\System\ODBC32.DLL
C:\Windows\System\ODBCINT.DLL C:\Windows\System\MSRD2X35.DLL
C:\Windows\System\MSREPL35.DLL

Group Name: DAO


Destination Directory: <CommonFilesDir>\Microsoft Shared\DAO
Com o auxílio do botão Launch Explorer arraste os seguintes arquivos para esta pasta:
C:\Arquivos de Programas\Arquivos comuns\Microsoft Shared\DAO\DAO350.DLL
C:\Arquivos de Programas\Arquivos comuns\Microsoft Shared\DAO\DAO2535.TLB
C:\Arquivos de Programas\Arquivos comuns\Microsoft Shared\DAO\DAO2532.TLB
C:\Arquivos de Programas\Arquivos comuns\Microsoft Shared\DAO\DAO3032.DLL

Group Name: VBFiles


Destination Directory: <WINSYSDIR>
Com o auxílio do botão Launch Explorer arraste os seguintes arquivos para esta pasta:
C:\Windows\System\OLEPRO32.DLL
C:\Windows\System\CTL3D32.DLL
C:\Windows\System\VBAR2232.DLL

As próximas partes (Components e Setup Types) são utilizadas quando você estiver trabalhando
com uma aplicação muito grande aonde existe a divisão em várias partes, você poderá dar também a chance
do seu cliente instalar apenas determinadas partes que o interesse.

4. Select User Interface Components


Este grupo é o que comandará a instalação propriamente dita, gerando a interface com o nosso
cliente. Vamos tratá-lo com calma e parte a parte:

Welcome Bitmap - Este é um bitmap de abertura, é a primeira janela que será mostrada
após iniciado o programa de instalação. Marque a opções e clique na página Settings e localize o arquivo
Splash.bmp enviado. Para o nosso caso deixe a opção marcada.

Welcome Message - Esta é uma janela de boas-vindas com uma mensagem para o nosso
cliente sobre o sistema, infelizmente ela é totalmente em inglês, só pode ser modificada na versão registrada
do produto. Para o nosso caso desmarque a opção.

Software Licence Agreement - Aqui esta a famosa janela da Licença de uso, ou se você
prefere das regras de uso para o nosso aplicativo, você pode modificar o conteúdo criando um arquivo texto
(formato .TXT) e o localizando através da página Settings, mas não poderá modificar as instruções em Inglês
(apenas na versão registrada). Para o nosso caso desmarque a opção.

Readme Information - Aqui será mostrado o arquivo LeiaMe inicial, novamente você pode
modificar o conteúdo criando um arquivo texto (formato .TXT) e o localizando através da página Settings,
mas não poderá modificar as instruções em Inglês (Apesar de que ela se reduz a um simples Information) se
você quiser crie-o ou então desmarque a opção.
User Information - Aqui são informações do nosso cliente: seu nome, nome da empresa e o
número de registro do nosso software. Para o nosso caso deixe a opção desmarcada.

Choose Destination Location - Aqui é aonde nosso cliente poderá escolher qual o drive e a
pasta que o sistema será instalado. (para o nosso caso ela será colocada em C:\Arquivo de
Programas\Curso\Mapa). Como acertamos no BDE podemos deixá-la marcada para que o nosso cliente
decida.

Setup Type - Em casos de sistemas muito grandes é aqui que o cliente decidirá qual o modo
que ele quer que seja instalado o sistema. Tudo, Compacto ou Customizado. Para o nosso caso deixe a opção
desmarcada.

Custom Setup - Esta é uma subdivisão da parte anterior aonde o cliente escolherá (a partir
da opção Customizado da janela anterior, qual a parte que ele quer que seja instalada. Para o nosso caso
deixe a opção desmarcada.

Select Program Folder - Aqui aparecerá uma janela que permitirá alterar o nome do grupo
que será criado no Windows para colocar nossos ícones do projeto. Para o nosso caso deixe a opção marcada.

Start Copying Files - É aqui que o cliente vê todas as opções que ele escolheu
anteriormente, podendo voltar atrás e modificar algo antes da instalação propriamente dita. Para o nosso caso
deixe a opção marcada.

Progress Indicator - Uma barra que acompanhará o processo de instalação mostrando ao


cliente o quanto falta (em percentual) para a conclusão da instalação. Para o nosso caso deixe a opção
marcada.

Billboards - São cartazes que fazem a propaganda do nosso software ou de outros que
produzimos, aqui é possível colocar um para cada mídia instalada, basta apenas nomeá-los em
SETUP1.BMP, SETUP2.BMP e assim sucessivamente dependendo do número de discos que produzimos.
Vá para a página Settings e localize o diretório dos bitmaps enviados (SETUP1.BMP, SETUP2.BMP e
SETUP3.BMP). Para o nosso caso deixe a opção marcada.

Online Registration - Muitas empresas processam o registros dos softwares de forma


automática, bastando para isso que o cliente possua um Modem, para tanto na página Settings identifique o
número identificador do sistema e o número do telefone ou então desmarque a opção.

Setup Complete - Este é o último passo do processo, aqui você pode escolher se o cliente
deve dar um Reboot na máquina (que é aconselhável), ou mostrar um arquivo Leiame final, bastando para
isso alterar na página Settings, mas de qualquer forma deixe esta opção marcada.

Clique no botão OK para finalizar

5. Make Registry Changes


Esta página deve ser tratada com o carinho e o respeito que ela merece, pois aqui faremos as
modificações na área de register do Windows, então calma e muito sangue frio aqui. Não queremos
corromper essa área de registro do nosso cliente.

Como modificamos a versão do DAO em nosso BDEAdmin para 3.5 também precisamos repetir
essa operação na máquina que será instalado o nosso sistema.

Na página Registry - Keys abra a chave HKEY_LOCAL_MACHINE e clique no botão Add


Key... crie a chave SOFTWARE, clique nesta nova chave e vá repetindo a operação criando a seguinte
estrutura:
HKEY_LOCAL_MACHINE\SOFTWARE\Borland\DataBase Engine\Settings\DRIVERS\MSACCESS\INIT

Deixe marcada a última chave INIT e clique na página Registry - Values e clique no botão Add
Values e proceda as seguintes alterações:

Pronto, clique no botão OK.

Agora crie a seguinte Chave na página Registry - Keys:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\DAO

Crie o seguinte Valor para esta chave na página Registry - Values:

Value Type: String


Value Name: Path
Value Data: <CommonFilesDir>\Microsoft Shared\DAO\Dao3032.dll

Crie a seguinte Chave na página Registry - Keys:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\DAO35

Crie o seguinte Valor para esta chave na página Registry - Values:

Value Type: String


Value Name: Path
Value Data: <CommonFilesDir>\Microsoft Shared\DAO\DAO350.DLL
6. Specify Folders and Icons
Aqui será mostrado os Ícones (dos Arquivos) que serão instalados dentro do grupo escolhido, este
grupo divide-se em:

General - Aonde é possível adicionar novos ícones, lembre-se que antes eles devem ter sido
colocados pelo grupo Specify Components and Files, tais como:

Arquivos TXT - Readme iniciais, para o registro do aplicativo, entre outros.


Arquivos HLP - Contendo um arquivo de auxílio para a aplicação.

Advanced Settings - Aqui podemos modificar o destino dos nossos arquivos, o ícone, criamos uma
tecla de atalho rápido para sua execução ou até mesmo iniciá-lo quando o Windows for iniciado.

☞Importante - Para o aplicativo iniciar assim que o Windows iniciar na página Advanced, existe uma
caixinha para marcar que está escrito: Place Icon and Start Programs Menu.

7. Run Disk Builder


Pronto, tudo foi informado e agora é o grande momento a geração do nosso pacote, escolha a midia
que será gerado e clique no botão Build, espere o término do processo e veja em quantas mídias foram
geradas o seu pacote.

☞Importante - Não se assuste com o número de disquetes (1.44Mb) normalmente apenas o BDE ocupa
2,5 disquetes então é comum sistemas darem de 3 ou superior. Contando que o DAO normalmente ocupa 3
Disquetes ou mais, calcule que seu sistema caberá em simples 7 disquetes.

☞Importante - Se você instalar o sistema a partir da rede escolha a opção CD-Rom pois aí será uma única
mídia.

8. Test the Installation


Aqui você pode testar como ficou seu pacote, acompanhando eventuais erros, mas o melhor mesmo é
você colocá-lo em disquetes e levá-lo para uma máquina que não tenha o Delphi instalado.

☞ Importante - Gere seu pacote em disquetes de 1.44Mb e copie para os disquetes para proceder a
instalação assim você poderá acompanhar a mudança das telas a cada disquete solicitado.

☞ Importante - Não se esqueça que depois, para removê-lo, você precisa ir em Painel de Controle |
Adicionar ou Remover Programas para que o Install proceda a retirada das entradas nas áreas de registro do
Windows.

9. Create Distribution Media


Neste último grupo você poderá copiar totalmente, ou parcialmente, o seu pacote na mídia
selecionada.

Finalmente
Agora você já pode mandar todo o seu projeto para aquele cliente especial, basta apenas embalá-lo e
despachar com as famosas instruções:

Como Instalar
O Mapa Eletrônico só pode ser consultado depois de instalado no seu Microcomputador, sob o ambiente
Windows 95 ou superior. Para realizar a instalação siga essas instruções:

1. Ligue o Microcomputador ativando o Windows


2. Introduza o disquete marcado como INICIAL na unidade de leitura
3. Clique no botão INICIAR e escolha a opção EXECUTAR
4. Digite então A:\SETUP (ou no lugar do A, a letra equivalente ao drive da sua unidade de leitura do
disquete).
5. Click sobre o botão OK e execute as instruções do Instalador.

Acredito que seu usuário não errará esses 5 passos. Um abraço e até a próxima.
5 Curso de Delphi 4.0 - Apostila 5

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• SQL.WRI

Prefácio
O nosso projeto para essa apostila será um tanto bobinho, mas é uma imensa mão na roda para
testarmos nossos aplicativos futuramente, noto que a maioria das pessoas quando começam a programar em
Delphi, temem o maior de todos os pesadelos: o SQL (Structured Query Language), são apenas três
letrinhas mas que confundem e complicam a vida da maioria dos programadores, um conselho dominando
essa simples (porém complexa) linguagem, garanto que será a diferença entre um sistema que apresentará
facilidades imensas e dará poderes extraordinários para o nosso usuário, basicamente a linguagem SQL
contém 4 comandos:

- SELECT
- INSERT
- UPDATE
- DELETE

Na apostila em anexo, enviada junto com esta, explica-se exatamente a função de cada comando,
aqui vamos nos ater ao Delphi, então vamos começar mais um projeto

Projeto 3 - Construtor de SQL


Bem, agora que estamos familiarizados com o ambiente SQL (espero que você tenha lido a apostila
em anexo antes de começarmos), vamos para as nossas receitas de bolo, siga um passo atrás do outro, mas
antes de começar crie uma pasta que abrigará seu projeto, por exemplo Gera SQL.

1. Na Component Pallete localize uma página chamada Standard e dentro dessa página de um clique no
objeto ListBox (acredito que seja o nono) e dê um clique no Form. Olhe na Object Inspector e altere a
propriedade Name para ListaAlias.

2. Pegue outro objeto ListBox e dê um clique no Form e altere a propriedade Name para ListaTabela e altere
a propriedade sorted para True isto fará a ordenação alfabetica dos nomes da lista.

3. Vá na Object Inspector e localize o objeto Form1 (basta clicar no Combo Box para selecioná-lo), e altere
as seguintes propriedades:

3.1. BorderStyle: bsDialog (Fará com que a janela fique no formato padrão de uma janela de
mensagens)
3.2. Caption: Executa instruções SQL (Conteúdo da tarja do formulário)
3.3. Name: F_SQL (Nome interno do formulário)
3.4. Position: poScreenCenter (Fará com que o formulário fique sempre centralizado quando for
executado)

4. Dê uma salvadinha no seu projeto, para tanto, no menu vá em File | Save All...:

4.1. Aonde aparece Unit1.pas (o Delphi está se referindo do nome do formulário) mude para
fSQL.PAS
4.2. Aonde aparece Project1.dpr (o Delphi está se referindo do nome do projeto - que será o nome
do executável final) mude para GerSQL.DPR

5. Na Component Pallete novamente na página Standard e localize agora o objeto Memo (acredito que seja
o quinto) e através da Object Inspector altere as seguintes propriedades:

5.1. Lines: Clique nos ... e elimine todo o seu conteúdo

6. Precisamos agora de três objetos Label's, para tanto pressione a tecla SHIFT e clique no objeto Label
(deve ter ficado um quadriculado azul em volta do objeto, como se ficasse marcado) e dê três cliques no
Form, coloque-os acima dos três objetos criados anteriormente. (automaticamente o Delphi criou oito objetos
chamados respectivamente Label1, Label2 e Label3)

7. Quando terminar clique dentro da Component Pallete na setinha para poder desmarcar o objeto Label.

8. Altere as seguintes propriedades para esses três objetos:

8.1. Font: Clique nos "..." e faça as seguintes alterações na janela de Fonts:
3.41. Cor: Castanho
3.42. Estilo: Negrito
8.2. Caption: Altere para cada um respectivamente:
Selecione o Alias:
Tabelas Disponíveis:
Digite a clausula SQL

9. Na Component Pallete vá para a página Addicional e localize agora o objeto SpeedButton (acredito que
seja o segundo) e traga dois para o form e através da Object Inspector altere as seguintes propriedades:

9.1. Glyph: Altere para cada um respectivamente:


CHECK.BMP
CLEAR.BMP
9.2. Flat: True (faz com que o botão fique liso no form)
9.3. Hint: Altere para cada um respectivamente:
Executa a instrução SQL
Limpa a instrução SQL
9.4. ShowHint: True
9.5. Name: Altere para cada um respectivamente:
ButExecuta
ButLimpa

10. Na Component Pallete vá para a página Data Access e localize agora o objeto Query (acredito que seja
o terceiro)

11. Na mesma página Data Access e localize agora o objeto DataSource (acredito que seja o primeiro) e
através da Object Inspector altere a propriedade:

11.1. DataSet: Query1 (faz a ligação com um objeto Query ou Table)


12. Para finalizar na Component Pallete vá para a página Data Controls e localize agora o objeto DbGrid
(acredito que seja o primeiro) e através da Object Inspector altere a propriedade:

12.1. DataSource: DataSource1 (faz a ligação com um objeto DataSource)

13. Terminamos, compare como ficou:

Codificando
Tudo pronto, basta apenas meter a mão no programa, mas vamos devagar, a idéia deste projeto
apesar de simples pode parecer um pouco complicada, inicialmente será mostrado todos os alias que existem
no BDE Administrator após a escolha de qualquer um deles, serão mostradas as tabelas disponíveis, agora
basta apenas digitar as instruções SQL no objeto MEMO1 e pressionar o botão para executá-lo.

14. Localize na Object Inspector o objeto F_SQL, mude para a página de eventos (Events) e localize o
evento OnShow, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a
chamada ao evento e o transferirá para a Code Editor, insira o seguinte código:

procedure TF_SQL.FormShow(Sender: TObject);


begin
Session.GetAliasNames(ListaAlias.Items);
Query1.DataBaseName := ListaAlias.Items[0];
end;

Este procedimento se encarregará de carregar o nosso objeto ListBox com a lista do nome de todos
os Alias existentes e transferir o primeiro nome carregado para a propriedade Databasename do objeto
Query1.

15. Localize na Object Inspector o objeto ListaAlias e na página de eventos (Events) localize o evento
OnClick, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a chamada ao
evento e o transferirá para a Code Editor, insira o seguinte código:
procedure TF_SQL.ListaAliasClick(Sender: TObject);
var
i : integer;
begin
if (ListaAlias.SelCount = 0) then begin
MessageDlg('Selecione primeiro algum Alias',mtError,[mbOk],0);
exit;
end;
// Mostra os itens da lista não resolvida
Screen.Cursor := crHourGlass;
for i := 0 to (ListaAlias.Items.Count - 1) do
if ListaAlias.Selected[i] then begin
with Query1 do if Active then Close;
Query1.DataBaseName := ListaAlias.Items[i];
Session.GetTableNames(ListaAlias.Items[i],'', true, false, ListaTabela.Items);
break;
end;
Screen.Cursor := crDefault;
end;

Não se preocupe em não entender nada aqui, muito desses comandos sequer foram falados, então
vamos por partes, o evento é disparado assim que qualquer dos Alias da nossa lista for selecionado:

1. Verificação (de rotina) se realmente algum alias foi selecionado da lista


2. Modifica o cursor para o formato de uma ampulheta
3. Do primeiro ao último da lista (aonde o primeiro é 0 e o último é o número de elementos - 1)
3.1. Verifica se é este o alias selecionado e se for
3.1.1. Verifica se a query1 está aberta se estiver fecha ela
3.1.2. Transfere o nome do alias para a propriedade Databasename da Query1
3.1.3. Carrega a lista dos nomes das tabelas do alias selecionado
3.1.4. Interrompe o laço
4. Modifica novamente o cursor para o formato padrão

☞Importante - Existem dois comandos que cancelam laços de repetições (Comandos For, While e
Repeat) são eles:

Break - Interrompe o laço mandando o comando para o próximo comando após o laço.
Exit - Interrompe o laço terminando o procedimento ou função.

O comando Break só pode ser usado dentro de um laço de repetição enquanto que o comando Exit
pode ser usado dentro de procedimentos ou funções livres de um laço de repetição.

16. Localize na Object Inspector o objeto ButExecuta e na página de eventos (Events) localize o evento
OnClick, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a chamada ao
evento e o transferirá para a Code Editor, insira o seguinte código:

procedure TF_SQL.ButExecutaClick(Sender: TObject);


begin
with Query1 do begin
if Active then Close;
SQL.Clear;
SQL := Memo1.Lines;
try
ExecSQL;
try
Open;
except
end;
MessageDlg('Instrução Executada...', mtInformation, [mbOk], 0);
except
MessageDlg('Comando SQL está inválido', mtError, [mbOk], 0);
end;
end;
end;

Aqui até que poderia ser tudo simples, mas para possibilitar que o usuário possa fazer uso dos
comandos INSERT, UPDATE e DELETE tive que usar de uns macetes que acabaram se tornando
interessantes, meu problema estava no seguinte, esses três comandos indicados anteriormente diferentemente
do comando SELECT não geram o que chamamos em SQL de uma cadeia de códigos, ou seja, eles não me
dão uma resposta em uma lista, então não posso utilizar-me do comando OPEN para eles, ao invés disso
preciso usar o comando EXECSQL que apenas dispara esses comandos para o banco de dados, não gerando
nenhuma espécie de retorno e para sorte o EXECSQL suporta o comando SELECT.

Além desse problema o usuário poderia digitar um comando errado, algo como: Maria tinha um
carneirinho... o que me daria um erro que travaria totalmente meu aplicativo (causando uma falha do
programa).

Para sanar ambos os problemas construí um bloco de proteção try...except...end; esses comandos
protegem os códigos que estão entre o try...except e caso acontece erro em algum deles (por exemplo um
comando assim: Variavel_Inteira := 10/0; ou Variavel_Inteira := 'Maria tinha um carneirinho...')
transferindo automaticamente para a instrução entre o except...end;

Vamos dar uma olhada então como ficou a lógica do procedimento:

1. Verifica se a query1 está aberta se estiver fecha ela


2. Limpa o parâmetro lines da Query1
3. Transfere o conteúdo das linhas do Memo1 para dentro do SQL da Query1
4. Abre um bloco de proteção
4.1. Executa o comando SQL
4.2. Ativa um novo bloco de proteção
4.2.1. Abre a Query1
4.2.2. Em caso de erro no bloco de proteção apenas segura e não faz nada
4.3. Mostra uma mensagem dizendo que está tudo bem
5. Em caso de erro no bloco de proteção coloca uma mensagem de alerta

Observação Interessante: Existe também o bloco de proteção try...finally...end; que protege os comandos, e
acontecendo ou não o erro executa obrigatoriamente os comandos localizados entre o finally...end;

17. Localize na Object Inspector o objeto ButLimpa, na página de eventos (Events) localize o evento
OnClick, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a chamada ao
evento e o transferirá para a Code Editor, insira o seguinte código:

procedure TF_SQL.ButLimpaClick(Sender: TObject);


begin
Memo1.Lines.Clear;
end;

Agora ficou fácil, a única função deste botão é limpar o conteúdo do objeto Memo1.
18. Localize na Object Inspector o objeto F_SQL, na página de eventos (Events) localize o evento
OnClose, dê um duplo clique na área em branco. Automaticamente o Delphi criará para você a chamada ao
evento e o transferirá para a Code Editor, insira o seguinte código:

procedure TF_SQL.FormClose(Sender: TObject; var Action: TCloseAction);


begin
with Query1 do if Active then Close;
end;

Aqui também é simples, quando terminar o aplicativo verifica se o objeto Query1 ficou aberto, e em
caso afirmativo fecha ele.

Finalmente
Prontinho você já pode executar seu aplicativo, mas ainda aqui vale uma pequena observação,
escreva um código esquisito para o objeto Memo1 (por exemplo digite: Maria tinha um carneirinho... e
clique no botão para executar o SQL note que automaticamente o Delphi interrompe a execução do programa
e assume o controle, basta apenas você disparar F9 para continuar, não se preocupe isso acontece apenas em
modo Run-Time se você executar o aplicativo fora do Delphi você não passará mais por isso e verá que seu
aplicativo consegue controlar o erro eficazmente.

☞ Importante - Você pode desativar isto, para tanto a partir do Menu Principal vá em Tools |
Environment Options... e na página Preferences no bloco Debugging desative a opção Break on
Exception.
6 Curso de Delphi 4.0 - Apostila 6

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Prefácio
Salve, antes de começarmos devo dizer que este será o projeto mais longo e completo que já fizemos
no decorrer deste curso, atualmente não existe mais a figura do programador, aquele cara que sentava atrás de
um teclado e ficava simplesmente desenvolvendo programas maravilhosos que o usuário acabava achando
confuso e complicado de usar. Então porque fazer um curso de Delphi (ou qualquer outra ferramenta) apenas
para apenas aprendermos a linguagem ? Sendo que seria muito mais fácil consultar o manual. Com base nisso
ao invés de me restringir a apenas ensinar macetes e dicas quentes, vou tentar algo mais "ousado" a partir de
agora, tentar dar uma visão do mundo externo para vocês com projetos reais.

Vale uma pequena observação aqui: Apesar de todos os dados se aproximarem o máximo possível
da realidade todas as empresas que serão abordadas e criadas aqui serão totalmente fictícias, caso numa dessas
loucuras da vida a empresa exista (cada dia é criado uma nova mesmo) todos os dados foram criados
exclusivamente por imaginação e não existe nenhuma relação com a realidade.

Começaremos desde a fase da entrevista com os usuários responsáveis até a finalização com a
instalação dos módulos, portanto dividi este projeto em diversas apostilas, a de hoje considero a mais chata,
mas em compensação é a mais importante, para quem gosta de colocar a mão na massa vai se decepcionar
hoje, pois a única massa que usaremos será a cerebral. Portanto feche o Delphi e o micro, pegue papel e
caneta e vamos ao trabalho.

Iniciando
A companhia Antes & Depois nos contratou para que criassemos um sistema que agilizaria o
trabalho rotineiro, esta empresa trabalha basicamente com o conceito de SPA (vulgarmente conhecidos como
Campo de Concentração para Gordinhos), mas teve um pequeno problema no caminho, Ela (a empresa) não
sabe qual o tipo de sistema que quer, mas a idéia basica de que se precisa é:

De um cadastro organizado e completo de cada cliente;


De um controle individual da criação dos programas alimentares; e
De um acompanhamento pós-programa do Cliente.

Então foram realizadas três entrevistas, a primeira com o médico-diretor geral da Empresa que
recebe e define o programa do cliente, a segunda com o responsável pelos cardápios da alimentação e a
terceira com o médico nutricionista da empresa responsável pelo acompanhamento pós-programa. A seguir
você encontrará a síntese dessas entrevistas.

Projeto 4 - Analizando o SPA Antes & Depois Cia.


1º Dia de entrevistas com o usuário: Programação alimentar para o emagrecimento
Um novo hábito em vez de uma nova dieta este é o lema da nossa empresa. Primeiramente, é
importante ter em mente a necessidade de se chegar a um novo hábito alimentar, que irá assegurar a
manutenção do peso ideal após o final do tratamento. Já sabemos que 90% das pessoas que fazem uma dieta
para emagrecer recuperam depois todo o peso perdido. Sabemos também que ficar engordando e
emagrecendo é pior para a saúde do que simplesmente manter-se obeso. Devemos, portanto, buscar sempre
um resultado definitivo, que permitirá a manutenção do peso dentro de uma faixa ideal. Esqueça aquela idéia
antiga do emagrecimento através de dietas, que representavam um período de sacrifício, fome, fraqueza e mau
humor. As pessoas deixavam inclusive de comparecer a festas e reuniões sociais que pudessem representar
uma ameaça ao seu programa alimentar rigoroso.

Flexibilidade. A tendência mundial tem sido de recomendar programas alimentares flexíveis, onde as
quantidades planejadas de cada alimento não precisam ser rigorosamente respeitadas nem o paciente é
obrigado a evitar compromissos sociais onde alimentos "proibidos" serão servidos. Algumas comidas devem
ser evitadas, ou consumidas com moderação, principalmente as mais gordurosas.

Alimentação sob-medida. Cada pessoa precisa de um determinado programa alimentar para


emagrecer de forma saudável e equilibrada. Existem fórmulas para se calcular a quantidade de calorias
a ser ingerida diariamente. Infelizmente, este método é muito falho, já que não leva em conta as grandes
variações de gasto metabólico de uma pessoa para outra. Este gasto energético só pode ser medido através de
aparelhos sofisticados e caros, que são utilizados apenas em trabalhos de pesquisa. Existem, no entanto,
maneiras práticas de se estimar quanto uma pessoa queima em calorias. Por exemplo, se o paciente já relata
na consulta que, mesmo comendo pouco, emagrece muito lentamente, provavelmente seu gasto metabólico é
baixo. Sua alimentação deverá conter entre 1000 e 1200 Kcal para que o tratamento não seja muito demorado.
Já uma pessoa que tenha engordado porque ingere uma quantidade exagerada de calorias e conta que
emagreceu rapidamente durante um período de contenção alimentar, provavelmente tem um metabolismo
que consome muita energia. Este paciente poderá emagrecer bem com uma quantidade de calorias maior,
entre 1500 e 1800 Kcal. Algumas pessoas acham que não podem emagrecer porque têm um horário muito
irregular, uma vida profissional muito agitada ou porque jantam fora todas as noites. Tudo isso pode ser
contornado. Sempre haverá uma maneira de planejar uma alimentação adequada que se adapte ao seu estilo de
vida, respeitando seus hábitos e seu paladar.

Equilíbrio. Emagrecer não é fechar a boca. A alimentação deve ser voltada para o equilíbrio do
metabolismo. Além de conter uma quantidade adequada de calorias, elas devem estar distribuídas em
proporções apropriadas, entre carboidratos, proteínas e gorduras. Para isso, você precisará conhecer a
composição dos alimentos, consultando a tabela de alimentos equivalentes ou o dicionário. Também é
importante distribuir adequadamente as refeições. Os horários não precisam ser obedecidos rigorosamente,
mas não se deve ficar mais de 4 horas sem comer. Um programa de alimentação ideal deveria conter 6
refeições diárias - desjejum (café da manhã), colação (refeição ligeira entre o desjejum e o almoço), almoço,
lanche, jantar e ceia. Se você tem o hábito de dormir logo após o jantar, não é necessário incluir a ceia. É
muito comum as pessoas saltarem refeições sempre que estão sem fome, tentando desta forma obter
resultados mais rápidos, o que não é recomendável. Uma parte importante do nosso gasto energético vem da
própria metabolização dos alimentos.

2º Dia de entrevistas com o usuário: Como são montados os cardápios


A tabela de alimentos equivalentes é uma lista de substituições, que deve ser sempre consultada
para que a alimentação não se torne monótona. Lembre-se que o objetivo principal é o desenvolvimento de
um novo hábito alimentar. Comendo todo dia as mesmas coisas você não estaria evoluindo na busca de um
comportamento alimentar diferente daquele que o levou a engordar. Através da tabela você poderá substituir
os alimentos à vontade, sempre dentro de um mesmo grupo, onde o teor calórico e a proporção de
carboidratos, proteínas e gorduras serão semelhantes (equivalentes). Conhecendo as possibilidades de
substituições que a tabela oferece, você mesmo poderá elaborar seu cardápio, mantendo-o sempre atrativo e
saboroso. Além disso, você estará apto a manipular sua alimentação para adaptá-la às mais diversas ocasiões,
como jantares festivos, refeições rápidas, churrascos e qualquer circunstância que o obrigue a sair da rotina.
A seguir você verá os 8 grupos básicos na composição de dietas para emagrecimento.

Grupo 1
VEGETAIS DE BAIXÍSSIMO TEOR CALÓRICO

ABOBRINHA ACELGA AGRIÃO AIPO


ALFACE ALMEIRÃO AZEDINHA BERTALHA
BRÓCOLIS CARURU CHICÓRIA COUVE
ESCAROLA ESPINAFRE MAXIXE NABIÇA
NABO PEPINO PIMENTÃO RABANETE
REPOLHO SALSÃO SERRALHA TAIOBA
TOMATE

Grupo 2
VEGETAIS DE BAIXO TEOR CALÓRICO (2 colheres das de sopa equivalem a 1 porção)

ABÓBORA ASPARGO BERINGELA BETERRABA


CEBOLA CENOURA CHUCHU COGUMELO
COUVE-FLOR ERVILHA PALMITO QUIABO
VAGEM

Grupo 3
FRUTAS

ABACAXI - 1 RODELA PEQUENA ACEROLA - 1 PEQUENA


ÁGUA DE COCO - 1 COPO PEQUENO MEIXA - 2 MÉDIAS
AMORA - MEIO COPO BANANA D'ÁGUA - MEIA FRUTA
BANANA MAÇÃ - 1 PEQUENA BANANA OURO - 1 PEQUENA
BANANA PRATA - 1 PEQUENA CAJÁ-MANGA - 1 PEQUENO
CAJU - 1 MÉDIOCAQUI - 1 PEQUENO CARAMBOLA - 1 MÉDIA
CEREJA - 6 FRUTAS DAMASCO - 2 MÉDIOS
FIGO - 1 MÉDIO FRAMBOESA - 10 FRUTAS
FRUTA-DE-CONDE - MEIA FRUTA GOIABA - 1 PEQUENA
GRAPEFRUIT - MEIA FRUTA JABUTICABA - 10 FRUTAS
JACA - 4 BAGOS JAMBO - 4 FRUTAS KIWI - 1 MÉDIO
LARANJA - 1 PEQUENA LIMA DA PÉRSIA - 1 PEQUENA
MAÇÃ - 1 MÉDIA MAMÃO - 1 FATIA PEQUENA
MANGA - 1 PEQUENA MARACUJÁ - 1 PEQUENO
MELANCIA - 1 FATIA MÉDIA MELÃO - 1 FATIA PEQUENA
MORANGO - 10 FRUTASNECTARINA - 1 MÉDIA NÊSPERA - 3 PEQUENAS
PASSA - 1 COLHER DE SOPA PERA - 1 PEQUENA
PÊSSEGO - 1 MÉDIO PITANGA - MEIO COPO
ROMÃ - MEIA FRUTA SALADA DE FRUTAS - 3 COLHERES
TÂMARA - 2 MÉDIAS TANGERINA - 1 MÉDIA
UVA - 10 FRUTAS

Grupo 4
CEREAIS, PÃES, BISCOITOS E MASSAS

AIPIM - 1 PEDAÇO MÉDIO ARROZ - 2 COLH. DE SOPA


AVEIA - 3 COLH. DE SOPA BATATA DOCE - 1 PEQUENA
BATATA INGLESA - 1 MÉDIA BISCOITO CREAM CRACKER - 2
BOLACHA ÁGUA E SAL - 2 CORN FLAKES - 1 COLH. DE SOPA
EMPADA - 1 PEQUENA FARINHA - 2 COLH. DE SOPA
FAROFA - 1 COLH. DE SOPA FEIJÃO - 4 COLH. DE SOPA
GERME DE TRIGO - 3 COLH. DE SOPA GRÃO DE BICO - 2 COLH. DE SOPA
LASANHA - 2 COLH. DE SOPA LENTILHA - 2 COLH. DE SOPA
MACARRÃO - 2 COLH. DE SOPA MAISENA - 1 COLH. DE SOPA
MILHO VERDE - 4 COLH. DE SOPA NHOQUE - 2 COLH. DE SOPA
PANQUECA - 1 PEQUENA PÃO DE CENTEIO - 1 FATIA
PÃO DE FORMA - 1 FATIA PÃO DE GRAHAM - 1 FATIA
PÃO INTEGRAL - 1 FATIA PÃO FRANCÊS - MEIO PEQ.
PASTEL - 1 MÉDIO PIPOCA - 1 PACOTE PEQ.
PIRÃO - 2 COLH. SOPA PIZZA - 1 FATIA PEQUENA
TORRADA - 6 DAS PEQUENAS TREMOÇOS - 3 COLH. DE SOPA

Grupo 5
CARNES, QUEIJOS E OVOS

CABRITO - 1 TERÇO DE BIFE CAMARÃO - 2 MÉDIOS


CARNEIRO - 1 TERÇO DE BIFE CARNE SECA - 1 PEDAÇO PEQUENO
CAVIAR - 1 COLHER DE SOBREMESA COELHO - MEIO BIFE
DOBRADINHA - 2 COLH. DE SOPA FÍGADO - 1 TERÇO DE BIFE
FONDUE DE QUEIJO - 25 GRAMAS FRANGO - 1 TERÇO DE BIFE
LAGOSTA - 1 PEDAÇO PEQUENO LINGUIÇA - 1 PEDAÇO PEQUENO
LULA - 1 PORÇÃO MÉDIA MEXILHÃO - 1 PORÇÃO PEQUENA
MORTADELA - 2 FATIAS FINAS OSTRAS - 1 PORÇÃO PEQUENA
OVO DE CODORNA - 3 UNIDADES OVO DE GALINHA - 1 UNIDADE
PAIO - 1 PEDAÇO PEQUENO PATO - 1 TERÇO DE BIFE
PERU - 1 TERÇO DE BIFE PEIXE - MEIA POSTA PEQUENA
POLVO - 1 PORÇÃO MÉDIA PRESUNTO MAGRO - 2 FATIAS
QUEIJO - 1 FATIA QUEIJO COTTAGE - 2 COLHERES
REQUEIJÃO - 1 COLHER DE SOPA RICOTA - 2 FATIAS FINAS
SALAME - 1 FATIA PEQUENA SALSICHA - 1 PEQUENA
SIRI - 3 DE TAMANHO MÉDIO VACA - 1 TERÇO DE BIFE

Grupo 6
GORDURAS

AZEITE - 1 COLHER DE CHÁ AZEITONA - 4 MÉDIAS


BACON - 1 FATIA PEQUENA CREME DE LEITE - 1 COLH. DE SOPA
MAIONESE - 1 COLHER DE CHÁ MAIONESE LIGHT - 2 COLH. DE CHÁ
MANTEIGA - 1 COLHER DE CHÁ MARGARINA - 1 COLHER DE CHÁ
ÓLEO VEGETAL - 1 COLHER DE CHÁ PATÊ - 1 COLHER DE CHÁ

Grupo 7
LEITES

COALHADA - MEIO COPO IOGURTE NATURAL - 1 COPO


IOGURTE DIET - 2 FRASCOS LEITE DESNATADO - 1 COPO
LEITE INTEGRAL - MEIO COPO LEITE INTEGRAL EM PÓ - 1 COLHER
PUDIM DIET - 1 PEQUENO SORVETE DIET - 1 BOLA

Grupo 8
BEBIDAS, CONDIMENTOS E DIETÉTICOS DE BAIXÍSSIMO TEOR CALÓRICO

ADOÇANTES ALHO CAFÉ CANELA


CHÁ CEBOLINHA COMINHO CRAVO
ERVA-DOCE GELATINA DIETÉTICA HORTELÃ LIMÃO
LIMONADA MATE ORÉGANO PIMENTA
REFRIG. DIETÉTICOS SAL SALSA VINAGRE
A unidade básica da tabela é chamada porção, que é a quantidade de cada alimento listado em um
grupo. Um exemplo: Se o seu programa alimentar tem no almoço 2 porções do grupo 4, você poderá
consumir:

1 colher de arroz + 1 colher de farofa ou


2 fatias de pão de forma ou
batata inglesa + 1 panqueca e assim por diante.

Se no almoço você também tem 3 porções do grupo 5, pode comer além daqueles alimentos:

1 bife de tamanho médio (cada porção corresponde a um terço de bife) ou


1 posta de peixe + 1 ovo ou
2 fatias de queijo (cada porção dá para 1 fatia) + 2 fatias de presunto e assim por diante.

Não devem ser trocados alimentos de grupos diferentes. A troca de um alimento do grupo 4 por um
alimento do grupo 5, por exemplo, implicaria em uma redução do teor de carboidratos da refeição, podendo
desregular os mecanismos cerebrais de regulação do apetite. Por outro lado, pode-se transferir um
determinado alimento de uma refeição para outra, desde que seja mantida em todas as refeições pelo menos
uma porção dos grupos 3 ou 4, que contêm mais carboidratos.

Apenas os alimentos listados nos grupos 1 e 8 podem ser consumidos à vontade, já que seu teor
calórico é considerado desprezível. Mesmo nas refeições onde estes grupos não forem mencionados, os
alimentos neles contidos podem ser consumidos sem restrições.

Os grupos 1 e 2 apresentam a vantagem de acrescentar fibras à alimentação, além de serem pobres


em calorias.

Os alimentos do grupo 3 são as frutas, constituídas basicamente de carboidratos. Não está


relacionado o abacate, por possuir um elevado teor de gordura.

Também os alimentos do grupo 4 são constituídos principalmente por carboidratos. Cuidado com as
massas e pizzas, porque na cobertura ou no molho elas podem carregar grandes quantidades de gorduras e
calorias.

No grupo 5 estão listados os alimentos constituídos por proteínas e gorduras. O teor de gorduras, no
entanto, é variável. Os queijos brancos, como a ricota, o cottage e o próprio queijo tipo Minas são menos
gordurosos que os outros. Também as carnes brancas são menos gordurosas que as vermelhas. Cuidado com a
pele dos peixes e do frango, porque é onde se armazena a gordura. Crustáceos como o camarão e a lagosta são
ricos em colesterol, assim como a gema dos ovos. Sempre que possível as carnes devem ser consumidas
grelhadas, assadas ou cozidas, já que a fritura as torna mais gordurosas.

O grupo 6 é o das gorduras. Deve ser evitado na medida do possível.

No grupo 7 estão o leite e seus derivados. Por serem menos gordurosos, deve-se dar preferência aos
desnatados.

No grupo 8 estão listados vários alimentos, temperos e bebidas cujo teor calórico é desprezível.
Apesar de não engordarem, seu consumo excessivo pode trazer outros males à saúde. O café, por exemplo,
pode causar insônia quando ingerido em demasia, enquanto os refrigerantes e temperos podem levar a
problemas gástricos.

As bebidas alcoólicas estão listadas na tabela abaixo, com seus respectivos teores calóricos. Elas não
podem substituir nenhum alimento de outro grupo, porque seu valor nutritivo não é o mesmo.

Grupo 9
BEBIDAS ALCOÓLICAS

BEBIDA QUANTIDADE VALOR CALÓRICO


Cachaça 1 dose de 50 ml 120 Kcal
Cerveja 1 copo com 300 ml 140 Kcal
Champanhe 1 copo com 100 ml 110 Kcal
Conhaque 1 copo com 50 ml 120 Kcal
Gim 1 copo com 50 ml 130 Kcal
Rum 1 copo com 50 ml 120 Kcal
Uísque 1 copo com 50 ml 120 Kcal
Vinho branco seco 1 copo com 100 ml 90 Kcal
Vinho branco doce 1 copo com 100 ml 140 Kcal
Vinho tinto 1 copo com 100 ml 70 Kcal
Vodka 1 copo com 50 ml 120 Kcal

Grupo 10
DOCES

O teor calórico dos doces é muito variável, dependendo principalmente do seu conteúdo de gorduras.
Na tabela abaixo você encontra o teor calórico médio de alguns doces mais consumidos pelos brasileiros.

DOCE QUANTIDADE VALOR CALÓRICO


BALA 1 UNIDADE 20 kCAL
BANANA CARAMELADA 1 UNIDADE 450 kCAL
BIS 1 UNIDADE 40 KCAL
BOLO DE FESTA 1 FATIA 200 kCAL
BOMBA DE CHOCOLATE 1 UNIDADE 200 KCAL
BOMBOM 1 UNIDADE 120 kCAL
BRIGADEIRO 1 UNIDADE 50 kCAL
CHICLETE 1 UNIDADE 20 kCAL
CHOCOLATE EM BARRA 1 PEQUENO 160 kCAL
DOCE DE LEITE 2 COLHERES DE SOPA 200 kCAL
GELATINA 1 CAIXA 70 kCAL
GELÉIA 1 COLHER DE SOBREMESA 30 kCAL
GOIABADA 1 PEDAÇO 80 KCAL
MILK SHAKE McDonald's 1 UNIDADE 340 kCAL
MOUSSE DE CHOCOLATE 1 POTE PEQUENO 200 KCAL
PÊSSEGO EM CALDA 1 METADE 80 kCAL
PUDIM 1 FATIA 250 kCAL
SONHO 1 UNIDADE 150 KCAL
SUNDAE (McDonald's) 1 UNIDADE 260 kCAL
SUSPIRO 1 GRANDE 70 KCAL
TORTA 1 FATIA 250 kCAL

Sempre que possível, recomenda-se dar preferência aos dietéticos, que não contêm açúcar. É
importante lembrar, no entanto, que muitos deles, mesmo não contendo açúcar, são altamente calóricos, como
é o caso dos chocolates.

Cardápio com 800 Kcal

REFEIÇÃO PORÇÕES
Desjejum (café da manhã) 1 do grupo 4 + 1 do grupo 5
Colação (lanche da manhã) 1 do grupo 3
Almoço 1 do grupo 2 + 2 do grupo 5 + 1 do grupo 4
Lanche 1 do grupo 3
Jantar 1 do grupo 2 + 3 do grupo 5 + 1 do grupo 4
Ceia 1 do grupo 3

Cardápio com 1.000 Kcal

REFEIÇÃO PORÇÕES
Desjejum (café da manhã) 1 do grupo 4 + 1 do grupo 5 + 1 do grupo 3
Colação (lanche da manhã) 1 do grupo 3
Almoço 1 do grupo 2 + 3 do grupo 5 + 1 do grupo 4 + 1 do grupo 3
Lanche 1 do grupo 4 + 1 do grupo 5
Jantar 1 do grupo 2 + 3 do grupo 5 + 1 do grupo 4
Ceia 1 do grupo 3

Cardápio com 1.200 Kcal

REFEIÇÃO PORÇÕES
Desjejum (café da manhã) 1 do grupo 7 + 1 do grupo 4 + 1 do grupo 5 + 1 do grupo 3
Colação (lanche da manhã) 1 do grupo 3
Almoço 1 do grupo 2 + 3 do grupo 5 + 1 do grupo 4 + 1 do grupo 3
Lanche 1 do grupo 4
Jantar 2 do grupo 2 + 3 do grupo 5 + 1 do grupo 4 + 1 do grupo 6 + 1 do grupo 3
Ceia 1 do grupo 3

Cardápio com 1.500 Kcal

REFEIÇÃO PORÇÕES
Desjejum (café da manhã) 1 do grupo 7 + 1 do grupo 4 + 1 do grupo 5 + 1 do grupo 3
Colação (lanche da manhã) 1 do grupo 3
Almoço 2 do grupo 2 + 3 do grupo 5 + 2 do grupo 4 + 1 do grupo 3
Lanche 2 do grupo 4 + 1 do grupo 5
Jantar 2 do grupo 2 + 1 do grupo 6 + 3 do grupo 5 + 2 do grupo 4 + 1 do grupo 3
Ceia 1 do grupo 3

Cardápio com 1.800 Kcal

REFEIÇÃO PORÇÕES
Desjejum (café da manhã) 1 do grupo 7 + 1 do grupo 4 + 1 do grupo 5 + 1 do grupo 3
Colação (lanche da manhã) 1 do grupo 3
Almoço 2 do grupo 2 + 4 do grupo 5 + 2 do grupo 4 + 1 do grupo 3
Lanche 2 do grupo 4 + 1 do grupo 5 + 1 do grupo 3
Jantar 2 do grupo 2 + 4 do grupo 5 + 2 do grupo 4 + 1 do grupo 6 + 1 do grupo 3
Ceia 1 do grupo 7 + 1 do grupo 3

Obs.: Os grupos 1 e 8 podem ser utilizados à vontade, em qualquer horário e em qualquer cardápio.

3º Dia de entrevistas com o usuário: Conversa com o nutricionista


O que é o peso ideal ? Peso ideal é aquele que propicia o máximo de saúde. O conceito atual de
saúde, segundo a Organização Mundial de Saúde é "Estado de bem-estar físico, mental e social". Estes 3
elementos devem ser, portanto, valorizados por quem tenta definir o peso ideal de um determinado indivíduo.
Métodos de cálculo do peso ideal. O cálculo do peso ideal deveria ser feito, idealmente, através da medida do
percentual de gordura corporal, que pode ser obtida por métodos como a bioimpedância ou pela medida das
dobras cutâneas. Como na maioria dos casos estes métodos não estão disponíveis, o índice de massa corporal
tem sido largamente utilizado para determinar a faixa ideal de peso. O Índice de Massa Corporal: Este índice
pode ser obtido dividindo-se o peso corporal pelo quadrado da altura em metros.
2
Por exemplo: uma pessoa que pese 67 Kg e meça 1,64m, tem um IMC de 24,9 Kg/m ,(67 divididos
pelo quadrado de 1,64).

ÍNDICE DE MASSA CORPORAL = PESO ( em Kg ) / ( ALTURA em metros ) 2

Apesar de não discriminar os componentes gordo e magro da massa corporal total, é o método mais
prático para avaliar o grau de risco associado à obesidade. Os estudos populacionais mostram que o menor
2
risco de mortalidade corresponde à faixa de IMC que vai dos 20 aos 25 Kg/m . Entre 25 e 30 já se observa
um aumento do risco. Os pacientes que aí se situam são rotulados como "sobrepesados" ou "com excesso de
peso". Entre 30 e 35 considera-se "obesidade leve", entre 35 e 40 "obesidade moderada" e acima de 40
2
"obesidade mórbida". Abaixo dos 20 Kg/m também se observam maiores índices de mortalidade,
principalmente por doenças pulmonares e desnutrição. Estão nesta faixa, por exemplo, os portadores de
2
anorexia nervosa. A faixa ideal, portanto, situa-se entre 20 e 25 Kg/m .

O indice de massa corporal por faixas de risco

Veja aqui o gráfico que mostra o risco de morte de acordo com o índice de massa corporal.

As tabelas de peso e altura

Apesar de muito sujeitas a erros, as tabelas de peso e altura ainda são largamente utilizadas em todo
o mundo para estimar-se o peso ideal. Elas são derivadas de dados obtidos por companhias de seguro
americanas, que as desenvolveram a partir da observação de dados de mortalidade e longevidade de sua
população segurada. Os pesos chamados de "ideais" são, na verdade, médias das faixas de peso ideal para
cada grupo etário analisado. As tabelas abaixo mostram os pesos de referência para cada um destes grupos.
Reparem que na tabela dos indivíduos mais idosos estes pesos já são bem mais altos.

Pesos de referência para adultos entre 21 e 55 anos

ALTURA (em metros) PESO para homens (em Kg) PESO para mulheres (em Kg)
1,47 - 51,7
1,50 - 52,8
1,52 - 53,9
1,55 - 55,3
1,57 60,3 56,7
1,60 61,2 58,0
1,63 62,4 59,4
1,65 63,5 60,8
1,68 64,9 62,1
1,70 66,2 63,5
1,73 67,6 64,9
1,75 68,9 66,2
1,78 70,3 67,6
1,80 71,9 69,0
1,83 73,9 -
1,85 75,3 -
1,88 76,9 -
1,91 78,9 -

Pesos de referência para adultos entre 55 e 74 anos

ALTURA (em metros) PESO para homens (em Kg) PESO para mulheres (em Kg)
1,47 - 57
1,50 - 62
1,52 - 65
1,55 - 64
1,57 68 64
1,60 70 65
1,63 71 66
1,65 72 67
1,68 74 66
1,70 78 72
1,73 78 70
1,75 77 72
1,78 80 73
1,80 84 -
1,83 81 -
1,85 88 -
1,88 95 -

Obs. Os métodos utilizados para o cálculo do peso ideal de adultos não são adequados para indivíduos em
fase de crescimento.

Observações finais
Além dessas três entrevistas foi constatado que o SPA Antes & Depois ainda mantêm alguns dados
importantes:

Manutenção periódica da Pasta do Cliente que contém:


Dados para o envio de eventual correspondência de propaganda e promoções.
Dependendo do plano adotado - acompanhamento nutricional e envio de um cardápio semanal
personalizado e completo, baseado no plano de calorias indicado pelo nutricionista.
Histórico dos planos realizados pelo cliente no SPA.

Não são aceitos clientes menores de 21anos e maiores de 74 anos de idade.

Descontos para clientes com re-incidência, baseado na seguinte tabela:


5% primeira re-incidência.
10% segunda re-incidência.
15% terceira re-incidência.
Aumento de 1% nas próximas re-incidências até um máximo de 20%.

Os planos da empresa são:


Plano A (Anti-Stress) - 3 Dias.
Plano B (Reeducação) - 1 Semana com acompanhamento periódico de 3 meses.
Plano C (Completo) - 1 mês.
Plano D (Especial de Reeducação) - 4 Dias com acompanhamento periódico de 3 meses.

A divisão do capital da empresa é realizada em cima do preço final do cliente, e dividido da seguinte maneira:
20% para o médico-presidente da empresa.
40% para o coordenador dos planos alimentares.
10% para o nutricionista (caso seja efetuado os planos B ou D ).
30% (ou 40 % - caso seja efetuado os planos A ou C) para despesas gerais.
e todo final de mês é criado um relatório de fechamento financeiro com a situação da empresa e a divisão do
capital do mês.

Finalmente
Prontinho na próxima apostila, criaremos nosso projeto físico baseado em tudo o que foi feito aqui, o
projeto físico servirá para montarmos nossa base de dados e termos uma idéia qual o caminho que seguirá
nosso sistema.

Então aconselho a você que releia as entrevistas com calma e começe a pensar não apenas como uma
chave de fenda mas como a caixa de ferramentas completa que não só senta na máquina e começa a
programar mas analisa e verifica o que o usuário realmente necessita.
7 Curso de Delphi 4.0 - Apostila 7

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• BASICO.MDB

Prefácio
Salve, espero que todos vocês tenha gostado do rumo que tomou o nosso curso, também espero que
assim fique mais interessante e atual o uso de uma linguagem tão complexa como é o Delphi.

Vale uma pequena observação aqui (copiada da apostila anterior, para ficar bem claro): Apesar de
todos os dados se aproximarem o máximo possível da realidade todas as empresas que serão abordadas e
criadas aqui serão totalmente fictícias, caso numa dessas loucuras da vida a empresa exista (cada dia é criado
uma nova mesmo) todos os dados foram criados exclusivamente por imaginação e não existe nenhuma
relação com a realidade.

Já estamos com todos os dados da nossa empresa na mão, agora vem a fase que antigamente era
designada exclusivamente para a nata da informática conhecida por: Analistas de Sistemas, quantas vezes
não sonhamos com esse maravilhoso e imponente título. Bem, uma coisa devemos aprender: "Atualmente
quem na área de informática não chuta nas onze, não se dá muito bem e acaba vendendo cachorro-quente na
porta da Igreja", então quem acha que aprendendo Delphi, ou qualquer outra ferramenta de desenvolvimento,
e a única coisa que vai ter que fazer daqui para frente, são programas já prontos e detalhados logicamente sem
ter que usar qualquer conhecimento de um Analista de Sistemas, pode começando a pensar seriamente a
mudar de profissão.

É óbvio que experiência nunca vou conseguir passar para todos, principalmente porque esta vida é
um eterno aprendizado, mas vou tentar dar algumas dicas para vocês começarem a pegar o embalo.

Brain-Storm
Na entrevista ouvimos algumas palavras chaves, então primeiramente, pegue um quadro-negro e
juntamente com sua equipe de desenvolvimento tente fazer um resumo de tudo o que foi dito nas entrevistas
iniciais:

• Cadastro organizado e completo de cada cliente;


• Criação dos programas alimentares;
• Acompanhamento do Cliente;
• Cada cliente precisa de um determinado programa;
• Existem fórmulas para se calcular a quantidade de calorias, este método é muito falho;
• O paciente relata na consulta e sempre haverá uma maneira de planejar uma alimentação adequada;
• Existe uma tabela de alimentos;
• Existem cardápios formados através de uma regra;
• O Índice de Massa Corporal pode ser obtido dividindo-se o peso corporal pelo quadrado da altura em
metros;
• Existe uma tabela para o Índice de Massa Corporal;
• Existe uma tabela de Descontos para clientes re-incidentes;
• Existem duas divisões entre 21 - 55 e 55 - 74 anos;
• Excluem-se menores de 21 e maiores de 74 anos; e
• Cálculos de receitas e despesas através de demonstrativos mensais e resumo anual.

Está técnica é melhor quando a equipe é formada por três ou mais pessoas, uma coisa se você é do
tipo que detesta o trabalho em grupo, infelizmente você será um péssimo Analista, pois 98% do trabalho é
feito com discussões em grupo, debates e análises com a equipe e com o usuário, validando e revalidando
periodicamente todos os dados levantados, até que o sistema esteje entregue e pronto.

O método que mostrei acima é conhecido por Brain-Storm (Tempestade Cerebral) a idéia é que
você recolha os dados mais importantes e discuta em cima deles, existem óbvio vários métodos de análises,
mas pessoalmente, considero este o melhor, adote aquele que você sinta mais a vontade.

Preparação da Modelagem dos Dados


A próxima fase é conhecida como Modelagem dos Dados, aqui vamos definir nossas entidades
(antigamente chamariamos de tabelas, mas prefiro adotar uma linguagem mais atual), faça um jogo com você
mesmo antes de ler os atributos de cada entidade (campos) propostos por mim, tente montar seus próprios
atributos:

Entidade Cliente

Atributos: CPF, Nome, Endereço, Bairro, CEP, Cidade, Estado, eMail, Telefones de contato, Altura,
Peso medido e data de nascimento.

Entidade Alimento

Atributos: Número do Grupo, Nome do Alimento e Quantidade Permitida

Entidade Pasta do Cliente

Atributos: CPF do Cliente, Data, Plano Adotado, Quantidade de Calorias, Observações do


tratamento, Data de pagamento, Valor Total e Desconto concedido

Entidade Resumo Mensal

Atributos: Mes e Ano, Valor do Médico, Valor Coordenador, Valor Nutricionista e Valor Despesa

☞Importante - Dicas Quentes:


- Não dê o nome de uma entidade no plural, por exemplo Clientes, Alimentos pois além de gastar
um byte a mais para o banco de dados, está errado pois sempre nos referimos a um único registro da
entidade.
- Pense na entidade como única, note que a entidade Cliente tem o atributo Cidade, o que pode
futuramente virar uma outra entidade, mas sempre deixe isso para a fase de normalização.
- Não invente entidades ou atributos que não fazem parte do que foi levantado com os usuários, é
lógico que os clientes devem ter uma profissão, mas isso não interessa para nosso sistema, se achar que
interessa discuta primeiro com o usuário.
- Evite sempre códigos estranhos ao cliente para definir Chaves Únicas (aquelas que servirão de
índices primários), primeiro procure por campos únicos na própria entidade, na entidade Cliente podemos
usar o CPF.

Modelo Físico
Terminada a fase de Preparação da Modelagem, é iniciado todo o trabalho para a construção de um
modelo físico, ou seja, como realmente vai ficar implantado nossa base de dados, neste momento valem todas
as regras de Normalização e outras técnicas aprendidas em qualquer bom Curso de Análise ou Livros
disponíveis no mercado, como minha função é ensinar o Delphi não vou me ater a estes detalhes então vamos
dar uma olhada no Modelo Físico pronto e depois farei alguns comentários necessários:

Bem aqui valem algumas regras que aprendi ao longo do tempo:

1. Formação dos Nomes dos Atributos:


O maior trabalho de uma empresa de desenvolvimento é formar o nome dos atributos, pois sabemos
que eles influenciarão no nome das variáveis, assim ao longo do tempo, e após vários aperfeiçoamentos
cheguei a uma regra que venho adotando:

XXX_YYYYY - aonde:

XXX - Três casas representativas do atributo, Ex: NOM - Nome, NUM - Número, VAL - Valor, DAT - Data,
DES - Descrição, ...
YYYYY - Complemento do Atributo, Ex: Nome da Própria Entidade, Nomes Significativos, ...

2. Quanto ao Tipo do Atributo:


Uma dica que aprendi a muito tempo ainda vale até hoje, escolha os tipos com lógica e utilidade,
quer um exemplo então responda as seguintes perguntas:
O que é mais útil e lógico um atributo CPF (NUM_CPF) ser Texto com 11 casas ou um Inteiro ?
Se vamos fazer cálculos com a Altura do Cliente (ALT_CLIENTE) então definiremos o atributo como Texto
ou Inteiro com casas decimais ?
Se a observação do clientes (OBS_PASTA) pode variar muito o que é mais prático um campo Texto
Variável ou um Texto fixo de 300 casas ?
Todas as quantidades devem ser numéricas mesmo que não se façam cálculos com elas ? E como fica a
Quantidade de Caloria (QTD_CALORIA)

3. Escolha das Chaves:


Vou bater na mesma tecla pois acho ela importante, escolha chaves fáceis de lembrar, no último caso
escolha os tipos de atributos automáticos, como foi o caso da entidade ALIMENTO que acabei optando por
uma chave Auto Incremental (1,2,3,4,5...)

☞Importante - Não utilize, mesmo que o banco permita, tipos de atributos AUTO INCREMENTAL pois
esses campos não permitem sua modificação ou seu controle, utilize campos INTEIROS e faça os cálculos
do maior através de uma função genérica.

Módulos Funcionais
A última fase da Analise de um sistema é a documentação de todas as funções ou se você preferir
pode chamar de Módulos Funcionais, estes módulos normalmente são divididos em cadastros,
movimentações, consultas e relatórios impressos, fazendo isso e conseguindo a validação do usuário, você
evitará muitos aborrecimentos posteriores, tais como ser mal interpretado ou de causar falsas expectativas, e
esta fase também ajudará na elaboração das Opções do Menu.

Cadastro

Cidade: terá a função de editar e coordenar o arquivo de cidades


Grupo: terá a função de editar e coordenar o arquivo de grupos
Alimento: terá a função de editar e coordenar o arquivo de alimentos
Cliente: terá a função de editar e coordenar o arquivo de clientes

Movimentação

Entrada do Cliente: recepção para os clientes e montagem e definição dos planos nas pastas
Saída do Cliente: fechamento da conta e da pasta do cliente
Massa Corporal: Cálculo da Massa Corporal e pesagem atual de determinado cliente

Consulta

Pasta do Cliente: Verificação de determinado cliente, com gráficos sobre peso e massa coorporal
Verificação do Caixa Mensal: Cálculo da arrecadação de um determinado mês

Relatório

Correspondência: envio de corrêspondencia a clientes


Cardápio: montagem de determinado cardápio diário baseado no número de calorias informadas
Divisão das Contas Mensal: fechamento das contas mensais e divisão dos lucros
Analítico das Contas Anual: resumo anual de toda a divisão efetuada

Finalmente
Prontinho agora resta mostrar para o nosso usuário ter o carimbo de aprovação, não se esquecendo de
especificar prazos para a conclusão de cada módulo funcional descrito.

Na próxima apostila, começaremos a programar nosso sistema criando o menu e as telas de apoio.
8 Curso de Delphi 4.0 - Apostila 8

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• PESO.HLP
• IM0.BMP até IM10.BMP

Prefácio
Salve, bem hoje pretendo tratar aqui de um tema da maior importância, também que gera a maior
polêmica entre qualquer grupo de mais de um programador, Menus. Não me refiro a Cardápios, e sim Menus
de Sistemas, ou popurlamente chamados de Telas de Entrada, por isso mesmo que são os responsáveis pela
maior polêmica.

Um Menu está para um sistema, assim como a Sala está para a casa, pegue um sistema, o mais
prático o possível, cheio de "nove horas", entre outras dezenas de outras vantagens, e acrescente nele um
Menu horroroso que só quem o programou entende e depois de um mês nem ele mais.

Esta apostila (tão aguardada) pode parecer simples a primeira vista, mas garanto-lhes que não é
muito simples projetar uma casa sem começar pela sala.

Tipos de Sistema SDI ou MDI ?


Vou falar rapidamente dos tipos de sistemas, existem basicamente dois tipos de sistemas:

MDI (multiple document interface) - é aquele que permite a abertura de várias janelas, caracterizando-as
como filhas que são exibidas dentro do contexto da janela principal, pode ser aberto inclusive diversas cópias
de uma mesma janela. Existindo uma intensa movimentação entre elas. Muito usado em Editores de texto e
Planilhas de cálculos.

SDI (single document interface) - é aquele que permite a abertura de uma só janela de cada vez inibindo
atuações nas áreas fora da mesma, não existindo nenhuma coorelação entre elas. Muito usados em sistemas de
grande porte.

Já deu para perceber a diferença básica entre os menus que são construídos para cada sistema, no
primeiro caso o Menu deve ser máximizado para comportar as janelas filhas, no segundo caso o Menu pode
ser uma simples janela que pode ser colocada no canto superior (como a barra do Office), se você se
complicou com os dois sistemas imaginemos um Sistema de Estoque, aonde existe um formulário que é a
Fatura podemos tratá-la da seguinte maneira:

No sistema MDI - A janela da Fatura pode ser aberta diversas vezes, ou seja no meio de uma Fatura,
poderemos iniciar uma nova, ou então entrar na janela de Material para cadastrar (ou descobrir o código) de
um determinado material.

No sistema SDI - A janela da Fatura é aberta e nela permanece (salvo que exista um botão, ou outro meio,
para chamar uma outra janela) até que a Fatura seja encerrada.

Também você deve ter notado que existem diferenças bárbaras em ambos os sistemas, vamos
analisar as desvantagens:

No sistema MDI - O usuário pode começar a abrir diversas janelas de Faturas, ou um número excessivo de
janelas, causando assim o estouro da área de memória, lembre-se que cada formulário aberto vai para a área
de memória, aquela área baixa (do 640 Kb) então nem adianta aumentar a memória, vai chegar num momento
que o sistema simplesmente não aguentará.

No sistema SDI - Se o usuário precisar de cadastrar (ou descobrir o código de) um determinado material, ele
precisará cancelar a Fatura fechar a janela, entrar na janela de Material, cadastrar ou pesquisar , fechar essa
janela e voltar para a janela de Fatura e começar a digitar a Fatura tudo novamente, a menos que o
Programador tenha lembrado de colocar um botão para que ele acesse a tela de material.

Pessoalmente eu prefiro meus sistemas no modo SDI, apesar de achar o MDI tentador, primeiro
muitos dos meus usuários são leigos, eu não teria como explicar-lhes (às cinco da manhã de sábado
normalmente) que a aplicação deles caiu porque tinha vinte clientes na loja e ele resolveu abrir vinte janelas
de Fatura, mas você poderá optar por qual sistema deseja adotar, pois futuramente nosso próximo projeto
será um sistema totalmente MDI.

Tipos de Menus
Ficou comprovado no ambiente Windows, também em outros ambientes, que o Menu que melhor
funciona é aquele que abre de cima para baixo, estou me referindo dentro do Delphi ao 1o. Objeto da 1a.
Palheta, ou seja o objeto MainMenu, não é a toa que ele é o primeiro, seu irmão mais novo é o PopMenu,
aquele menuzinho rápido que temos todas as vezes que clicamos com o botão direito em cima de um objeto.

Já vi muitos Menus interessantes, dos mais diversos tipos, um deles inclusive imita o menu do botão
Iniciar do Windows 95, mas pessoalmente fico com os menus Pull-Down (é assim que são chamados)
primeiro porque em qualquer aplicação do Windows (ou outro ambiente) eles estão lá, segundo porque o
usuário é acostumado com eles (desde que se sigam regras) e terceiro porque são mais simples de se
programarem.

Desde a primeira versão do Pascal for Windows que a Borland (hoje Inprise) lançou esse tipo de
menu, e sempre sua programação foi muito superior aos seus concorrentes, além de muito fácil, abro um
desafio aqui, peguem uma cópia dos VB's (ou FOX, Access, CA-Clipper) ou e tentem criar um menu lá,
agora peguem o velho Pascal for Windows e façam a mesma coisa, e me digam o que acharam.

O Delphi, seguiu uma tradição da família, seu menu é tão fácil de programar que até mesmo me
assusta, vamos lá, sigam o mestre:

1. Se você ainda não fez crie um diretório que abrigará seu sistema. (para padronizar comigo crie:
C:\CursoDelphi\Peso)

Antes de começarmos a criar nossos menus, deixe-me dizer-lhes um detalhe a mais, a partir do MS-
Office 97, foram colocadas figurinhas no tamanho de 16x16 nos menus, e parece que com o Windows 98 isto
virou um padrão oficial dos Menus, então na Component Pallete localize uma página chamada Win32 e
dentro dessa página de um clique no objeto ImageList (acredito que seja o terceiro) e dê um clique no Form.
(automaticamente o Delphi criou um botãozinho com o desenho dele. Para o Delphi é assim que ficam todos
os objetos que são invisíveis durante o tempo de execução, ou seja tanto faz em qual posição que você o
coloque, quando começar a rodar seu sistema este objeto ficará invisível). Dê um duplo clique no objeto
criado e vamos entrar na ImageList, clique no botão Add e vá adicionando as imagens enviadas na ordem:
primeiro a IM0.BMP, depois a IM1.BMP e assim sucessivamente, veja a figura:

2. Abra o Delphi e na Component Pallete localize uma página chamada Standard e dentro dessa página de
um clique no objeto MainMenu (acredito que seja o primeiro) e dê um clique no Form. (automaticamente o
Delphi criou um botãozinho com o desenho dele, mais um objeto invisível). Dê um clique simples em cima
do objeto criado e altere a seguinte propriedade:

Images: ImageList1 (Define um objeto ImageList para ser utilizado como repositório de imagens).

3. Vamos agora entrar na Menu Editor, dê agora um clique duplo em cima do MainMenu1 criado, agora é
só começar a construir seu Menu, este é um objeto que sou apaixonado vamos a algumas propriedades:

3.0.Antes deixe-me avisá-lo que cada quadradinho criado representa um novo objeto (pertencente a
classe tMenuItem)
3.1.BitMap: A partir do MS-Office 97, foram colocadas figurinhas no tamanho de 16x16 nos
menus, e parece que com o Windows 98 isto virou um padrão oficial dos Menus, então aqui você insere este
tipo de figura.
3.1.Break: permite que você crie um submenu lateral (utilize a opção mbBreak para o primeiro e
mbBarBreak para os filhos)
3.2.Caption: é o que o seu usário verá, a opção em si, utilize o caracter & para colocar atalhos nas
opções (ex: &Arquivo)
3.3.Check: permite que você crie uma marca no item de menu, assim você pode criar opções do tipo
habilitado ou não.
3.4.Default: permite que uma das opções de um dos itens do submenu fique em negrito.
3.5.GroupIndex: cria para um determinado Grupo de submenu um indice, uma marca, determinante,
assim você pode dizer os itens do grupo 1 estão desabilitados, os do grupo 2 estão habilitados e assim vai.
3.6.HelpContext: desloca automaticamente ao contexto selecionado ao ser chamado um arquivo de
auxílio, se o HelpContext for igual a 0 não envia para contexto nenhum.
3.7.Hint: Pequeno auxílio para o item do menu, mas essa propriedade deve ser visualizada através de
um objeto do tipo StatusBar (localizado na Palheta Win32)
3.8.Name: Todos os objetos tem que ter, me recuso a escrever sobre essa propriedade, vou deixar
vocês na dúvida.
3.9.RadioItem: Seleciona dentre um grupo (determinado pela propriedade GroupIndex) um único
item do menu, por exemplo um submenu assim: Cor de Fundo, items: Azul, Vermelho ou Verde.
3.10.ShortCut: Cria um atalho rápido através do menu, por exemplo CRTL+C ou CTRL+V
3.11.Tag: Outra propriedade, em conjunto com a propriedade Name, que aparece em todos os
objetos, independente da cor, raça ou credo, a Tag é uma variável inteira que você pode rotular para diversos
usos como por exemplo transformar em Invisível todos os objetos que possuam a Tag igual a 10 ou pintar a
fonte de azul-marinho todos os objetos da Tag 5.
3.12.Visible: Permite que o objeto fique visível ou não em tempo de execução.

Prontinho com todas essas informações acredito que você já está pronto (e ansioso) para construir nosso
menu. Vamos lá então. Na primeira janelinha, ou se você prefere no primeiro Item de Menu altere as
seguintes propriedades:

Caption - &Arquivo
Hint - Arquivos principais do sistema.

Assim que você pressionar o Enter vai formar mais duas novas janelas uma lateral a Arquivo e uma logo
abaixo dele, na janela abaixo, clique nela e altere as seguintes propriedades:

Caption: &Cadastro
Hint: Informações principais do sistema.
ImageIndex: 0

Assim que você pressionar o Enter vai formar uma nova janela uma abaixo a Cadastro, ainda com o curso
posiciona em Cadastro clique com o botão direito e no menu que aparecerá clique com o botão direito do
mouse na opção Create Submenu, e será criada um item de menu lateral, clique nesse novo item e altere as
seguintes propriedades, e a medida que for criando crie as demais opções:

Caption: &Cidade
Hint: função de editar e coordenar o arquivo de cidades

Caption: &Grupo
Hint: função de editar e coordenar o arquivo de grupos

Caption: &Alimentos
Hint: função de editar e coordenar o arquivo de alimentos
Caption: - (sinal de menos)

O resultado será uma barra de separação

Caption: Cli&entes
Hint: função de editar e coordenar o arquivo de clientes

Volta para aquela área abaixo do cadastro e altere a propriedade

Caption: -

(Você não está enchergando ruim não é o traço de menos mesmo.) Isso produzirá o seguinte efeito:
E vamos a última opção deste submenu:

Caption: &Sair
Hint: Retorna ao Windows
ShortCut: Ctrl+S
ImageIndex: 10

Prontinho a subopção Arquivo ficou da seguinte maneira:

☞Importante - As imagens aparecerão apenas fora do MenuEditor.


Agora crie os outros submenus segundo definimos na apostila anterior, não se lembra ? então aqui estão eles:
(com os respectivos Caption's, Hint's e caso tenham ImageIndex)

&Movimentação: informações constantes do sistema


&Entrada do Cliente: recepção para os clientes e montagem e definição dos planos (ImageIndex:
1)
&Saída do Cliente: fechamento da conta do cliente (ImageIndex: 2)
&Massa Corporal: Cálculo da Massa Corporal e pesagem atual do cliente (ImageIndex: 3)

&Consulta: visões on-line dos arquivos


&Pasta do Cliente: Verificação de determinado cliente, com gráficos sobre peso e massa coorporal
(ImageIndex: 4)
&Verificação do Caixa Mensal: Cálculo da arrecadação de um determinado mês

&Relatório: emissões na tela e em papel de um determinado momento dos arquivos


&Correspondência: envio de corrêspondencia a clientes (ImageIndex: 9)
Car&dápio: montagem de determinado cardápio diário baseado no número de calorias informadas
&Divisão das Contas Mensal: fechamento das contas mensais e divisão dos lucros
&Analítico das Contas Anual: resumo anual de toda a divisão efetuada
-
Configura &Impressora: Verifica qual a impressora que será utilizada para as impressões
(ImageIndex: 5)

Au&xílio: chama o help on-line do sistema


&Conteúdo: Conteúdo do auxílio on-line (ImageIndex: 6)
&Tópicos do Auxílio: Chama os tópicos do Auxílio on-line (ImageIndex: 7)
Como &Usar o Auxílio: Como ultilizar o auxílio do windows (ImageIndex: 8)
-
&Sobre o Sistema: Informações sobre a execução do sistema
4. Dê uma salvadinha no seu projeto, para tanto, no menu vá em File | Save All...:

4.1. Aonde aparece Unit1.pas (o Delphi está se referindo do nome do formulário) mude para
fMenu.PAS
4.2. Aonde aparece Project1.dpr (o Delphi está se referindo do nome do projeto - que será o nome
do executável final) mude para Peso.DPR

5. Pode sair do Menu Editor e testar seu menu. Clique agora em qualquer área vázia do formulário e vamos
alterar algumas propriedades:

5.1. Caption - Sistema de Controle do SPA - Antes & Depois


5.2. Name - F_Menu
5.3. WindowState - wsMaximized (fará com que o formulário se inicie no modo maximizado)

6. Na Component Pallete localize uma página chamada Win32 e dentro dessa página de um clique no objeto
StatusBar (acredito que seja o décimo quarto) e dê um clique no Form, foi criado tipo um painel na parte
inferior do formulário. Altere as seguinte propriedades:

6.1. Name - BarraStat


6.2. Panels - Clique nos ... e clique três vezes no primeiro botãozinho (marcado com Add New (Ins)
) para criar 3 subpainéis e altere as seguintes propriedades de cada um:

6.2.1. Para o primeiro:


Text - Bem Vindo...
Width - 500
6.2.2. Para o segundo:
Text - 99:99:99
Width - 60
Alignment - taCenter
6.2.3. Para o terceiro:
Text - Criado por: Curso de Delphi
Alignment - taCenter

7. Na Component Pallete localize uma página chamada System e dentro dessa página de um clique no objeto
Timer (acredito que seja o primeiro) e dê um clique no Form, foi criado tipo um quadradinho representando o
objeto.

Iniciando os programas do Menu


Vamos começar agora a programar nosso Menu. Primeiramente vamos programar a Barra de Status,
note que nela foram criados 3 painéis, ou três divisões, a primeira servirá para capturar os Hint de cada objeto
do Menu (tMenuItem), a segunda mostrará a hora atual do micro com a ajuda do objeto Timer, e a terceira
será uma propaganda fixa (isso é excelente quando queremos promover nossa SoftwareHouse). Para capturar
os hint dos objetos precisamos criar um procedimento particular que faça esse desvio, para tanto, aperte o
botão F12 para ir para a Code Editor e localize a seguinte parte:

private
{ Private declarations }
public

E coloque o seguinte código:

private
procedure MontaHint(Sender: TObject);
public
Agora abaixo da diretiva de compilação, insira o seguinte código:

implementation

{$R *.DFM}

procedure TF_Menu.MontaHint(Sender: TObject);


begin
BarraStat.Panels[0].Text := Application.Hint;
end;

Isto transferirá o Hint do objeto selecionado para o primeiro painel da Barra de Status, mas
precisamos iniciar, aperte a tecla F11 para chamar a Object Inspector e selecione o objeto F_Menu vá para a
janela de eventos e dê um duplo clique para o evento OnCreate e coloque o seguinte código:

procedure TF_Menu.FormCreate(Sender: TObject);


begin
Application.OnHint := MontaHint;
end;

Prontinho, agora vamos tratar do segundo painel, selecione novamente a Object Inspector e
selecione o objeto Timer1 vá para a janela de eventos e dê um duplo clique para o evento OnTimer e
coloque o seguinte código:

procedure TF_Menu.Timer1Timer(Sender: TObject);


begin
BarraStat.Panels[1].Text := FormatDateTime('HH:MM:SS',Now);
end;

A cada segundo a hora será atualizada, não se preocupe que isso não afetará em nada o desempenho
do sistema. Bem agora vamos colocar alguns comandos básicos, inicialmente, aperte F12 para voltar a ter a
visão do formulário, e clique em Arquivo e Sair, coloque o seguinte código:

procedure TF_Menu.Sair1Click(Sender: TObject);


begin
Close;
end;

O comando Close fará com que o formulário seja encerrado, como é o próprio Menu do Sistema,
então o Sistema será encerrado.

Codificando o Auxílio
Uma coisa interessante sobre o Delphi é como ele facilmente chama e executa arquivos .HLP,
enquanto que para muitos softwares isso é algo do outro mundo, no Delphi basta, simplesmente executarmos
alguns comandos pré-programados, além de que diversos objetos tem a propriedade HelpContext que
permite que o arquivo de ajuda seja acionado a partir da tecla F1 a partir de um tópico Pré-Definido.

Futuramente veremos como criar nosso arquivo de auxílio, mas, por enquanto vamos utilizar o
arquivo enviado juntamente com esta apostila.

A partir do Menu Principal vá em Project | Options... na página Applications altere as seguintes


propriedades:
Title: Controle do SPA
HelpFile: Peso.HLP

As palavras-chaves para o comando HelpCommand são:

Comando Parâmetro Passado Utilização


HELP_CONTEXT Inteiro longo, contendo o número do contexto. Mostra o auxílio a partir de tópico selecionado
identificado a
partir do número do contexto
definido pela seção [MAP] do arquivo .HPJ

HELP_CONTENTS Ignorado. Normalmente passado 0. Mostra o conteúdo do primeiro tópico definido


pela seção [MAP] do arquivo .HPJ

HELP_SETCONTENTS Inteiro longo, contendo o número do contexto Determina a chamada do tópico determinado
que foi designado como tópico de conteúdo.através do uso da tecla F1

HELP_CONTEXTPOPUP Inteiro longo, contendo o número do contexto. Mostra uma janela Pop-Up com um tópico
particular identificado pelo número do contexto definido pela seção [MAP]
do arquivo .HPJ

HELP_KEY Ponteiro longo como uma string contendo o Mostra um tópico pesquisado em uma lista
tópico designado. de palavras chaves. Esta palavra chave deve ser
exatamente o
texto procurado.

HELP_PARTIALKEY Ponteiro longo como uma string contendo o Mostra um determinado tópico através de uma
tópico designado. lista de palavras chaves. Se a palavra chave não
for encontrada posiciona na palavra fonêtica
mais perto.

HELP_MULTIKEY Ponteiro longo para uma estrutura de Mostra o tópico indentificado pela palavra
TMULTIKEYHELP. Esta estrutura específica de chave ou uma chave da tabela alternada.
caracteres e palavras chaves.

HELP_COMMAND Ponteiro longo, contém a macro para a execução Executa um macro help.

HELP_SETWINPOS Ponteiro longo para uma estrutura de Mostra um help do windows com um mínimo de
TMULTIKEYHELP. Esta estrutura específica memória, variando o tamanho e a posição de
contém o tamanho e a posição da janela do help acordo primário ou a janela secundária para ser
mostrado. com o dado passado.

HELP_FORCEFILE Ignorado. Normalmente passado 0. Executa o WinHelp mostrando o arquivo de


auxílio corrijido.

HELP_HELPONHELP Ignorado. Normalmente passado 0. Mostra o auxílio de como usar o auxílio.

HELP_QUIT Ignorado. Normalmente passado 0. Solicita o fechamento do auxílio ativo.

De posse desse nosso dicionário de comandos, aperte F12 e clique em Auxílio e Conteúdo, e insira
o seguinte código:

procedure TF_Menu.Contedo1Click(Sender: TObject);


begin
Application.HelpCommand(HELP_CONTENTS, 0);
end;

Aperte F12 e clique em Auxílio e Tópicos do Auxílio, e coloque o seguinte código:

procedure TF_Menu.TpicosdoAuxlio1Click(Sender: TObject);


const
EmptyString: PChar = '';
begin
Application.HelpCommand(HELP_PARTIALKEY, Longint(EmptyString));
end;

E finalmente, aperte F12, clique em Auxílio e Como usar o Auxílio, e coloque o seguinte código:

procedure TF_Menu.ComoUsaroAuxlio1Click(Sender: TObject);


begin
Application.HelpCommand(HELP_HELPONHELP, 0);
end;

Vamos completar o comando de sair colocando também o encerramento do arquivo de auxílio,


aperte F12 e clique em Arquivo e Sair, complete com seguinte código antes do comando Close:

procedure TF_Menu.Sair1Click(Sender: TObject);


begin
Application.HelpCommand(HELP_QUIT, 0);
Close;
end;

Rode sua aplicação e teste os comandos do Auxílio, caso a tecla F1 não ative o auxílio On-Line,
provavelmente o seu menu está com a propriedade FormStyle em modo fsMDIForm, coloque-a no modo
fsNormal. Se mesmo assim ainda não funcionou, mude a propriedade HelpContext do formulário para 1.

Finalmente
Uma dica interessante é que o Fórmulário está associado ao Menu através da propriedade Menu, é
que ela é possível de ser alterada em modo Run-Time, então imagine que num mesmo formulário é possível
ter vários Menus diferentes, cada um se adaptando a uma situação do usuário (financeiro, administrador,
digitador).

Na próxima apostila, vamos criar as janelas auxiliares Splash e Sobre o Sistema.


9 Curso de Delphi 4.0 - Apostila 9

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• IMGGER.BMP
• IMGICO.BMP

Prefácio
Salve, a apostila de hoje faz parte do chamado propaganda do sistema, o ambiente Windows
conseguiu trazer consigo mais do que simplesmente um ambiente gráfico de janelas, trouxe uma coisa muito
importante, alias foram duas, note que todo o sistema ditos "for Windows" carregam consigo essas duas
importantes e imprescindíveis janelas.

Splash Screen, não isso não é nada do outro mundo, ouvimos e vimos falar de uma janela Splash
desde a primeira vez que entramos no Word, no Access e até mesmo o Delphi tem a sua janela Splash, não
precisa você ficar procurando por ela, ela está logo na nossa cara assim que entramos em qualquer desses
aplicativos, e a chamada janela inicial.

Sobre o Sistema, para que serve ? como surgiu ? como começou ? ninguém sabe, sabe-se apenas
que todo o sistema que se preza tem que ter a sua, algumas bem incrementandas contendo os famosos "Ovos
de Páscoa", aquela combinação maluca de teclas que antes de iniciarmos a janela Sobre é mostrado algo mais,
as vezes pode até ser um joguinho.

A Splash Screen e a Sobre o Sistema são janelas que a maioria dos programadores não dá a menor
importância, mas que bem feita pode ser como um Out-Door na estrada, rendendo-nos uma bela propaganda
gratuita da nossa empresa. Vou tentar ensinar aqui alguns macetes como se criar ambas as janelas com um
pouco de incrementação, vamos nessa então.

Splash Screen
Inicialmente deixe-me dizer uma coisa, a Splash é apenas uma janela pedindo para o usuário ter um
pouco de paciência enquanto todo o sistema se inicia, não a faça demorada demais pois a última coisa que o
usuário precisa e de mais paciência, tem gente que coloca um timer nelas para poder demorar ou então um
simples comando For i := 1 to 10000 não façam isso, inicialmente pode parecer que a janela pouco vai
aparecer, mas não se preocupe com o tempo, e o sistema crescendo, essa janela vai acabar demorando o
tempo suficiente para que o usuário possa ver as informações descritas nela e não se aborrecer.

Para começarmos abra o sistema e a partir do Menu Principal clique em File | New Form criando
um novo formulário que será a nossa área de trabalho, vamos aos passos:
1. Altere as seguintes propriedades desta janela:
1.1. BorderStyle - bsNone - A borda em volta da janela, incluindo a tarja azul desapareça.
1.2. Name - F_Splash.
1.3. Position - poScreenCenter - A janela aparecerá centralizada no vídeo.

2. Na Component Pallete localize uma página chamada Additional e dentro dessa página de um clique no
objeto Image (acredito que seja o sexto) e dê um clique no Form, foi criado tipo um painel pontilhado no
formulário. Altere as seguinte propriedades:
2.1. Picture - clique nos ... clique no botão Load e localize o arquivo IMGGER.BMP (enviado)
2.2. Transparent - True - Isso fará com que a cor da posição 0,0 seja a base para que a imagem
fique transparente, então dentro da imagem aonde tiver cor semelhante ficará transparente.

3. Na Component Pallete localize uma página chamada Standard e dentro dessa página de um clique no
objeto Label (acredito que seja o terceiro) e dê um clique no Form. Altere as seguinte propriedades:
3.1. Caption - Produzido por ...
3.2. Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Negrito
Tamanho: 10
3.2. Transparent - True - Isso fará com que a cor de fundo do objeto Label fique transparente.

Prontinho de uma comparada e veja como ficou, agora salve esse formulário com o nome de
fSplash, já temos agora em nosso projeto a nossa Splash Screen mas ainda falta um pequeno toque, clique no
formulário e selecione o evento OnCreate, dê um duplo clique neste evento e digite o seguinte comando:

procedure TF_Splash.FormCreate(Sender: TObject);


begin
Brush.Style := bsClear;
end;

Este simples comando produzido no evento de criação fará com que todo o formulário fique também
transparente, então na verdade dentro da nossa Splash só aparecerá a Imagem e o Label, agora precisamos
chamá-la do nosso sistema.

☞Importante - Peço por favor a maior atenção para o próximo passo pois mecheremos em áreas delicadas
do nosso projeto.

Antes de começarmos deixe-me dizer-lhes uma curiosidade sobre o Pascal, um projeto em Pascal
sempre existe apenas um ÚNICO programa, o resto é tudo UNIDADES de sistema, pensam que estou
mentindo ? Olhem na primeira linha de qualquer formulário, aparecerá escrito UNIT tal, mas aonde então
está o nosso Programa ? Quando você inclui um novo formulário ao projeto, o Delphi se encarrega
automaticamente de criar as chamadas a esta nova Unidade alterando por si só o nosso Programa,
infelizmente ele não tem uma área para fazer isso automaticamente com uma janela Splash então teremos que
colocar na mão.

A partir do menu principal clique em View | Project Source e aí está o nosso único PROGRAM do
sistema todo, ele recebe exatamente o nome do nosso Projeto, vamos as alterações, localize o comando
BEGIN e insira os seguintes comandos:

begin
Application.Initialize;
Application.Title := 'Controle do SPA';
Application.HelpFile := 'Peso.hlp';
F_Splash := TF_Splash.Create(Application);
F_Splash.Show;
F_Splash.Update;
Application.CreateForm(TF_Menu, F_Menu);
Application.Run;
end.

Ou seja com estes três comandos, nos Criaremos a janela de Splash, chamaremos ela (não passando
o controle para ela) e forçaremos sua aparição.

☞Importante - Existem dois comandos para se chamar um Formulário, são eles:


SHOW - Chama o formulário sem passar o controle para ele, ou seja o programa que o chamou ainda
possui o controle da ação.
SHOWMODAL - Chama o formulário passando o controle da ação para ele até que ele seja
finalizado.

Bem, feito isso, agora só falta destruirmos nossa janela quando o sistema começar a execução, você
pode colocar o comando: F_Splash.Free antes do comando Application.Run mas pessoalmente eu prefiro
finalizá-la apenas quando o menu efetivamente for criado, então chame o formulário do Menu e para o evento
OnShow coloque o comando:

procedure TF_Menu.FormShow(Sender: TObject);


begin
F_Splash.Free;
end;

Não se esqueça de logo após a diretiva de compilação acrescentar a utilização da Unidade, desta
maneira:

{$R *.DFM}
uses
fSplash;

Sobre o Sistema
A partir do Menu Principal clique em File | New Form criando um novo formulário que será a nossa
área de trabalho, vamos aos passos:

1. Altere as seguintes propriedades desta janela:


1.1. BorderStyle - bsDialog
1.2. Caption - Sobre o Sistema...
1.3. Name - F_Sobre.
1.4 Position - poScreenCenter - A janela aparecerá centralizada no vídeo.

2. Na Component Pallete localize uma página chamada Standard e dentro dessa página de um clique no
objeto Panel (acredito que seja o último) e dê um clique no Form. Altere as seguinte propriedades:
2.1. BevelInner - bvLowered - Borda interna rebaixada
2.2. BevelOuter - bvRaised - Borda externa levantada
2.3. BevelWidth - 2 - Espessura da borda

☞Importante - Para os tópicos 3 e 4, antes de clicar nos objetos indicados clique primeiramente neste
objeto Panel criado.

3. Na Component Pallete localize uma página chamada Additional e dentro dessa página de um clique no
objeto Image (acredito que seja o sexto) e dê um clique no objeto Panel. Altere as seguinte propriedades:
3.1. Picture - clique em ... clique no botão Load e localize o arquivo IMGICO.BMP (enviado)
3.2. Transparent - True - Isso fará com que a cor da posição 0,0 seja a base para que a imagem
fique transparente, então dentro da imagem aonde tiver cor semelhante ficará transparente.

4. Na Component Pallete localize uma página chamada Standard e dentro dessa página traga três objetos
Label (acredito que seja o terceiro) para dentro do objeto Panel. Altere as seguinte propriedades:
4.1. Objeto Label1:
4.1.1. Caption - Sistema de Controle do SPA
4.1.2. Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Negrito
Tamanho: 10
Cor: Castanho
4.2. Objeto Label2:
4.2.1. Caption - Versão Beta 1
4.2.2. Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Itálico
Tamanho: 8
Cor: Castanho
4.3. Objeto Label3:
4.3.1. Caption - Copyright © Curso Delphi 1998 - Junho
4.3.2. Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Normal
Tamanho: 8
Cor: Castanho

5. Na Component Pallete ainda na página Standard dentro dessa página de um clique no objeto GroupBox
(acredito que seja o décimo segundo) e dê um clique no Form. Altere as seguinte propriedades:
5.1. Caption - Dados Técnicos
5.2. Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Negrito
Tamanho: 8
Cor: Castanho

☞Importante - Para o tópico 6, antes de clicar no objeto indicado clique primeiramente neste objeto
GroupBox criado.

6. Na Component Pallete ainda na página Standard e dentro dessa página traga quinze objetos Label
(acredito que seja o terceiro) para dentro do objeto Panel. Altere as seguinte propriedades:

6.1. Para os primeiros Sete labels (coloque um abaixo do outro) mudando a propriedade Font de
todos para:
Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Normal
Tamanho: 8
Cor: Castanho
E a propriedade Caption para:
Caption do 1: Endereço Internet:
Caption do 2: EMail:
Caption do 3: Versão Windows:
Caption do 4: Versão do DOS:
Caption do 5: CPU:
Caption do 6: Memória Livre:
Caption do 7: Espaço Livre:

6.2. Coloque os próximos Oito labels na frente dos primeiros Sete (deixe o último sobrando) e altere
a propriedade Font de todos para:
Font - clique nos ... e altere as seguintes propriedades:
Fonte: MS Sans Serif
Estilo da Fonte: Normal
Tamanho: 8
Cor: Azul-marinho
A propriedade Name para:
Name do 1: EnderNet
Name do 2: EMail
Name do 3: WinVersion
Name do 4: DOSVersion
Name do 5: CPU
Name do 6: FreeMemory
Name do 7: FreeDisk
Name do 8: FreeResources
Dos dois primeiros objetos altere as seguintes propriedades:
Caption para:
do 1: http://www.geocities.com/SiliconValley/Vista/3144
do 2: fernandoans@geocities.com
Complete a propriedade Font de ambos para:
Efeitos: Sublinhado
Cursor de ambos para:
crUpArrow
7. Finalmente na Component Pallete localize uma página chamada Additional e dentro dessa página de um
clique no objeto BitBtn (acredito que seja o primeiro) e dê um clique no form. Altere as seguinte
propriedades:
7.1. Kind - bkOK, isto trocará também as propriedades: Caption, Glyph e ModalResult.

Compare agora como ficou a janela Sobre o Sistema


Iniciando o programa da Sobre o Sistema
Notou que colocaremos algumas informações bem sofisticadas tais como Versão do Windows e
DOS entre outras, mas vamos com calma, inicialmente clique no objeto EnderNet e para o evento OnClick
insira o seguinte código:

procedure TF_Sobre.EnderNETClick(Sender: TObject);


const
pEnderNET = 'http://www.geocities.com/SiliconValley/Vista/3144';
begin
{$ifdef win32}
ShellExecute(Handle, 'open', pEnderNET, nil, nil, SW_SHOW);
{$endif}
end;

Este código fará com que seja executado um comando via API para uma chamada ao OLE para
iniciar o Browser de Internet corrente com o comando a home-page especificada, as diretivas de compilação
são para assegurar que o comando só seja executado em ambiente Win32. Clique agora no objeto EMail e
para o evento OnClick insira o seguinte código:

procedure TF_Sobre.EMailClick(Sender: TObject);


const
pEMail = 'mailto:fernandoans@geocities.com';
begin
{$ifdef win32}
ShellExecute(Handle, 'open', pEMail, nil, nil, SW_SHOW);
{$endif}
end;

Novamente é realizado um comando via API para uma chamada ao OLE desta vez para iniciar o
servidor de eMail corrente criando uma nova correspondência para o endereço eMail especificado. Clique
agora no objeto F_Sobre e para o evento OnShow insira o seguinte código:

procedure TF_Sobre.FormShow(Sender: TObject);


var
OsInfo: TOSVERSIONINFO;
SysInfo: TSYSTEMINFO;
MemStat: TMEMORYSTATUS;
DiskNo: Integer;
begin
OsInfo.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO);
GetVersionEx(OsInfo);
// Versão do Windows
case OsInfo.dwPlatformId of
VER_PLATFORM_WIN32s : WinVersion.Caption := 'Windows 3.1';
VER_PLATFORM_WIN32_WINDOWS : WinVersion.Caption := 'Windows 95';
VER_PLATFORM_WIN32_NT : WinVersion.Caption := 'Windows NT';
end;
// Versão do DOS
DosVersion.Caption := format('%d.%d Ver : %d',
[OsInfo.dwMajorVersion,OsInfo.dwMinorVersion,LOWORD(OsInfo.dwBuildNumber)]);
// Pega o processador
GetSystemInfo(SysInfo);
case SysInfo.dwProcessorType of
PROCESSOR_INTEL_860 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Intel
8086']);
PROCESSOR_INTEL_386 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Intel
80386']);
PROCESSOR_INTEL_486 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Intel
80486']);
PROCESSOR_INTEL_PENTIUM : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors,
'Intel Pentium']);
PROCESSOR_MIPS_R2000 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'MIPS
R2000']);
PROCESSOR_MIPS_R3000 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'MIPS
R3000']);
PROCESSOR_MIPS_R4000 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'MIPS
R4000']);
PROCESSOR_ALPHA_21064 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors,
'ALPHA 21064']);
PROCESSOR_PPC_601 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Power PC
601']);
PROCESSOR_PPC_603 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Power PC
603']);
PROCESSOR_PPC_604 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Power PC
604']);
PROCESSOR_PPC_620 : CPU.Caption := format('%d %s',[SysInfo.dwNumberOfProcessors, 'Power PC
620']);
end;
MemStat.dwLength := sizeof(TMEMORYSTATUS);
GlobalMemoryStatus(MemStat);
// Memória Livre
FreeMemory.Caption := format('Tot: %d KB Disp: %d KB',
[Trunc(MemStat.dwAvailPhys/1024),Trunc(MemStat.dwTotalPhys/1024)]);
// Recursos livres
DiskNo := 3;
FreeDisk.Caption := '';
FreeResources.Caption := '';
repeat
if DiskNo < 7 then
FreeDisk.Caption := FreeDisk.Caption + format('%s: %d MB ',
[Chr(DiskNo + Ord('A')- 1),Trunc(DiskFree(DiskNo)/1024/1024)])
else
FreeResources.Caption := FreeResources.Caption + format('%s: %d MB ',
[Chr(DiskNo + Ord('A')- 1),Trunc(DiskFree(DiskNo)/1024/1024)]);
inc(DiskNo);
until DiskFree(DiskNo)=-1;
end;

Basicamente são todos comandos API que fazem chamadas ao Windows solicitando as informações
necessárias, apenas perderia tempo explicando comando a comando quando seria muito mais proveitoso que
você consulte o Help e verifique os comandos utilizados para fazer as capturas, uma pequena observação,
note que para capturar o processador me utilizei de determinadas constantes para facilitar o entendimento,
elas devem então serem criadas, localize o comando VAR e entre este comando e o comando End de
finalização do comando Type crie as seguintes constantes:

public
{ Public declarations }
end;

const
PROCESSOR_INTEL_860 = 860;
PROCESSOR_INTEL_386 = 386;
PROCESSOR_INTEL_486 = 486;
PROCESSOR_INTEL_PENTIUM = 586;
PROCESSOR_MIPS_R2000 = 2000;
PROCESSOR_MIPS_R3000 = 3000;
PROCESSOR_MIPS_R4000 = 4000;
PROCESSOR_ALPHA_21064 = 21064;
PROCESSOR_PPC_601 = 601;
PROCESSOR_PPC_603 = 603;
PROCESSOR_PPC_604 = 604;
PROCESSOR_PPC_620 = 620;

var
F_Sobre: TF_Sobre;

Para que todos os comandos API funcionem precisamos ainda disponibilizar a utilização da
Unidade: ShellAPI, coloque então a declação dela no comando USES perto do comando INTERFACE.

Pronto, agora basta chamarmos novamente nosso formulário que contém o Menu e chamarmos a
janela do Sobre para tanto chame o formulário, clique em Auxílio | Sobre o Sistema e insira os seguintes
códigos:

procedure TF_Menu.SobreoSistema1Click(Sender: TObject);


begin
F_Sobre := Tf_Sobre.Create(Application);
F_Sobre.ShowModal;
F_Sobre.Free;
end;

Não se esqueça de logo após a diretiva de compilação acrescentar a utilização desta nova Unidade,
desta maneira:

{$R *.DFM}
uses
fSplash, fSobre;

Nota Importante: Note que para o formulário fMenu eu criei um novo comando USES enquanto que no
formulário do fSobre eu apenas acrescentei no USES já existente, existe uma grande diferença entre ambos,
no primeiro caso as unidades fSplash e fSobre não estão com os endereços fixados na área de memória no
momento da criação do formulário, no segundo caso todas as unidades inclusive a ShellApi estão com os
endereços de memória reservado assim que o formulário é criado.

Retirando os formulários da Área de Memória


Falando em áreas de memória, os formulários só devem ser criados (a excessão óbvia do fMenu)
quando o usuário necessitar deles, ou seja, se o usuário que chamar o FSobre então o sistema deve criá-lo,
chamá-lo e depois removê-lo completamente da área de memória, isto é feito pois o Delphi se utiliza da área
de memória baixa para manter os endereços do objetos criados, ou seja o Delphi faz uso dos 640 Kb desta
memória, então não adianta ter um Pentium com 64 Megas de memória, pois o disponível para execução dos
formulário é apenas aquela taxa de 640 Kb, e deve ser muito menos, pois o Windows também utiliza ela, e
outros aplicativos também.

Precisamos então aliviar o máximo esta área, para isso no Menu Principal clique em Project |
Options... na folha Forms selecione F_Splash e F_Sobre e clique no botão > mandando ambas para a área
dos Avaliable Forms isto será feito com todas as outras janelas a exceção da DModelo que será o nosso
DataModule.

Finalmente
Pode executar o sistema e apreciar a propaganda da Splash e da Sobre, novamente digo não se
preocupe com a rapidez que a janela Splash vai aparecer, quanto mais inserirmos no sistema mais demorado
esta janela ficará.

Na próxima apostila, vamos discutir o assunto de como juntar todas as nossas regras de negócio num
único e simples DATA MODULE.
10 Curso de Delphi 4.0 - Apostila 10

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• BASICO.MDB

Prefácio
Salve, nesta apostila desvendaremos a utilização dos Data Modules.

Os Data Modules não são um bicho de sete cabeças, na verdade ele tem oito e mais uma que vive
escondida esperando para te dar aquela dentada. Mas, você verá é que depois de domesticado ele se torna um
fiel e amável bichinho de nove cabeças, você deve é tomar cuidado para não cortar nenhuma delas pois
sempre nascem mais duas no lugar.

Primeira Cabeça - Quando nasceu


Os Data Modules surgiram a partir do Delphi 2.0, então não adianta você ficar procurando naquela
sua antiga versão de Delphi 1.0, com a necessidade de organizar os formulários, pois ficava aquele monte de
objetos invisíveis em tempo de execução tipo tTable, tDataSource e tQuery perdidos, fora que você sempre
tinha que definir em dois formulários diferentes a mesma tabela, os mesmos campos, as mesmas ligações, isto
gastava tempo e muito espaço do sistema.

Segunda Cabeça - Invisibilidade


Os Data Modules são parentes primários dos formulários, eles são uma espécie de "Nehandertal"
dos formulários, não são visíveis em tempo de execução, então não adianta tentar dar um comando do tipo
Show para mostrá-los pois todos são envergonhados e detestam aparecer, eles só servem para uma única
função controlar e armazenar objetos invisíveis como eles, então não tente colocar um tEdit ou um tImage
dentro deles que eles não deixarão.

Outra característica dos Data Modules é que eles adoram ser criados automaticamente, quando os
tiramos daquela área dos Auto-Create Forms eles simplesmente somem do projeto, você pode até ficar
criando os Data Modules na mão, dando aqueles comandos de criação, mas em todo o nosso projeto será
apenas um único Data Module, então além do Menu deixe-o quietinho na área dos Auto-Create.

Terceira Cabeça - Relação Data Module X Formulário


É possível criar um Data Module para cada formulário, mas este não é o objetivo para o qual eles
foram criados, a maneira mais racional de se trabalhar com eles é criar um único Data Module abrigando
todas as tabelas, montando as regras de negócio, criando e definindo os campos das tabelas além de outros
objetos invisíveis que o sistema poderá a necessitar.

O Data Module é um espécie de armazém do nosso sistema, guarde nele tudo o que for globalmente
usado, como por exemplo variáveis, funções ou procedimentos basta apenas definí-los em sua área Public e
depois declarar o Data Module no comando Uses da nossa unidade.

Quarta Cabeça - Criando a 1a. Conexão


Vamos começar nosso desenvolvimento criando o Banco de Dados que abrigará o nossas tabelas do
sistema, pegue novamente a Apostila 7 e veja como ficou o nosso Banco de Dados e crie-o com o MS-
Access 97 (ou então utilize o MBD enviado) o nome do nosso banco será BASICO.MDB, na Apostila 2
mostrei como se cria um Alias, precisamos criar outro para este sistema. Abra o aplicativo BDE
Administrator para criar o Alias para o Banco de Dados enviado.

1. A partir do BDE Administrator aberto vá em Object | New... (ou simplesmente CTRL+N) e modifique a
janelinha que aparece para o Database Driver Name para MSACCESS e pressione a tecla OK.

2. Mude o nome do seu novo alias para AlPeso.

3. Altere a propriedade DATABASE NAME para C:\CursoDelphi\Peso\basico.mdb e confirme as


alterações em Object | Apply (ou simplesmente CTRL+A, ou ainda clique no quarto botão da barra de
ferramentas).

4. Teste seu novo alias clicando em Object | Open seu alias deve formar um quadradinho luminoso em volta
do objeto.

5. Feche-o em em Object | Close.

Volte para o Delphi e reabra novamente o projeto PESO.DPR, a partir do Menu Principal clique em
File | New Data Module criando a seguinte janela:

Altere a propriedade Name para D_Modelo e salve o Data Module com o nome de dModelo.

Na Component Pallete localize uma página chamada DataAccess e dentro dessa página de um
clique no objeto DataBase (acredito que seja o quinto) e dê um clique dentro do Data Module criado. Altere
as seguinte propriedades:
AliasName - AlPeso - Nome do Alias de Conexão
DataBase Name - DNmPeso - Nome da Base de Dados Interna
Name - PrjPeso - Nome do Objeto

Quinta Cabeça - Criando a 2a. Conexão


Vamos agora criar toda a nossa regra de negócio, ou seja, vamos criar todos os objetos tDataBase,
tTable, tQuery e quaiquer outro que necessitaremos e que utilizaremos ao longo de todo esse projeto e qual a
forma como as tabelas se relacionam.

Na Component Pallete ainda uma página chamada DataAccess e dentro dessa página traga nove
objetos Table (acredito que seja o segundo), um objeto DataSource (acredito que seja o primeiro) e um
objeto Query (acredito que seja o terceiro). Altere as seguinte propriedades:

Para os objetos Tables e Query altere a propriedade DataBaseName para DNmPeso

Para os objetos Tables altere as propriedades TableName, Name e IndexFieldName


respectivamente:

TableName Name IndexFieldName


Alimento tbAlimento COD_ALIMENTO
Cidade tbCidade SIG_CIDADE
Cliente tbCliente NUM_CPF
Grupo tbGrupo NUM_GRUPO
Pasta_Cliente tbPasta_Cliente NUM_CPF;DAT_CORRENTE
Peso_Cliente tbPeso_Cliente NUM_CPF;DAT_MEDIDO
Resumo_Mensal tbResumo_Mensal ANO_MES
Telefone_Cliente tbTelefone_Cliente NUM_CPF;NUM_TELEFONE

Para o objeto DataSource altere as propriedades:


DataSet - tbCliente
Name - DsCliente

Para o objeto tbTelefone_Cliente altere as propriedades:


MasterSource - DsCliente
MasterFields - NUM_CPF
Isto fará com que esta tabela automaticamente se relacionem com a tabela de Cliente através do
campo chave NUM_CPF, o mesmo será colocado automaticamente quando de uma inclusão, mantendo assim
a integridade referencial com este.

Altere a propriedade Name do objeto Query1 para QrySql

Prontinho, deve ter ficado algo parecido com isso:

Sétima Cabeça - Criando os campos


Uma coisa prática que podemos fazer é a definição dos campos de cada tabela, isto servirá para que
quando mostremos esta tabela através de um objeto dbGrid o Delphi o trate pelo nome que desejamos e não
como NUM_CPF por exemplo, outra parte interessante é que aqui podemos definir as máscaras para os
campos.

Para criar os objetos fields, dê um duplo clique em cima de qualquer tabela e aparecerá a janela
Definition Fields, clique com o botão direito nela e aparecerá o menu popup conforme a figura a seguir:

Clique em Add fields... e clique no botão OK para inserir todos os campos, vou agora descrever
campo a campo de cada tabela e as propriedades que devem ser trocadas, cabe a você entrar em tabela a tabela
e ir criando e alterando os campos:

Tabela Campo DisplayLabel EditMask


Currency

tbAlimento COD_ALIMENTO Código


tbAlimento NUM_GRUPO Núm Grupo >a;0;_
tbAlimento NOM_ALIMENTO Nome
tbAlimento QTD_PERMITIDA Qtd Permitida
tbResumo_Mensal ANO_MES Ano e Mês 9999\/99;0;_
tbResumo_Mensal VAL_MEDICO Valor Médico
True
tbResumo_Mensal VAL_COORDENADOR Valor Coordenador
True
tbResumo_Mensal VAL_NUTRICIONISTA Valor Nutricionista
True
tbResumo_Mensal VAL_DESPESA Valor Despesa
True
tbCliente NUM_CPF CPF Cliente 000\.000\.000\/00;0;_
tbCliente SIG_CIDADE Sigla da Cidade >aaa;0;_
tbCliente NOM_CLIENTE Nome
tbCliente END_CLIENTE Endereço
tbCliente BAI_CLIENTE Bairro
tbCliente CEP_CLIENTE CEP 00\.000\-000;0;_
tbCliente DES_EMAIL eMail
tbCliente ALT_CLIENTE Altura (Cm)
tbCliente DAT_NASCIMENTO Data de Nascimento !99/99/0000;1;_
tbGrupo NUM_GRUPO Número >a;0;_
tbGrupo DES_GRUPO Descrição
tbTelefone_Cliente NUM_CPF CPF Cliente 000\.000\.000\/00;0;_
tbTelefone_Cliente NUM_TELEFONE Núm Telefone \(0000\) 000\-0000;0;_
tbTelefone_Cliente DES_FUNCAO Função
tbPasta_Cliente NUM_CPF CPF Cliente 000\.000\.000\/00;0;_
tbPasta_Cliente DAT_CORRENTE Data Corrente !99/99/0000;1;_
tbPasta_Cliente PLN_ADOTADO Plano Adotado >a;0;_
tbPasta_Cliente QTD_CALORIA Qtd Calorias 0000;0;_
tbPasta_Cliente OBS_PASTA Observações
tbPasta_Cliente DAT_PAGAMENTO Data Pagamento !99/99/0000;1;_
tbPasta_Cliente VAL_TOTAL Valor Total
True
tbPasta_Cliente VAL_DESCONTO Valor Desconto
True
tbCidade SIG_CIDADE Sigla >aaa;0;_
tbCidade NOM_CIDADE Nome
tbCidade SIG_UF UF >AA;0;_
tbPeso_Cliente NUM_CPF CPF Cliente 000\.000\.000\/00;0;_
tbPeso_Cliente DAT_MEDIDO Data Medição !99/99/0000;1;_
tbPeso_Cliente PES_MEDIDO Peso Medido

Oitava Cabeça - Coficando a entrada das tabelas


Um grande problema que existe quando se troca de bancos de dados em sistemas com o Delphi é
quanto ao nome das tabelas, quem já tentou por exemplo mudar do Paradox para o Oracle viu que nem por
mais cuidado se tome sempre acaba tropeçando nos chamados Domínios do Oracle, que são iniciais
automáticas que ele coloca para definir quem é o dono das tabelas. O problema uma mudança de nome em
qualquer ponto pode ser desastroso, e isso não se limita apenas ao Oracle serve para qualquer outra migração
de base de dados, para evitar este pequeno problema, vamos adotar em nosso sistema oito variáveis globais,
cada uma contendo e carregando consigo o nome da tabela.

Outra coisa que precisamos controlar é a entrada do sistema, verificarmos se foi feito a conexão
corretamente entre o objeto TDataBase e o Alias para ambas:

1. Alterne para o Code Editor e localize a seguinte porção do código:

private
{ Private declarations }
public
{ Public declarations }

e coloque o seguinte:

private
{ Private declarations }
public
nmAlimento, nmCidade, nmGrupo, nmPasta_Cliente, nmPeso_Cliente, //
nmResumo_Mensal, nmTelefone_Cliente, nmCliente : String;
end;

2. Selecione o objeto D_Modelo e para o evento OnCreate insira o seguinte código:

procedure TD_Modelo.D_ModeloCreate(Sender: TObject);


var
Conexao : Boolean;
begin
// Atribui os nomes externos as variáveis
nmAlimento := 'ALIMENTO';
nmCidade := 'CIDADE';
nmGrupo := 'GRUPO';
nmPasta_Cliente := 'PASTA_CLIENTE';
nmPeso_Cliente := 'PESO_CLIENTE';
nmResumo_Mensal := 'RESUMO_MENSAL';
nmTelefone_Cliente := 'TELEFONE_CLIENTE';
nmCliente := 'CLIENTE';
// Atribui os nomes das variáveis aos nomes das tabelas
tbAlimento.TableName := nmAlimento;
tbCidade.TableName := nmCidade;
tbGrupo.TableName := nmGrupo;
tbPasta_Cliente.TableName := nmPasta_Cliente;
tbPeso_Cliente.TableName := nmPeso_Cliente;
tbResumo_Mensal.TableName := nmResumo_Mensal;
tbTelefone_Cliente.TableName := nmTelefone_Cliente;
tbCliente.TableName := nmCliente;
// Testa a conexão
try
PrjPeso.Connected := True;
if not PrjPeso.IsSQLBased then
PrjPesoLogin(PrjPeso, nil);
Conexao := True;
except
MessageDlg('Erro na Conexão do Banco de Dados', mtError, [MbOk], 0);
Conexao := False;
end;
if not conexao then begin
MessageDlg('Sistema cancelado...', mtError, [MbOk], 0);
Application.Terminate;
end;
end;

3. Selecione o objeto PrjPeso e para o evento OnLogin insira o seguinte código:

procedure TD_Modelo.PrjPesoLogin(Database: TDatabase; LoginParams: TStrings);


begin
LoginParams.Values['USER NAME'] := '';
LoginParams.Values['PASSWORD'] := '';
end;

4. Para terminar a conexão, quando o sistema for encerrado, selecione o objeto D_Modelo e para o evento
OnDestroy insira o seguinte código:

procedure TD_Modelo.D_ModeloDestroy(Sender: TObject);


begin
PrjPeso.Connected := False;
end;

Nona Cabeça - Funções Particulares e as regras de negócio


Todas as amarrações que normalmente são definidas por DBA do banco de dados, criando Stored
Procedures e Triggers para a administração do banco podem ser reproduzidas perfeitamente aqui, vou citar
alguns exemplos e você terá uma boa base para criar outras que serão necessários aos seus sistemas.
Já falei antes e vou repetir agora, não sou muito fã de campos do tipo AutoIncremento, primeiro
porque não são todos os bancos que os implementam e segundo porque não sou eu quem o controla, assim já
que não posso arrumá-lo ou liberá-lo quando desejar, não posso criar meu próprio passo e inúmeras outras
coisas, isto em bancos complexos é realizado criando Stored Procedures, procedimentos prontos em
linguagens SQL que são chamados em determinados momentos, mas estamos utilizando o MS-Access aqui, e
amanhã podemos usar o Oracle no dia seguinte o InterBase imagine o tempo que ficariamos com o sistema
parado nas famosas ADAPTAÇÕES.

Para gerar um número automático para um campo qualquer precisamos apenas seguir os seguintes
passos:

1. Crie uma chamada a uma função particular:

private
function Maximo(nmCampo, nmTabela: String) : integer;
public

2. Crie a função:

function TD_Modelo.Maximo(nmCampo, nmTabela: String) : integer;


begin
with QrySQL do begin
if Active then Close;
SQL.Clear;
SQL.ADD('SELECT MAX(' + NmCampo + ') FROM');
SQL.ADD(NmTabela);
Open;
result := Fields[0].AsInteger + 1;
Close;
end;
end;

3. Para o evento AfterInsert do objeto tbAlimento coloque a seguinte codificação:

procedure TD_Modelo.tbAlimentoAfterInsert(DataSet: TDataSet);


begin
tbAlimentoCOD_ALIMENTO.AsInteger := Maximo('COD_ALIMENTO',nmAlimento);
end;

Resolvido as crises com os números automáticos, a função recebe como parâmetro o nome do campo
inteiro e o nome da tabela, então ela simplesmente monta uma cláusula SQL para procurar o maior valor
daquele campo dentro da tabela e depois simplesmente soma mais um e devolve este resultado aonde o
mesmo é jogado direto para o campo.

Outras funções particulares que podemos colocar são para os eventos OnPostError e
OnDeleteError para controlar falhas na gravação e ao invés de recebermos aquelas amigáveis mensagens
binárias hexadecimais $FFFFFFF para a alegria e desespero do nosso usuário, aparecer controladamente algo
mais agradável, então siga os passos:

1. Alterne para o Code Editor e defina os seguintes procedimentos antes da cláusula Private

procedure TabelaErroPost(DataSet:TDataSet; E: EDataBaseError; var Action: TDataAction);


procedure TabelaErroDelete(DataSet:TDataSet; E: EDataBaseError; var Action: TDataAction);
private
2. Codifique agora os procedimentos:

// Controla os Erros de Gravação coloque no Evento onPostError de todas as Tabelas


procedure TD_Modelo.TabelaErroPost(DataSet:TDataSet; E: EDataBaseError; var Action: TDataAction);
begin
if (E is EDBEngineError) then begin
MessageDlg('Impossível gravação: Provavelmente Registro Duplicado', mtWarning, [mbOk], 0);
Abort;
end;
end;

// Controla os Erros de Exclusão coloque no Evento onDeleteError de todas as Tabelas


procedure TD_Modelo.TabelaErroDelete(DataSet:TDataSet; E: EDataBaseError; var Action: TDataAction);
begin
if (E is EDBEngineError) then begin
MessageDlg('Impossível excluir: Provavelmente Registros Associados', mtWarning, [mbOk], 0);
Abort;
end;
end;

3. Selecione todas as tabelas e para o evento OnPostError selecione (através da seta, não dê duplo clique) o
procedimento TabelaErroPost e para o evento OnDeleteError selecione o procedimento
TabelaErroDelete.

Estes procedimentos foram criados para receberem os mesmos parâmetros do procedimento original
ou seja, o DataSet vinculado, o código do erro e a ação a tomar, então basta simplesmente verificarmos se o
código do erro é um EDBEngineError ou seja um erro de banco, darmos a nossa mensagem controlada e
abortarmos o processo de gravação ou eliminação.

Para as regras de negócio contamos com o evento OnValidate que cada campo separadamente
possui, vou citar aqui uma das mais importantes regras:

• Existem duas divisões entre 21 - 55 e 55 - 74 anos;


• Excluem-se clientes menores de 21 e maiores de 74 anos;

Isto é uma regra que o banco deve cumprir, normalmente isto é feito através do que chamamos de
Triggers de banco (Gatilhos), mas esses "Gatilhos" variam muito de banco para banco, então pessoalmente
prefiro colocá-los no Delphi pois assim permito a maleabilidade dos diversos bancos, vamos então
implementar esta regra:

1. Dê um duplo clique na tabela de cliente, e selecione o campo DAT_NASCIMENTO.

2. Altere a propriedade Required para True, isto fará com que o campo tenha que ser preenchido
obrigatoriamente.

3. Chame o evento OnValidate e insira os seguintes procedimentos:

procedure TD_Modelo.tbClienteDAT_NASCIMENTOValidate(Sender: TField);


var
Idade: Integer;
begin
Idade := StrToInt(FormatDateTime('YY',Now - tbClienteDAT_NASCIMENTO.AsDateTime));
if (Idade < 21) or (Idade > 74) then
raise Exception.Create('Este Cliente está com a idade fora da faixa');
end;
Criamos uma variável inteira aonde será calculado quantos anos este cliente possui, para isso,
utilizamos a função FormatDateTime que devolve uma data com base de uma máscara formatada, isso vale
para:

Especificação Mostra
c A data que usa o formato dada pelo ShortDateFormat variável global, seguiu até que usasse
o formato dado pelo LongTimeFormat variável global. O tempo não é exibido se a parte
fracionária do valor do DateTime é zero.
d O dia como um número sem um zero principal (1-31).
dd O dia como um número com um zero principal (01-31).
ddd O dia como uma abreviação (Sun-Sat) usando a string ShortDayNames que é uma variável
global.
dddd Exibe o dia como um nome cheio (Sunday-Saturday) usando a string LongDayNames que é
uma variável global.
ddddd A data usando a string ShortDateFormat que é uma variável global.
dddddd A data usando a string LongDateFormat que é uma variável global.
m O mês como um número sem um zero principal (1-12). Se a especificação de m segue um h
ou especificar de hh imediatamente, então será exibido o minuto em lugar do mês.
mm O mês como um número com um zero principal (01-12). Se a especificação de mm segue
um h ou especificar um hh imediatamente, o minuto em lugar do mês é exibido.
mmm O mês como uma abreviação (Jan-Dec) usando a string ShortMonthNames que é uma
variável global.
mmmm O mês como um nome cheio (January-December) usando a string LongMonthNamesque é
uma variável global.
yy O ano como um número de dois-dígito (00-99).
yyyy O ano como um número de quatro-dígito (0000-9999).
h Displays a hora sem um zero principal (0-23).
hh A hora com um zero principal (00-23).
n O minuto sem um zero principal (0-59).
nn O minuto com um zero principal (00-59).
s O segundo sem um zero principal (0-59).
ss O segundo com um zero principal (00-59).
t O tempo que usa o formato dado pela variável global ShortTimeFormat.
tt Exibe o tempo que usa o formato dado pela variável global LongTimeFormat.
am/pm Usa a notação Hora-12 do relógio para o h precedendo ou especificado de hh, e exibições '
am' durante qualquer hora antes de meio-dia, e ' pm' durante qualquer hora depois de meio-dia.
A especificação pode ser usado em minúscula (am/pm), caso contrário (AM/PM), ou
misturado (Am/Pm) o resultado será exibido de acordo.
a/p Usa a notação Hora-12 do relógio para o h precedendo ou especificado de hh, e exibições ' a'
durante qualquer hora antes de meio-dia, e ' p' durante qualquer hora depois de meio-dia. A
especificação pode ser usado em minúscula (a/p), caso contrário (A/P), ou misturado (A/p) o
resultado será exibido de acordo.
ampm Usa a notação Hora-12 do relógio para o h precedendo ou specifier de hh, e exibições os
conteúdos da variável global TimeAMString durante qualquer hora antes de meio-dia, e os
conteúdos da variável global TimePMString durante qualquer hora depois de meio-dia.
/ Exibe o carácter separador de data dado pela variável global DateSeparator.
: Exibe o carácter separador de tempo dado pela variável global TimeSeparator.
"xx" Carácter incluídos em plicks ( ' ) ou aspas ( " ) não afetam o formato.

Coloquei esta tabela, que pode ser encontrada no tópico do auxílio da função FormatDateTime
apenas para que você não se esqueça o quão útil pode ser esta função no tratamento de Datas. O cálculo para
a idade é feito da seguinte maneira, pegamos a data atual e subtraimos pela data de nascimento o resultado é
convertido em anos pela função, depois basta apenas questionarmos se o valor está fora da faixa especificada.

Outro tipo de Regra de Negócio que podemos aplicar e quanto a entrada padrão de determinados
campos, supomos que queremos que toda vez que for dada a entrada dos campos na tabela Pasta do Cliente
os campos Plano Adotado receba o Plano A, Quantidade de Calorias receba 800 KCal e Data Corrente
receba a Data Atual, esta Regra também pode ser determinada por certos bancos, mas para realizá-la no
Delphi fazemos:

1. Selecione o objeto tbPasta_Cliente.

2. Para o evento onAfterInsert (depois de ser dado o comando Insert) coloque os seguintes códigos:

procedure TD_Modelo.tbPasta_ClienteAfterInsert(DataSet: TDataSet);


begin
with tbPasta_Cliente do begin
FieldByName('PLN_ADOTADO').AsString := 'A';
FieldByName('QTD_CALORIA').AsString := '0800';
FieldByName('DAT_CORRENTE').AsDateTime := Now;
end;
end;

Acredito que não precisa de muita explicação para o que fiz, apenas mandei os valores especicados
para cada campo. Estas regras podem ser aplicadas na medida que você precise delas, não precisando de
bancos complexos como Oracle, MS-SQL ou Interbase entre outros, para obtê-las.

Finalmente
Ao longo deste projeto ainda voltaremos por aqui para incluirmos novas funcionalidades globais,
mas acredito que já deu para você perceber a utilíssima ferramenta que são os Data Modules. Na próxima
apostila, nosso assunto será de construir os formulários que cadastrarão as tabelas básicas do sistema, ou seja,
começaremos a construir nossas telas de entradas.
11 Curso de Delphi 4.0 - Apostila 11

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• OBJETOS.WRI
• POO.WRI

• Seguintes Objetos :
• DgFiltro
• DgPrint
• SelectT
• PosEstad

• Seguintes Imagens :
• ImgAnterior.BMP ImgFiltra.BMP ImgMarca.BMP
• ImgAvanca.BMP ImgFormCons.BMP ImgPrimeiro.BMP
• ImgGrava.BMP ImgTabela.BMP ImgAvancaSalto.BMP
• ImgCancela.BMP ImgImprime.BMP ImgUltimo.BMP
• ImgDesFiltro.BMP ImgInsere.BMP ImgFicha.BMP
• ImgDuplFicha.BMP ImgInsLote.BMP ImgVaiMarca.BMP
• ImgElimina.BMP ImgLocaliza.BMP ImgVoltaSalto.BMP
• ImgEnviaArea.BMP

Prefácio
Salve, nesta apostila desvendaremos a primeira parte de como criar os cadastros. Mas antes de
começarmos deixe-me explicar porque suspendi o curso durante o mês de Agosto.

Todo o curso foi reformulado, tanto o ambiente como a linguagem, e aviso que isto sempre vai
acontecer, porque sempre que pensei em lançar um curso deste nível também sempre desejei que as pessoas
pudessem aprender o que existe de mais moderno sem ficar preso a uma linguagem ou ambiente antigo e
morto, então não quero nem vou ficar esperando concluir ou terminar um módulo para mudar. Aconselho que
você sempre se mantenha sempre atualizado em relação ao Delphi, ao ambiente Windows e ao Gerenciador
de Banco de Dados MS-Access.

☞ Importante - Junto com esta estou disponibilizando na parte de Objetos um manual e todos os objetos
necessários que iremos utilizar a partir de agora, então antes que você começe a desenvolver nesta apostila
aconselho que você baixe e dê uma lida neste manual, instale e verifique a utilidade dos objetos
disponibilizados, e também estou disponibilizando o Apêndice C para que você aprenda e compreenda mais
um pouco sobre a linguagem Object Pascal.
Começando e Criando o Pai de Todos
Em Orientação a Objetos a palavra-chave é Reaproveitamento, e isto é conseguido facilmente
através da Herança dos Objetos primeiramente se ninguém nunca disse isso a você então vou ter a honra de
falar primeiro, tudo no Delphi são objetos, inclusive e principalmente os formulários, eles são tratados como
qualquer outro objeto, então existe a propriedade Herança para o reaproveitamento dos formulários, para não
complicar muito esta apostila será dividida em duas partes (você verá que mesmo dividindo esta apostila em
dois ela é bastante extensa).

Neste primeiro momento criaremos o pano de fundo para todos os nossos cadastros, não pense que
vai ser simples, pois em 17 anos programando mudei várias vezes minhas telas de cadastro desde que
trabalhava com linguagens do tipo Natural e Cobol, venho aprimorando minhas telas, até que finalmente,
graças a uma olhada num sistema me apaixonei logo de cara na tela de cadastro, mais pela simplicidade do
que pelo número de funções fiz algumas mudanças e consegui chegar a uma tela de cadastro que julgo a ideal.
Sendo simples e ao mesmo tempo complexa em número de utilidade que ela disponibiliza para o usuário.

Para diminuir um pouco, ou se você prefere, para não assustar muito ao usuário dividi a parte central
da tela em três partes:

1a. Parte. Mostra os dados em forma de uma FICHA, é como se o usuário estivesse navegando em uma
gaveta dessas de bibliotecas e vasculhando as fichas que ele deseja utilizar, servindo também para incluir ou
alterar qualquer ficha.

2a. Parte. Mostra os dados em forma de uma TABELA aberta ou como a forma de uma Planilha, esta deve
dar a mobilidade necessária para que o usuário possa ver os dados num bloco, de maneira rápida e eficiente.

3a. Parte. Fica a cargo das pesquisas, relações e filtragens o que o usuário quiser fazer para poder visualizar
seus dados da forma como ele julgar melhor.

Criando o Geral
Para começarmos abra o sistema e a partir do Menu Principal clique em File | New Form criando
um novo formulário que será a nossa área de trabalho, vamos aos passos:

1. Altere as seguintes propriedades desta janela:


1.1. BorderStyle - bsDialog - Uma janela diálogo padrão.
1.2. Name - F_Ficha.
1.3. Position - poScreenCenter - A janela aparecerá centralizada no vídeo.

☞Importante - salve o formulário com o nome de fFicha, e de vez em quando vá salvando para não perder
o serviço.

2. Na Component Pallete localize uma página chamada Additional e dentro dessa página de um clique no
objeto BitBtn (prendendo-o com a tecla Shift) e dê cinco cliques no Form, solte o objeto clicando no cursor
reprensentado na Component Pallete, foram criados cinco botões, organize-os do lado esquerdo, um abaixo
do outro deixando um espaço maior entre o quarto e quinto. Altere as seguinte propriedades dos quatro
primeiros:

Glyph Name Caption Hint


1 ImgInsere ButInsert &Insere Inclui uma nova ficha
2 ImgGrava ButPost &Grava Grava as alterações realizadas na ficha
3 ImgCancela ButCancel &Cancela Cancela as alterações realizadas na ficha
4 ImgElimina ButDelete &Elimina Apaga a Ficha corrente
2.1. Para o quinto botão altere a propriedade Kind para bkClose, e altere a propriedade Hint para
Fecha esta janela.
2.2. Altere a propriedade ShowHint de todos para True.

3. Na Component Pallete ainda na página Additional dentro dessa página de um clique no objeto
SpeedButton (prendendo-o com a tecla Shift) e dê dez cliques no Form, solte o objeto, foram criados dez
botões pequenos, dois coloque-os no espaço entre o ButDelete e o BitBtn5 e estique-os para ficarem do
mesmo tamanho, os outros oito organize-os na parte de baixo do formulário. Altere as seguinte propriedades:

Glyph Name Caption Hint


1 ImgInsLote ButFixIns Ins. &Lote Insere um conjunto de fichas
2 ImgDuplFicha ButDupField &Dupl.Ficha Duplica determinada Ficha quando Inserir
3 ImgPrimeiro ButFirst Primeira Ficha
4 ImgVoltaSalto ButRW Volta o Salto das Fichas
5 ImgAnterior ButPrior Ficha Anterior
6 ImgAvanca ButNext Próxima Ficha
7 ImgAvancaSalto ButFF Salta Fichas
8 ImgUltimo ButLast Última Ficha
9 ImgMarca ButMark Marca uma determinada Ficha
10 ImgVaiMarca ButGotoMark Volta para a Ficha marcada

3.1. Altere as seguintes propriedades para os objetos ButFixIns e ButDupField: propriedade


AllowAllUp altere para True e propriedade GroupIndex altere do primeiro para 1 e do segundo para 2.
3.2. Altere a propriedade ShowHint de todos para True.

4. Na Component Pallete ainda na página Additional pegue um objeto chamado Bevel e envolva os objetos
ButMark e ButGotoMark.

5. Se perdeu ? Ok, vamos dar uma olhada para ver como está ficando a janela:

6. Na Component Pallete, na página Data Access clique no objeto DataSource e dê um clique no Form e
altere a propriedade Name para dsVisao.

7. Na Component Pallete, na página Additional clique no objeto PosEstado (Olhe o Manual dos Objetos
para qualquer referencia) e dê um clique no Form bem abaixo do BitBtn5 e altere a propriedade DataSource
para dsVisao e limpe a propriedade Caption.

8. Na Component Pallete, na página Data Controls clique no objeto DBMemo e dê um clique no Form e
altere a propriedade Name para DBMemClip, a propriedade Visible para False e a propriedade DataSource
para dsVisao.

9. Na Component Pallete, na página Standard clique no objeto Memo e dê um clique no Form e altere a
propriedade Name para memClip e a propriedade Visible para False.

10. Na Component Pallete, ainda na página Standard clique no objeto Label e dê um clique no Form
colocando no espaço entre os objetos ButPrior e ButNext e altere a propriedade Caption para Valor Salto.

11. Na Component Pallete, na página Additional clique no objeto MaskEdit e dê um clique no Form
colocando abaixo do objeto Label1e altere as seguintes propriedades
11.1. Name para mskSalto
11.2. EditMask para 099;0;_
11.3. Hint para Defina um valor para o salto das Fichas
11.4. ShowHint para True

Veja como ficou o trabalho até aqui:

Criando o Separador das Partes


Toda essa parte de botões e apenas o acessoramento que servirá para substituir com muito mais
eficiência um padrão adotado desde o Delphi 1.0, a famosa Barra de Navegação, ou seja o objeto
DBNavigator, não quero aqui em momento nenhum falar mal deste objeto, o problema se deu que com o
passar do tempo eu o consegui aprimorar, até torná-lo uma barra com 23 botões e sem querer acabei foi
conseguindo complicar bastante a cabeça dos meus usuários, então resolvi descartá-lo e colocar toda a sua
funcionalidade nesta tela.

☞ Importante - Ainda na terceira parte desta janela criaremos mais alguns botões para completar a barra
que eu tinha desenvolvido, mas você pode notar a ausência do botão Edição ou Alteração, o Delphi permite
entrada direta em modo de Edição, basta que para isto o usuário começe a digitar os dados e depois ou gravar
uma determinada Ficha ou simplesmente começar a navegar os dados, caso ele deseje pode também Cancelar
o processo, veja bem criei esta janela para facilitar a vida do usuário, não para prendê-lo a uma regra ou a um
conjunto, você notará que em momento nenhum desabilito ou habilito qualquer destes botões (a excessão do
butMark e butGotoMark).

Para dividir a tela em três partes utilizei um objeto PageControl associado a figuras para ficar mais
familiar ao usuário, vamos construir este preparatório antes de continuarmos.

12. Na Component Pallete, na página Win32 clique no objeto ImageList e dê um clique no Form, agora dê
um duplo clique em cima do objeto criado para entrarmos no editor da lista de imagens, conforme a figura
abaixo:

12.1. Clique no botão Add... e localize a figura ImgFicha, e clique no botão abrir, ela será a posição
0, insira as imagens ImgTabela e ImgFormCons. Clique no botão OK e saia do editor.

13. Na Component Pallete, ainda na página Win32 clique no objeto PageControl e dê um clique no Form,
acerte-o para ocupar o espaço vazio do formulário e altere a propriedade Images para ImageList1 e a
propriedade Name para PgPrincipal.

14. Clique neste objeto criado com o botão Direito do mouse e escolha a opção NewPage, uma nova página
será criada, altere a propriedade Caption para Ficha e propriedade Name para TabFicha.

15. Novamente clique no objeto PgPrincipal com o botão Direito do mouse e escolha a opção NewPage,
mais uma nova página será criada, altere a propriedade Caption para Tabela e propriedade Name para
TabTabela.

16. Finalmente clique no objeto PgPrincipal com o botão Direito do mouse e escolha a opção NewPage,
mais uma nova página será criada, altere a propriedade Caption para Formas de Consulta e propriedade
Name para TabConsulta.

O resultado de todo este trabalho se mostra na figura a seguir:


☞Importante - Note que os objetos DBMemClip e MemClip ficaram escondidos atrás do objeto
PgPrincipal, isto não tem importância pois quando em modo de execução estes objetos ficarão invisíveis.

Criando a Primeira Parte


Atenção que esta é a parte mais difícil e complicada, você aqui simplesmente não vai fazer nada,
deixe exatamente do jeito que está, utilizaremos esta parte apenas nos formulários que criaremos por herança.

Criando a Segunda Parte


Clique na orelha Tabela dentro do objeto PgPrincipal, o problema em se mostrar os dados de uma
tabela sob a forma de uma planilha é que campos tipo Imagem e campos tipo Texto não aparecem, solucionei
este problema, dividindo esta parte em mais três partes, uma que mostra exclusivamente os dados simples, a
outra apenas para campos tipo Imagem e a última apenas para campos do tipo Texto e vamos ao trabalho:

17. Na Component Pallete, clique na página Win32 clique no objeto PageControl e dê um clique no Form,
e altere a propriedade Align para AlClient e a propriedade Name para PgTabela.

18. Clique neste objeto criado com o botão Direito do mouse e escolha a opção NewPage, uma nova página
será criada, altere a propriedade Caption para Dados e propriedade Name para TabTDados.

19. Dentro desta página na Component Pallete, clique na página Data Controls clique no objeto dbGrid e
dê um clique nesta página, altere as seguintes propriedades:
19.1. Align para AlClient
19.2. Options para
[dgTitles,dgColumnResize,dgColLines,dgRowSelect,dgAlwaysShowSelection]
19.3. DataSource para DsVisao, compare como ficou:
20. Novamente clique no objeto PgTabela com o botão Direito do mouse e escolha a opção NewPage, mais
uma nova página será criada, altere a propriedade Caption para Imagem e propriedade Name para
TabTImagem.

21. Dentro desta página na Component Pallete, clique na página Data Controls clique no objeto dbImage e
dê um clique nesta página, altere a propriedade Align para AlTop e a propriedade DataSource para DsVisao

22. Ainda dentro desta página na Component Pallete, clique na página Standard clique no objeto Label e dê
um clique nesta página, altere a propriedade Caption para Campo e a propriedade Font para Estilo: Negrito
e Cor: Castanho.

23. Ainda dentro desta página na Component Pallete, ainda na página Standard clique no objeto
ComboBox e dê um clique nesta página, altere a propriedade Hint para Selecione o campo a pesquisar, a
propriedade ShowHint para True e a propriedade Name para CbCampoImg.

24. Ainda dentro desta página na Component Pallete, ainda na página Standard traga outro objeto
ComboBox, e altere a propriedade Visible para False e a propriedade Name para CbCampoImgReal,
compare como ficou:

25. Finalmente clique novamente no objeto PgTabela com o botão Direito do mouse e escolha a opção
NewPage, mais uma nova página será criada, altere a propriedade Caption para Texto e propriedade Name
para TabTTexto.

26. Dentro desta página na Component Pallete, clique na página Data Controls clique no objeto dbMemo e
dê um clique nesta página, altere a propriedade Align para AlTop e a propriedade DataSource para DsVisao
27. Ainda dentro desta página na Component Pallete, clique na página Standard clique no objeto Label e dê
um clique nesta página, altere a propriedade Caption para Campo e a propriedade Font para Estilo: Negrito
e Cor: Castanho.

28. Ainda dentro desta página na Component Pallete, ainda na página Standard clique no objeto
ComboBox e dê um clique nesta página, altere a propriedade Hint para Selecione o campo a pesquisar, a
propriedade ShowHint para True e a propriedade Name para CbCampoTxt.

29. Ainda dentro desta página na Component Pallete, ainda na página Standard traga outro objeto
ComboBox, e altere a propriedade Visible para False e a propriedade Name para CbCampoTxtReal,
compare como ficou:

Criando a Terceira Parte


Clique na orelha Formas de Consulta dentro do objeto PgPrincipal e vamos ao trabalho:

30. Na Component Pallete clique na página Additional dentro dessa página de um clique no objeto
SpeedButton (prendendo-o com a tecla Shift) e dê cinco cliques nesta página, solte o objeto, foram criados
cinco botões pequenos, coloque-os um abaixo do outro modificando a propriedade Flat de todos para True. E
altere as seguinte propriedades:

Glyph Name Enabled


1 ImgFiltra ButFilterOpen True
2 ImgDesFiltro ButFilterClose False
3 ImgLocaliza ButSearch True
4 ImgImprime ButPrint True
5 ImgEnviaArea ButCopyClip True

31. Na Component Pallete clique na página Standard dentro dessa página de um clique no objeto Label
(prendendo-o com a tecla Shift) e dê cinco cliques nesta página, solte o objeto, coloque-os ao lado de cada
botão, altere a propriedade Font de todos para Cor: Azul-Marinho. E altere a propriedade Caption de cada
para:

Caption
1 Ativa as opções para se criar um Filtro, o Filtro permite uma seleção das fichas mostradas,
limitando-as.
2 Desativa um filtro.
3 Localiza determinada Ficha.
4 Imprime todas as fichas, limitando-as caso haja filtro ativo.
5 Envia a ficha corrente para área de transferência.

Compare como ficou:

Criando os Acessores na D_Modelo


Antes de continuarmos, abra a unidade D_Modelo e crie os seguintes objetos:

Na Component Pallete na página chamada Dialogs e dentro dessa página traga um objeto
SelectDlgT, um objeto DgPrint e um objeto DgFiltro. Altere a propriedade Name para SelPesquisa,
PrtPesquisa e FilPesquisa respectivamente.

Codificando
A codificação deste formulário não é tão complicado quando se entende toda a utilidade desta janela,
óbvio que precisei usar uma boa gama de conhecimento que tenho em linguagem Object Pascal mas adianto
que não utilizei nada estranho

1. Alterne para o Code Editor e localize a seguinte porção do código:

private
{ Private declarations }
public
{ Public declarations }

e coloque o seguinte:

private
FBM: TBookmark;
ChDuplica, fTrava: Boolean;
FiltroVisto: String;
public
procedure ChamaExterno(var Tab: TTable; aFormClass: TFormClass);
end;
uses
dModelo,
fFiltro; // Gera o Filtro

// Procedure Global para a chamadas a formulários terceiros


procedure TF_Ficha.ChamaExterno(var Tab: TTable; aFormClass: TFormClass);
begin
Screen.Cursor := crHourGlass;
Tab.Close;
with aFormClass.Create(Application) do
try
ShowModal;
finally
Free;
end;
Tab.Open;
Screen.Cursor := crDefault;
end;

☞ Importante - Coloque na primeira declaração do USES (fica logo abaixo da Seção interface) a unidade
DBTables pois o procedimento ChamaExterno faz uso do objeto TTable que faz parte desta biblioteca.

Aqui foram criadas algumas variáveis para uso particular do programa ou seja só funcionarão aqui
dentro, são elas:

• FBM: Ponteiro para guardar a posição do arquivo quando for disparado o botão Marca Registro.
• ChDuplica: Booleana que diz se é ou não para Duplicar um registro marcado.
• fTrava: Booleana que informa se o Inserção em Lote foi ou não ativada.
• FiltroVisto: Caso a tabela está com o filtro ativo criado e armado pelo usuário.

Foi criada também um procedimento público para poder criar e chamar formulários secundários, este
procedimento será visto com mais detalhes a frente.

2. Para o evento onShow do Formulário

procedure TF_Ficha.FormShow(Sender: TObject);


var
i : Integer;
begin
with dsVisao.DataSet do begin
for i := 0 to (FieldCount -1) do
case Fields[i].DataType of
ftMemo, ftFmtMemo :
begin
CbCampoTxt.Items.Add(Fields[i].DisplayLabel);
CbCampoTxtReal.Items.Add(Fields[i].FieldName);
end;
ftBlob, ftBCD, ftTypedBinary, ftGraphic :
begin
CbCampoImg.Items.Add(Fields[i].DisplayLabel);
CbCampoImgReal.Items.Add(Fields[i].FieldName);
end;
end;
end;
CbCampoTxt.ItemIndex := 0;
CbCampoImg.ItemIndex := 0;
CbCampoImgChange(Sender);
CbCampoTxtChange(Sender);
PgPrincipal.ActivePage := TabFicha;
PgTabela.ActivePage := TabTDados;
PosEstado1.Atualiza;
fTrava := False;
Screen.Cursor := crDefault;
end;

A primeira parte coloca e divide os nomes dos campos das tabelas em três segmentos, do tipo
comum, do tipo texto e do tipo imagem, isto é para ser colocado na segunda parte do formulário quando o
usuário terá a visão da tabela como a forma de uma planilha de dados.

A segunda parte prepara todo o ambiente para a mostragem dos dados. Posicionando os combos,
ativando os procedimentos Change de ambos os combos Imagem e Texto para carregá-los, transformando a
Página FICHA como inicial, na segunda página ativa a Página DADOS como principal, atualiza o objeto
PosEstado1, acerta a variável fTrava e retorna o cursor para o formato de uma seta.

3. Para o evento onClick do objeto ButInsert

procedure TF_Ficha.ButInsertClick(Sender: TObject);


var
i : Integer;
begin
with dsVisao.DataSet do begin
Insert;
if ChDuplica then
for i := 0 to (FieldCount -1) do
Fields[i].Value := D_Modelo.QrySQL.Fields[i].Value;
end;
PosEstado1.Atualiza;
TabFicha.SetFocus;
Keybd_event(9,0,0,0);
end;

Quando for pressionado o botão Insere ativa o comando Insert da tabela e verifica se está em modo
de Duplicação da Ficha, se estiver transfere todos os dados da Query pública para a tabela corrente campo a
campo, atualiza o objeto PosEstado1 e manda o foco para o objeto TabFicha depois simula o
pressionamento da tecla TAB isto fará com que o foco vá para o primeiro campo da TabFicha.

4. Para o evento onClick do objeto ButPost

procedure TF_Ficha.ButPostClick(Sender: TObject);


begin
with dsVisao.DataSet do Post;
if fTrava then
ButInsertClick(Sender)
else
PosEstado1.Atualiza;
end;

Quando for pressionado o botão Grava ativa o comando Post da tabela e verifica se está em modo
de Inserção de Lote, se estiver chama o procedimento de inclusão, caso contrário atualiza o objeto
PosEstado1.

5. Para o evento onClick do objeto ButCancel

procedure TF_Ficha.ButCancelClick(Sender: TObject);


begin
with dsVisao.DataSet do Cancel;
if fTrava then
ButInsertClick(Sender)
else
PosEstado1.Atualiza;
end;

Quando for pressionado o botão Cancela ativa o comando Cancel da tabela e verifica se está em
modo de Inserção de Lote, se estiver chama o procedimento de inclusão, caso contrário atualiza o objeto
PosEstado1.

6. Para o evento onClick do objeto ButDelete

procedure TF_Ficha.ButDeleteClick(Sender: TObject);


begin
with dsVisao.DataSet do Delete;
PosEstado1.Atualiza;
end;

Quando for pressionado o botão Elimina ativa o comando Delete da tabela e atualiza o objeto
PosEstado1.

7. Para o evento onClick do objeto ButFixIns

procedure TF_Ficha.ButFixInsClick(Sender: TObject);


begin
fTrava := not fTrava;
ButFixIns.Down := not fTrava;
ButDelete.Enabled := not fTrava;
if fTrava then
ButInsertClick(Sender);
end;

Quando for pressionado o botão Insere Lote pode acontecer dois momentos o primeiro
pressionamento trava e o segundo pressionamento libera, acerta a variável de controle, coloca o botão
pressionado (ou despressionado conforme o caso), desabilita (ou habilita conforme o caso) o botão de
exclusão e se for para travar chama o procedimento de inclusão.

8. Para o evento onClick do objeto ButFirst

procedure TF_Ficha.ButFirstClick(Sender: TObject);


begin
with dsVisao.DataSet do First;
end;

Quando for pressionado o botão Primeiro Registro ativa o comando First da tabela.

9. Para o evento onClick do objeto ButRw

procedure TF_Ficha.ButRwClick(Sender: TObject);


begin
with dsVisao.DataSet do moveby(-StrToInt(mskSalto.Text));
end;

Quando for pressionado o botão Salto para Trás ativa o comando MoveBy enviando o salto
estipulado de forma negativa.

10. Para o evento onClick do objeto ButPrior

procedure TF_Ficha.ButPriorClick(Sender: TObject);


begin
with dsVisao.DataSet do Prior;
end;

Quando for pressionado o botão Registro Anterior ativa o comando Prior da tabela.

11. Para o evento onClick do objeto ButNext

procedure TF_Ficha.ButNextClick(Sender: TObject);


begin
with dsVisao.DataSet do Next;
end;

Quando for pressionado o botão Próximo Registro ativa o comando Next da tabela.

12. Para o evento onClick do objeto ButFF

procedure TF_Ficha.ButFFClick(Sender: TObject);


begin
with dsVisao.DataSet do moveby(StrToInt(mskSalto.Text));
end;

Quando for pressionado o botão Salto para Frente ativa o comando MoveBy enviando o salto
estipulado.

13. Para o evento onClick do objeto ButLast

procedure TF_Ficha.ButLastClick(Sender: TObject);


begin
with dsVisao.DataSet do Last;
end;

Quando for pressionado o botão Último Registro ativa o comando Last da tabela.

14. Para o evento onClick do objeto ButMark

procedure TF_Ficha.ButMarkClick(Sender: TObject);


begin
with dsVisao.DataSet do FBM := getbookmark;
ButGotoMark.enabled := true;
end;

Quando for pressionado o botão Marca Registro acerta o ponteiro BookMark para guardar a
posição do registro.

15. Para o evento onClick do objeto ButGotoMark


procedure TF_Ficha.ButGotoMarkClick(Sender: TObject);
begin
with dsVisao.DataSet do gotobookmark(FBM);
end;

Quando for pressionado o botão Vai para o Registro Marcado posiciona a tabela de acordo com o
ponteiro criado com o BookMark.

16. Para o evento onClick do objeto ButFilter

procedure TF_Ficha.ButFilterOpenClick(Sender: TObject);


begin
with D_Modelo.FilPesquisa do begin
Tabela := (dsVisao.DataSet as TTable);
FiltroSQL := (dsVisao.DataSet as TTable).Filter;
FiltroVe := FiltroVisto;
if Execute then begin
FiltroVisto := FiltroVe;
with dsVisao.DataSet do begin
Close;
Filter := FiltroSQL;
Filtered := True;
Open;
end;
ButFilterOpen.Enabled := False;
ButFilterClose.Enabled := True;
end;
end;
end;

Quando for pressionado o botão Abre Filtro seta os parâmetros para o objeto FilPesquisa localizado
na D_Modelo e depois executa-o, caso seja devolvida uma resposta positiva realiza a filtragem da tabela e
desabilita este botão e habilita o botão Fecha Filtro.

17. Para o evento onClick do objeto ButFilterClose

procedure TF_Ficha.ButFilterCloseClick(Sender: TObject);


begin
with dsVisao.DataSet do begin
Close;
Filtered := False;
Open;
ButFilterOpen.Enabled := True;
ButFilterClose.Enabled := False;
end;
end;

Quando for pressionado o botão Fecha Filtro limpa o filtro da tabela e desabilita este botão e
habilita o botão Abre Filtro.

18. Para o evento onClick do objeto ButSearch

procedure TF_Ficha.ButSearchClick(Sender: TObject);


var
Marca: TBookmark;
begin
D_Modelo.SelPesquisa.Tabela := (dsVisao.DataSet as TTable);
with dsVisao.DataSet do
with D_Modelo.SelPesquisa do begin
Filtro := Filter;
Marca := GetBookMark;
if not Execute then
GotoBookMark(Marca);
FreeBookMark(Marca);
end;
end;

Quando for pressionado o botão Localiza Registro seta os parâmetros para o objeto SelPesquisa
localizado na D_Modelo e depois executa-o, antes guarda em um ponteiro do tipo BookMark a posição da
tabela, caso seja devolvida uma resposta negativa retorna a posição guardada anteriormente.

19. Para o evento onClick do objeto ButPrint

procedure TF_Ficha.ButPrintClick(Sender: TObject);


begin
D_Modelo.PrtPesquisa.Tabela := (dsVisao.DataSet as TTable);
with dsVisao.DataSet do
with D_Modelo.PrtPesquisa do begin
NomeTela := 'Impressão';
NomeRel := 'Relação de';
Filtro := Filter;
Execute;
end;
end;

Quando for pressionado o botão Imprime Dados seta os parâmetros para o objeto PrtPesquisa
localizado na D_Modelo e depois executa-o.

20. Para o evento onClick do objeto ButCopyClip

procedure TF_Ficha.ButCopyClipClick(Sender: TObject);


var
i : Integer;
begin
with dsVisao.DataSet do begin
MemClip.Lines.Clear;
for i := 0 to FieldCount - 1 do
if Fields[i].Visible then begin
MemClip.Lines.Add(Fields[i].DisplayLabel + ': ');
DBMemClip.DataField := Fields[i].FieldName;
if Fields[i].AsString > '' then begin
DBMemClip.SelectAll;
DBMemClip.CopyToClipboard;
MemClip.PasteFromClipBoard;
end;
end;
MemClip.SelectAll;
MemClip.CopyToClipboard;
end;
end;
Quando for pressionado o botão Copia para Área de Transferência utiliza-se do objeto invisível
MemClip, com o auxílio do objeto dbMemClip, para colocar todos os dados do registro atual para dentro
deste e depois simplesmente seleciona tudo e envia para a Área de Transferência.

21. Para o evento onChange do objeto CbCampoTxt

procedure TF_Ficha.CbCampoTxtChange(Sender: TObject);


begin
CbCampoTxtReal.ItemIndex := CbCampoTxt.ItemIndex;
if CbCampoTxtReal.Items.Count > -1 then
DbMemo1.DataField := CbCampoTxtReal.Text;
end;

Quando for modicada a posição do combo que contém os campos em formato Texto da página
Tabela faz as alterações necessárias setando o objeto DBMemo1 para o novo campo.

22. Para o evento onChange do objeto CbCampoImg

procedure TF_Ficha.CbCampoImgChange(Sender: TObject);


begin
CbCampoImgReal.ItemIndex := CbCampoImg.ItemIndex;
if CbCampoImgReal.Items.Count > -1 then
DbImage1.DataField := CbCampoImgReal.Text;
end;

Quando for modicada a posição do combo que contém os campos em formato Imagem da página
Tabela faz as alterações necessárias setando o objeto DBImage1 para o novo campo.

23. Para o evento onExit do objeto TabFicha

procedure TF_Ficha.TabFichaExit(Sender: TObject);


begin
if fTrava then begin
ButPostClick(Sender);
TabFicha.SetFocus;
end;
end;

A Inserção de Registros em Lote é realizada da seguinte forma, é disparado um comando Insert


para a tabela e posicionado no primeiro campo, o usuário digitará até o último campo pressionando a tecla
Tab quando ele chegar no último campo ele pressionará mais um Tab isto fará com que este comando seja
ativado, então confirmaremos a gravação do registro digitado, chamando o procedimento para tal, e
retornaremos para o primeiro campo.

24. Para o evento onClick do objeto ButDupField

procedure TF_Ficha.ButDupFieldClick(Sender: TObject);


var
NomeCampo: String;
i : Integer;
begin
ChDuplica := not ChDuplica;
ButDupField.Down := not ChDuplica;
if ChDuplica then
with D_Modelo.QrySQL do if Active then Close
else
with D_Modelo.QrySQL do begin // Monta o "SQL Completo"
if Active then Close;
SQL.Clear;
SQL.Add('select * from ' + (dsVisao.DataSet as TTable).TableName);
NomeCampo := (dsVisao.DataSet as TTable).IndexFields[0].FieldName;
case (dsVisao.DataSet as TTable).FieldByName(NomeCampo).DataType of
ftAutoInc, ftTypedBinary, ftSmallint, ftInteger, ftWord,
ftBoolean, ftFloat, ftCurrency, ftBytes, ftVarBytes:
SQL.Add('where (' + NomeCampo + ' = ' +
(dsVisao.DataSet as TTable).FieldByName(NomeCampo).AsString + ')');
else
SQL.Add('where (' + NomeCampo + ' = ''' +
(dsVisao.DataSet as TTable).FieldByName(NomeCampo).AsString + ''')');
end;
for i := 1 to (dsVisao.DataSet as TTable).IndexFieldCount-1 do begin
NomeCampo := (dsVisao.DataSet as TTable).IndexFields[i].FieldName;
case (dsVisao.DataSet as TTable).FieldByName(NomeCampo).DataType of
ftAutoInc, ftTypedBinary, ftSmallint, ftInteger, ftWord,
ftBoolean, ftFloat, ftCurrency, ftBytes, ftVarBytes:
SQL.Add('and (' + NomeCampo + ' = ' +
(dsVisao.DataSet as TTable).FieldByName(NomeCampo).AsString + ')');
else
SQL.Add('and (' + NomeCampo + ' = ''' +
(dsVisao.DataSet as TTable).FieldByName(NomeCampo).AsString + ''')');
end;
end;
Open;
end;
end;

Quando for pressionado o botão Duplica Registro fará com que esta trenheira (gostei do trenheira)
de código seja executado, é simples, com o auxílio do objeto Query público da D_Modelo (Objeto QrySQL)
geraremos um comando SQL que quando disparado conterá o registro atual, apenas ele, após isto basta com
que após cada comando Insert copiemos campo a campo do objeto Query para a Tabela.

25. Para o evento onClose do Formulário

procedure TF_Ficha.FormClose(Sender: TObject; var Action: TCloseAction);


begin
if FiltroVisto <> '' then
with dsVisao.DataSet do begin
if Active then Close;
Filter := '';
Filtered := False;
end;
if ButGotoMark.enabled then
with dsVisao.DataSet do FreeBookmark(FBM);
with D_Modelo.QrySQL do if Active then Close;
end;

Antes do usuário sair, cancelaremos o filtro, caso exista algum, finalizaremos caso tenha sido criado
o ponteiro de guardar registros e fecharemos, caso esteje ativa, o objeto Query Público da D_Modelo.

Finalmente
Na próxima apostila criaremos a primeira utilização deste formulário através da Herança dos
Objetos.

Dúvidas das Apostilas Anteriores


Como faço para criar tabelas relacionadas ?

Use o gerenciador do banco de dados para isso ou você quer criá-los via programação ? se sim não faça isso
pois os comandos variam muito de banco para banco.

Posso relacioná-las no Access ?

Claro, mas lembre-se que alguns bancos não permitem o relacionamento de Alteração e Exclusão em cascata
como o Access permite, entaum se vc quer um sistema portátil não utilize essa opção mesmo sendo ela muito
prática.

ou uso MasterSource ?

Você não relaciona tabelas com as opções MasterSource e MasterFields o que você faz é criar um indice
virtual, isso apenas serve para controlar entradas e visões dos dados nada mais.

Qual a melhor solução ? Ex. Produto -> Items

Quando utilizava o Paradox naum utilizava relacionamentos deixava o sistema controlar toda a entrada dos
dados, quando passei a usar o Access comecei a definir meus relacionamentos no próprio banco mas sempre
tomando o cuidado para que o sistema naum deixe passar besteiras, acredito que vc próprio saberá o que é
melhor para seu sistema pois cada caso é uma sentença.

A minha duvida é com relação ao Access/Multiusuario, isto é possível?

Sim ele é um banco multiusuário, ou controlado o acesso livremente ou por determinados usuários com
determinadas permissões.

e com relação a distribuição?

Veja a apostila 4 como criar o Install Shield para isto.

Com o Access isto também acontece?

A forma de acesso ao Access é pelo DAO, seu cliente precisa tê-lo ou vc a permissão para instalá-lo.

o DAO3032.DLL nao foi encontrado em um determinado diretorio. O bom e velho

Isto ocorre porque vc precisa instalar o DAO 3.5, instale o APE Work disponível no endereço citado da home
page do Bruno.

Ja li sua resposta no final da apostila 7. Possuo Windows 95 e o Office ORIGINAIS !!!!! Sera que nao resolve
?!?

Dependendo naum resolve pois vc terá apenas o DAO 3.0, mas se vc conseguir conexão com ele sem
problemas então deixe a IDDAO32.DLL

Acessei o endereco para atualizar o DBE so que a versao que la se encontra e a 5.0 ! Por acaso, exitiria algum
problema em baixa-la ?
Ela foi criada para atender o Delphi 4.0 ainda naum testei com o D3

A minha base de dados que está feita no Access 97 quando é acessada sempre pede o login e a password. É
somente dar um <enter> que consigo acessá-la. Já fiz todas as configurações que você fala na sua Home Page,
desabilitei o botão de "login prompt" no componente DataBase do Delphi, mas ainda o problema de pedir o
login para acessar a base persiste. O meu Delphi é o 3.0 e você fala que os exemplos são todos para a versão
3.02 do Delphi. Será que os meus problemas são por causa da minha versão do Delphi ??? Onde posso
arrumar um uprade para atualizar a minha versão de Delphi ???

Sempre em modo de edição ele pedirá para vc a janela Status Login, apenas com o sistema rodando que ele
parará de pedir pois entrará ou no LoginPrompt := False ou no evento OnLogin (conforme as apostilas 3 e
10). O problema naum é com seu Delphi mas para atualizá-lo para a versão 3.02, primeiro vc tem que pegar
aonde vc comprou o Delphi a versão 3.01, depois vc vai no próprio site da Inprise e pega a atualização para
3.02, ATENÇÃO: Não baixe a 3.02 em cima da 3.0.

A senha e pedida e se eu der o OK o erro ocorre.

O que é óbvio porque apenas neste momento que vc está tentando o acesso ao DAO.

É preferível sempre trabalhar com Querys? Quando devo usar Tables ?

Isso surgiu com o Delphi 1.0 e se estendeu com o Delphi 2.0, pois os objetos Query´s eram indiscutivelmente
mais rápidos e práticos que os Table´s mas se vc está utilizando o Delphi 3.0 ou Delphi 4.0 a Inprise já
corrigiu e acertou os objetos Table´s, então aconselho que vc os utilize.

Qual a melhor maneira de procurar um registro usado query ? Pode ser o Locate ?

Usando a cláusula Where.

Como devo fazer a consitencia do meu sistema para não deixar que registros duplicatos sejam cadastrados ?
Faço a procura em outra Query? Crio em run_time ?

Crie outra table para procura, ou uma query para procurar, mas modifique o comando SQL via programa, pois
assim vc pode utilizar uma única query para seu sistema inteiro.

Uso DBEdit ? ou a melhor opção são Edits ?

Os DBEdit são melhores.

Os indíces, ou By Order, ...Permito que o usário escolha a ordem dos dados? Neste caso coloquei no evento
OnTitleClick do DBGrid o seguinte código.

procedure TFClas.DBGridClasTitleClick(Column: TColumn);


var Chave:String;
begin
Chave:=Column.FieldName;
With QueryClas do begin
Close;
SQL.Clear;
SQL.Add('Select * from Classe');
SQL.Add('Order By ' + Chave );
Open;
end;
end;
É a melhor opção ?

Se vc está utilizando Query´s para cadastrar é, mas eu naum recomendo seu uso depois do Delphi 3.0.

Em um sistema, 60% se resume em inclui, altera, exclui,consulta. Se eu estiver equivocado por favor me
corrija...

Não tenho como fazê-lo no meu caso as vezes é quase 90%

Nao sei direito como funciona o relacionamento entre tabelas do Access. No clipper eu criava minhas tabelas
(.DBF) e depois com SET RELATION... relacionava a tabela PAI com a tabela FILHO. Quando posicionava
o registro na tabela PAI, seu correspondente na tabela FILHO ja era posicionado automatico. No access criei
um .MDB com duas tabelas, uma PAI e outra FILHO. Na aba de relacionamento (dentro do ACCESS97) fiz o
relacionamento, salvei e abri o DELPHI. Iniciei um novo projeto coloquei dois table/datasource/grid. Fiz as
conexoes, porem quando movimento o registro na tabela PAI, a tabela filho nao se movimenta! Isso esta
correto? Se sim, entao para que serve o relacionamento feito dentro do Access em um programa delphi? No
teste que eu fiz, o relacionamento dentro do access nao funcionou no programa em delphi.

Se vc quer movimentar o PAI e movimentar o FILHO use os parametros Master do objeto Table para isso. Os
relacionamentos no banco de dados, em qualquer deles, serve para garantir que só existirá FILHOS se
existirem PAIS, é que um PAI dependendo da regra não pode morrer ou modificar sua chave se ouverem
FILHOS atrelados a eles. Para o Delphi isso serve pois vc não precisa codificar isso.

O que voce acha do OPUS para acessar MDB em relacao ao BDE 4.51 ??? Qual a melhor opcao?

OPUS sem sombra de dúvida, é rápido, prático e seguro, utilizo o BDE para manter a integridade e
portabilidade dos sistemas para qualquer banco de dados, não sei se amanhã resolvo mudar do Access para
outra coisa qualquer.

Gostaria de armazenar um conjunto de imagens diretamente no banco de dados, que pode ser Access97 ou
Paradox 7.0 e depois empregá-las no meu projeto. Qual seria o tipo de campo ideal para armazenar estas
imagens e qual seria o procedimento para fazer a visualização dessas imagens? Se isto for possível(eu sei que
é, só não sei como) quais os formatos além do Bmp e ico que o delphi aceita, poderia ser empregado?

No Access e no Paradox é um campo OLE e no Delphi vc os associa a um campo DBImage, existe um


exemplo nos Demos do Delphi sobre isso. O Delphi aceita qualquer formato pois para colocar uma imagem
nesses campos o que vc faz é recortar a imagem e colar, vc pode desenvolver uma função que faça isso.

Existe algum componente que permite a "Justificação" de texto nos relatórios criados via QuickReport?

Nunca o vi, mas talvez o QR que vem com o Delphi 4 já vem com isso, vou dar uma pesquisada nele aguarde
notícias.

Suponha que eu tenho 5 micros ligados em rede win95 com nenhum computador servidor dedicado(apenas
compatilhamento de arquivos e hardware). Seria possível a utilização do programa Mapa criado nas apostilas
2,3,4 e todo a rede, elegendo por exemplo, o micro1 como local de instalação do programa e do banco de
dados? Em todos os micros temos instalados os mesmo programas (Access97, win95 e bde 4.51)

É possível sem problema nenhum e vc naum precisa do Access97 instalado nos micros apenas o Win95 -
Sistema - BDE 4.51 - DAO, para instalar tudo siga as instruções da nova apostila 4.
12 Curso de Delphi 4.0 - Apostila 12

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• Formulário : F_Ficha (criado na Apostila 11)

• Objetos: DBCmpList DBDateEdit97

• Seguintes Imagens :
• ImgLamp.BMP ImgTerc.BMP ImgTele.BMP

Prefácio
Salve, nesta apostila desvendaremos a segunda parte de como criar os cadastros dos nossos sistemas.

Na apostila passada criamos a primeira parte dos cadastros que foi a construção de um formulário
que servirá como base de todos os cadastros, neste mostrarei como utilizar o formulário criado, lembre-se que
definimos quatro cadastros: Cidade, Grupo, Alimento e Cliente. Aqui criarei o formulário para o Cadastro
de Cliente que é o mais complexo de todos, então caberá a você, após este, a criação dos formulários para os
cadastros de Cidade, Grupo e Alimento.

Como utilizar a Herança


A coisa que mais falei na apostila passada foi no tocante a Herança, então vamos fazer uso dela,
inicialmente reabra o nosso projeto e proceda da seguinte maneira:

1. A partir do Menu Principal vá em File | New... e vá na página Peso, escolha o formulário F_Ficha e clique
em Ok.

Pronto, primeiramente vamos começar bem devagar, neste momento foi criado uma cópia, um
espelho ou se você prefere um novo objeto formulário baseado por herança no objeto formulário F_Ficha.
NÃO altere neste formulário criado qualquer posição dos botões, NÃO faça modificações na janela, NADA.
Se tiver que fazer este tipo de alteração faça no formulário F_Ficha pois deste modo automaticamente todos
os outros formulários que foram herdados serão alterados. Altere aqui o extritamente necessário, pois cada
alteração causa um desvínculo da herança.

Para este objeto altere apenas as seguintes propriedades:

1.1. Name: F_Cliente


1.2. Caption: Cadastro de Clientes...
1.3. Salve o formulário com o nome de fCliente.PAS

Note que precisamos preencher o miolo da primeira parte (A página da ficha propriamente dita),
para tanto:

2. A partir do Menu Principal vá em File | New... e vá na página Business, escolha o formulário "Database
Form Wizard" e clique em Ok:

2.1. O tipo do formulário a ser criado. Para a opção Form Options marque Create a simple form
(Um formulário simples) e para a opção DataSet Options marque Create a form using TTables
objects (Usando o objeto tabela) e clique no Botão Next.

2.2. A tabela a ser usada para o formulário. Para a opção Drive or Alias name localize o Alias
AlPeso e para a opção Table Name marque Cliente e clique no Botão Next.

2.3. Campos a serem inseridos clique no Botão ">>" para ser inserido todos os campos e clique no
Botão Next.

2.4. Clique na opção Vertically para a formação dos campos na Vertical e clique no Botão Next

2.5. Posição dos Labels deixe marcada a opção Left (A esquerda) e clique no Botão Next

2.6. Completo. Desmarque a opção Generate a main form (Gera a tela como form principal) e na
opção Form Generation marque Form e clique no Botão Finish.

3. Agora selecione todos os campos e respectivos labels e digite CTRL+C vá para o formulário F_Cliente e
clique na página Ficha selecione a página e digite CTRL+V dê uma arrumada nos campos, você deve
conseguir algo como isto:

Este segundo formulário criado já serviu para seu propósito pode fechá-lo cancelando qualquer
procedimento para sua gravação.

☞ Importante - Existem várias maneiras de se criar este formulário que mostrei, garanto que em breve
você dominará uma maneira que mais lhe agrade, particularmente prefiro deste modo.

Acertando os campos
4. Inicilmente vamos nos ocupar dos objetos Label´s, altere as seguintes propriedades de todos:
4.1. Propriedade Caption (respectivamente):
CPF:
Nome:
Endereço:
Bairro:
CEP:
Cidade:
eMail:
Altura:
Dt.Nasc:

4.3. Propriedade AutoSize para True

4.4. Na frente do campo EditALT_CLIENTE crie mais um objeto Label e coloque na propriedade
Caption: em Cm

4.5. Altere a propriedade Font de todos para:


Font.Color = clMaroon
Font.Style = [fsBold]

5. Vamos para os campos agora, aumente o espaço entre o campo CEP e eMail e elimine o objeto
EditSIG_CIDADE, e na página Data Controls localize o objeto DBCmpList e coloque-o no lugar deste.

☞Importante - Abra o Data Module D_Modelo, volte para o formulário F_Cliente e alterne para a janela
do programa e insira a seguinte declaração após a diretiva de compilação:

{$R *.DFM}

uses
dModelo;

6. Marque o objeto DsVisao e altere a propriedade DataSet para D_Modelo.tbCliente.

7. Para o objeto DBCmpList criado altere as seguintes propriedades:

7.1. Desça-o para o espaço aberto entre os campos CEP e eMail


7.2. CapLocaliza: Localiza determinada Cidade
7.3. Caption:
7.4. CriticaEd: False
7.5. DataSource: DsVisao (Atenção: Não marque, caso apareça F_Ficha.DsVisao)
7.6. DataField: SIG_CIDADE
7.7. GlyphLoc: ImgLamp.BMP (Enviado)
7.8. HintButLoc: Localiza determinada Cidade
7.9. MensagemCodigo: Sigla da Cidade não localizada
7.10. MensagemDescricao: Cidade não localizada
7.11. Name: CmpCidade
7.12. PosCmpCodigoSec: 0
7.13. PosCmpDescricao: 1
7.14. TbSecundaria: D_Modelo.tbCidade
7.15. TipoSQL: Access
7.16. UsaDescricao: True
7.17. UsaLocaliza: True
8. Marque este objeto e vá na página Additional e coloque um objeto SpeedButton em cima do objeto
CmpCidade ao lado do botão de localizar e altere as seguintes propriedades:

8.1. Flat: True


8.2. Glyph: ImgTerc.BMP
8.3. Hint: Chama o cadastro de Cidade
8.4. Name: ButIncCidade
8.5. ShowHint: True

9. Elimine o campo EditDAT_NASCIMENTO e coloque um DBDateEdit97 no lugar e altere as seguintes


propriedades:

9.1. DataSource: DsVisao


9.2. DataField: DAT_NASCIMENTO
9.3. Name: EditDAT_NASCIMENTO

10. Altere a propriedade Font de todos os campos para Font.Color = clNavy e organize a propriedade
TabOrder para colocar os campos na sequência.

O trabalho final ficou desta maneira:

Criando Mais uma Orelha


Note através do nosso modelo que a tabela de CLIENTE tem um relacionamento de 1 para N com a
tabela de TELEFONE_CLIENTE, normalmente adoto o seguinte método para o cadastro desse tipo.

11. Dê um Duplo-Clique no objeto ImageList1, clique no botão Add... e insira a imagem ImgTele.BMP
(enviada)

12. Clique no objeto PgPrincipal e depois clique com o botão direito no sub-menu que aparece clique na
opção New Page.

13. Para esta nova página criada altere as seguintes propriedades:

13.1. Caption: Telefones


13.2. Name: TabTelefone

14. Crie agora três objetos:

14.1. Label e altere as seguintes propriedades:

14.1.1. Caption: Inclua aqui os telefones de Contato do Cliente:


14.1.2. Propriedade Font para:
Font.Color = clMaroon
Font.Style = [fsBold]

14.2. DataSource e altere as seguintes propriedades:

14.2.1. Name: dsTelefone_Cliente


14.2.2. DataSet: D_Modelo.tbTelefone_Cliente

14.3. dbGrid e altere as seguintes propriedades:

14.3.1. DataSource: dsTelefone_Cliente


14.3.2. Options:
[dgEditing,dgTitles,dgIndicator,dgColumnResize,dgColLines,dgRowLines,
dgTabs,dgConfirmDelete,dgCancelOnExit]
14.3.3. Columns: clique em [...], na janela que aparece clique duas vezes em , altere as
seguintes propriedades:

para a coluna 0

FieldName: NUM_TELEFONE
Font.Color: clNavy
Title.Caption: Número do Telefone
Title.Font.Color: clMaroon
Title.Font.Style: [fsBold]
Width: 200

para a coluna 1

FieldName: DES_FUNCAO
Font.Color: clNavy
Title.Caption: Função
PickList: Voz; FAX; Voz e FAX; PABX (Um em cada linha)
Title.Font.Color: clMaroon
Title.Font.Style: [fsBold]
Width: 104

Não vamos nos preocupar aqui com os detalhes de controlar qual telefone e de qual cliente pois esta
amarração foi realizada no DataModule através do objeto tbTELEFONE_CLIENTE, veja como ficou esta
nova página:
Difícil Programação
Você vai se surpreender com a programação criada aqui, a maior parte do trabalho ficou com o
formulário anterior, este é a apenas um espelho do passado e sua programação é quase mínima e teremos
apenas três trabalhos, vamos a ela:

1° Trabalho. Abrir as tabelas. Para tanto selecione o evento OnShow do formulário:

procedure TF_Cliente.FormShow(Sender: TObject; var Action: TCloseAction);


begin
with D_Modelo do begin
with tbCIDADE do begin
Tab1 := Active;
if not Tab1 then Open;
end;
with tbCLIENTE do begin
Tab2 := Active;
if not Tab2 then Open;
end;
with tbTELEFONE_CLIENTE do begin
Tab3 := Active;
if not Tab3 then Open;
end;
end;
inherited;
end;

e crie três variáveis na Seção Particular do Objeto:

private
Tab1, Tab2, Tab3 : Boolean;

Uma explicação geral é a seguinte, sempre que abro um formulário de cadastro abro respectivamente
as tabelas que ele utiliza na D_Modelo, mas como um formulário pode chamar outro formulário então corrijo
isso através de variáveis locais que armazenam se a respectiva tabela já se encontrava ou não aberta quando o
formulário foi ativado.
☞Importante - Aqui a ordem dos tratores altera o viaduto, o objeto DBCmpList exige que a tabela
secundária (tbCidade) seja aberta primeiramente que a tabela que serão gravados os dados (tbCliente).

Um outro comando que você pode estranhar é o comando inherited ele é o responsável por chamar
os comandos que estão localizados no evento OnShow do formulário Pai.

2° Trabalho. Fechar as tabelas. Para tanto selecione o evento OnClose do formulário:

procedure TF_Cliente.FormClose(Sender: TObject; var Action: TCloseAction);


begin
with D_Modelo do begin
case CriticaEdicao(dsVISAO, 'do Cliente', 'fechar') of
mrYes : tbCLIENTE.Cancel;
mrNo : begin
Action := caNone;
Exit;
end;
end;
// ***
Screen.Cursor := crHourGlass;
if not Tab3 then tbTELEFONE_CLIENTE.Close;
if not Tab2 then tbCLIENTE.Close;
if not Tab1 then tbCIDADE.Close;
end;
inherited;
end;

Aqui é relativamente simples, através da função CriticaEdicao que será montada na D_Modelo
verifica-se se o estado da tabela Cliente está em estado de Edição ou Inserção em caso positivo, podemos
cancelar a Edição ou cancelar o Fechamento da janela.

Na segunda parte devolvemos o estado original das tabelas.

☞Importante - Novamente a ordem dos camarões altera o vatapá, o objeto DBCmpList exige que a tabela
que serão gravados os dados (tbCliente) seja fechada primeiramente que a tabela secundária (tbCidade).

3° Trabalho. É o botão responsável por chamar o Cadastro de Cidade para tanto de um duplo-clique no
objeto ButIncCidade para ativar o evento OnClick:

procedure TF_Cliente.ButIncCidadeClick(Sender: TObject);


begin
inherited;
ChamaExterno(D_Modelo.tbCIDADE, TF_CIDADE);
end;

Não se esqueça de declarar o formulário utilizado na USES:

uses
dModelo, fCidade;

Esse foi moleza pois basta que chamemos a função ChamaExterno localizada no formulário
F_Ficha, note que por ser uma função localizada no objeto que herdamos não precisamos nem fazer a
referência para ela.
Alterando a D_Modelo
Lembra-se que na apostila referente ao DataModule avisei que algumas funções seriam
posteriormente incluídas ? Então vamos começar estas inclusões:

Função Responsável pela Verificação do Estado de uma Tabela:

1. Abra o DataModule D_Modelo através do Code Editor e localize a seção Public, insira o seguinte
cabeçalho para a declaração da função coloque-o abaixo da declaração das variáveis:

public
nmAlimento, nmCidade, nmGrupo, nmPasta_Cliente, nmPeso_Cliente, //
nmResumo_Mensal, nmTelefone_Cliente, nmCliente : String;
function CriticaEdicao(DSOrigem: TDataSource; DoQue: String; AntesDe: String) :Word;
end;

2. Após a diretiva de compilação insira os seguintes comandos:

{$R *.DFM}

function TD_Modelo.CriticaEdicao(DSOrigem: TDataSource; DoQue: String; AntesDe: String) :Word;


begin
if DSOrigem.State in [dsEdit, dsInsert] then
result := MessageDlg('Necessário cancelar a edição (ou Inclusão) ' + Doque +
' antes de ' + AntesDe + '. Deseja sair agora ?', mtConfirmation, [mbYes, mbNo], 0)
else
result := mrNone;
end;

Vamos a uma explicação geral, a função é relativamente simples, ela recebe três variáveis sendo uma
delas um objeto inteiro, uma coisa fantástica na linguagem Object Pascal é a possibilidade de passar objetos
inteiros atraves de funções ou procedimentos, são passados os seguintes:

DSOrigem : DataSource que será analisado


DoQue : Ajuda na montagem da mensagem, "Do que será cancelada a tarefa ? "
AntesDe : Complemento da mensagem do modo de edição

Então caso o DataSource passado esteja em estado de Edição ou inserção será mostrada a seguinte
mensagem "Necessário cancelar a edição (ou Inclusão) Conteúdo_Doque antes de Conteúdo_AntesDe.
Deseja sair agora ?" e mostrado dois botões "Sim" ou "Não" o resultado será um dos dois, caso contrário será
devolvido um resultado mrNone.

Função Responsável pela crítica do CPF do Cliente:

1. Localize agora a seção Private, e insira o seguinte cabeçalho para a declaração da função:

private
function Maximo(nmCampo, nmTabela: String) : integer;
function Critica_CPF(sNumCpf: String) : Boolean;

2. Após a diretiva de compilação insira os seguintes comandos:

{$R *.DFM}
function TD_Modelo.Critica_CPF(sNumCpf: String) :boolean;
var
I, J, nMod, nSubTotal, nTotal, nDv: Integer;
sChar, sNumCpfCalc: String;
begin
Result := True;
if sNumCpf = '' then Exit;
sNumCpfCalc := Copy(sNumCpf,1,9);
for I := 1 to 2 do begin
nMod := 2;
nTotal := 0;
for J := Length(sNumCpfCalc) downto 1 do begin
sChar := Copy(sNumCpfCalc, J, 1);
nSubTotal := (StrToInt(sChar) * nMod);
nTotal := nTotal + nSubTotal;
Inc(nMod);
end;
nDv := (11 - (nTotal mod 11));
if nDv > 9 then nDv := 0;
sNumCpfCalc := sNumCpfCalc + IntToStr(nDv);
end;
Result := (sNumCpfCalc = sNumCpf);
end;

3. Dê um duplo clique em cima da Tabela de Clientes e marque o campo NUM_CPF para o evento
OnValidade insira os seguintes códigos:

procedure TD_Modelo.tbClienteNUM_CPFValidate(Sender: TField);


begin
if not Critica_CPF(tbClienteNUM_CPF.Value) then
Raise Exception.Create('CPF não confere com o da Receita Federal');
end;

A função é o cálculo do famoso MÓDULO 11, você já deve ter ouvido falar isso várias vezes, o
cálculo para o primeiro dígito é feito pegando-se os nove primeiros números do CPF e multiplicando-os da
seguinte maneira, o primeiro por 10, o segundo por 9 e assim sucessivamente até o nono número por 2, e este
valor somado (isto é realizado no segundo comando FOR) é aplicada a seguinte equação:

Digito1 = 11 - Resto( Soma / 11)

A função MOD dá exatamente o resto de uma divisão. Se o valor deste primeiro dígito for maior que
9 o resultado é 0, adiciona-se este digito aos outros nove e realiza-se uma nova multiplicação com os 10
números da seguinte maneira, o primeiro por 11, o segundo por 10 e assim sucessivamente até o décimo
número por 2, aplica-se a mesma fómula anterior para encontrar o resultado do segundo dígito.

☞ Importante - Neste sistema não precisaremos, mas vou colocar aqui os códigos caso você precise, da
função para a crítica do CGC de Empresas.

function TD_Modelo.Critica_CGC(sNumCgc: String) : boolean;


var
I, J, nMod, nSubTotal, nTotal, nDv: Integer;
sChar, sNumCgcCalc: String;
begin
Result := True;
if sNumCgc = '' then Exit;
sNumCgcCalc := Copy(sNumCgc,1,12);
for I := 1 to 2 do begin
nMod := 2;
nTotal := 0;
for J := Length(sNumCgcCalc) downto 1 do begin
sChar := Copy(sNumCgcCalc, J, 1);
nSubTotal := (StrToInt(sChar) * nMod);
nTotal := nTotal + nSubTotal;
inc(nMod);
if nMod > 9 then nMod := 2;
end;
nDv := (11 - (nTotal mod 11));
if nDv > 9 then nDv := 0;
sNumCgcCalc := sNumCgcCalc + IntToStr(nDv);
end;
Result := (sNumCgcCalc = sNumCgc);
end;

Finalmente
Agora basta você voltar para o formulário F_Menu para fazer a inserção dos comandos para chamar
o formulário:

procedure TF_Menu.Cliente1Click(Sender: TObject);


begin
F_Cliente := TF_Cliente.Create(Application);
F_Cliente.ShowModal;
F_Cliente.Free;
end;

Também chame a partir do menu principal Project | Options... e retire o formulário F_Cliente da
área dos Auto-Create forms (retire também o F_Ficha caso você ainda não o fez)

☞Importante - Este formulário precisa do Formulário F_Cidade já criado para funcionar.


Agora cabê a você a criação dos formulários F_Cidade, F_Grupo e F_Alimento. Até a próxima.
13 Curso de Delphi 4.0 - Apostila 13

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• Objeto : DBDateEdit97

• Seguintes Imagens :
• ImgLamp.BMP ImgTerc.BMP ImgGrava.BMP ImgCancela.BMP

Prefácio
Salve, nesta apostila começaremos as primeiras movimentações do nosso projeto.

A movimentação basicamente é dividida em duas fases: dados de Entrada ou dados de Saída, nesta
vamos analisar a movimentação para Dados de Entrada. Esta fase deve ser lembrada como um formulário
fácil e simples para que o usuário não se confunda com o processo que ele realizará.

Entrada de Clientes
Inicialmente vamos construir a parte da movimentação relativa a Entrada de Clientes, é o momento
em que o Cliente entra no SPA e é cadastrado em algum plano

1. A partir do Menu Principal vá em File | New Form e para este objeto altere apenas as seguintes
propriedades:

1.1. BorderStyle: bsDialog


1.2. Caption: Entrada de Clientes
1.3. Name: F_Entrada
1.4. Position: poScreenCenter
1.5. Salve o formulário com o nome de fEntrada.PAS

2. Crie um objeto do tipo TPanel e altere as seguintes propriedades:

2.1. BevelInner: bvLowered


2.2. BorderWidth: 4
2.3. Align: alTop

3. Crie dentro deste Panel seis objetos do tipo Label e altere as seguintes propriedades

3.1. Propriedade Caption (respectivamente):


CPF:
[Nome do Cliente]
Data:
Plano:
Qtd.Caloria:
Observação:

3.2. Propriedade Font para:


Font.Color = clMaroon
Font.Style = [fsBold]

3.3. Propriedade AutoSize para True, menos para o segundo Label

3.4. Para o segundo Label altere as seguintes propriedades

3.4.1. LabNOM_CLIENTE
3.4.2. Estique-o para ficar com o tamanho do Panel

☞Importante - Abra o Data Module D_Modelo, volte para o formulário F_Entrada e alterne para a janela
do programa e insira a seguinte declaração após a diretiva de compilação:

{$R *.DFM}

uses
dModelo;

4. Crie um objeto do tipo DataSource e altere as seguintes propriedades:

4.1. DataSet: D_Modelo.tbPasta_Cliente


4.2. Name: dsPasta_Cliente

5. Crie dentro deste Panel um objeto do tipo dbEdit e altere as seguintes propriedades

5.1. DataSource: dsPasta_Cliente


5.2. DataField: NUM_CPF
5.3. Font.Color: clNavy
5.4. Name: EditNUM_CPF

6. Ao lado deste objeto criado crie mais dois objetos do tipo SpeedButton e altere as seguintes propriedades:

6.1. Para o primeiro SpeedButton:


6.1.1. Flat: True
6.1.2. Glyph: ImgLamp.BMP
6.1.3. Hint: Localiza determinado Cliente
6.1.4. Name: ButLocCliente
6.1.5. ShowHint: True

6.2. Para o segundo SpeedButton:


6.2.1. Flat: True
6.2.2. Glyph: ImgTerc.BMP
6.2.3. Hint: Chama o cadastro de Clientes
6.2.4. Name: ButIncCliente
6.2.5. ShowHint: True

7. Crie dentro do objeto Panel1 um objeto do tipo dbDateEdit97 e altere as seguintes propriedades
7.1. DataSource: dsPasta_Cliente
7.2. DataField: DAT_CORRENTE
7.3. Font.Color: clNavy
7.4. Name: EditDAT_CORRENTE

8. Crie dentro do objeto Panel1 dois objetos do tipo DBRadioGroup e altere as seguintes propriedades

8.1. Para o primeiro DBRadioGroup:


8.1.1. DataSource: dsPasta_Cliente
8.1.2. DataField: PLN_ADOTADO
8.1.3. Font.Color: clNavy
8.1.4. Items: (Um por Linha)
Plano Anti-Stress
Plano Reeducação
Plano Completo
Plano Especial de Reeducação
8.1.5. Values: (Um por Linha)
A;B; C;D
8.1.6. Columns: 2

8.2. Para o segundo DBRadioGroup:


8.2.1. DataSource: dsPasta_Cliente
8.2.2. DataField: QTD_CALORIA
8.2.3. Font.Color: clNavy
8.2.4. Items: (Um por Linha)
800 KCal
1.000 KCal
1.200 KCal
1.500 KCal
1.800 KCal
8.2.5. Values: (Um por Linha)
0800 ; 1000 ; 1200 ; 1500 ; 1800
8.2.6. Columns: 2

9. Crie dentro do objeto Panel1 um objeto do tipo DBMemo e altere as seguintes propriedades

9.1. DataSource: dsPasta_Cliente


9.2. DataField: OBS_PASTA
9.3. Font.Color: clNavy
9.4. Name: MemoOBS_PASTA

10. Acerte a propriedade TabOrder para a sequência correta.

11. Abaixo do Objeto Panel1 crie três objetos do tipo BitBtn e altere as seguintes propriedades:

11.1. Para o primeiro BitBtn:


11.1.1. Caption: &Grava
11.1.2. Glyph: ImgGrava.BMP
11.1.3. Hint: Grava os dados na Pasta do Cliente
11.1.4. Name: ButGrava
11.1.5. ShowHint: True

11.2. Para o segundo BitBtn:


11.2.1. Caption: &Cancela
11.2.2. Glyph: ImgCancela.BMP
11.2.3. Hint: Cancela e limpa a entrada dos dados
11.2.4. Name: ButCancela
11.2.5. ShowHint: True

11.3. Para o terceiro BitBtn:


11.3.1. Kind: bkClose
11.3.2. Caption: &Fechar
11.3.3. Hint: Fecha esta janela retornando ao menu do sistema
11.3.4. ShowHint: True

O trabalho final ficou desta maneira:

Programando a Entrada
Lembre-se, a programação aqui é uma coisa rápida é direta, ela não deve ser aplicada em situações
de risco, como por exemplo um cadastro.

1. Inicialmente alterne para a Code Editor e na seção Private crie a seguinte chamada para o procedimento:

private
procedure AcertaInsercao;
public

2. Agora abaixo da diretiva de compilação crie o procedimento proposto:

{$R *.DFM}
uses
dModelo;

procedure TF_Entrada.AcertaInsercao;
begin
D_Modelo.tbPasta_Cliente.Insert;
LabNOM_CLIENTE.Caption := '';
end;

Este procedimento será chamado toda vez que for feito uma nova inclusão na tabela Pasta Cliente.

3. Selecione agora o evento OnShow do formulário:

procedure TF_Entrada.FormShow(Sender: TObject);


begin
with D_Modelo do begin
tbCliente.Open;
SelPesquisa.NomeTela := 'Seleciona Determinado Cliente';
SelPesquisa.Tabela := tbCliente;
tbPasta_Cliente.Open;
end;
AcertaInsercao;
end;

Toda vez que o formulário for ativado, e aberta a tabela acessória tbCliente e organizado os campos
dentro do objeto SelPesquisa localizado na D_Modelo, depois aberta a tabela em que será realizada toda a
movimentação a tbPasta_Cliente e chamado o procedimento particular para colocá-la em estado de inserção.

4. Selecione o evento OnClose do formulário:

procedure TF_Entrada.FormClose(Sender: TObject; var Action: TCloseAction);


begin
with D_Modelo do begin
tbCliente.Close;
tbPasta_Cliente.Cancel;
tbPasta_Cliente.Close;
end;
end;
Aqui é relativamente simples, simplesmente fechamos as tabelas cancelando o estado de inserção da
tabela principal.

5. Vamos começar com os botões, primeiro o botão responsável para realizar a Gravação na Pasta para tanto
de um duplo-clique no objeto ButGrava para ativar o evento OnClick:

procedure TF_Entrada.ButGravaClick(Sender: TObject);


begin
if EditNUM_CPF.Text = '' then
raise exception.create('Cliente não informado');
if LabNOM_CLIENTE.Caption = '' then
raise exception.create('Cliente não cadastrado');
D_Modelo.tbPasta_Cliente.Post;
AcertaInsercao;
end;

Fazemos duas críticas simples apenas para controlar se o CPF foi preenchido e se o nome do cliente
foi encontrado (o que significará que o cliente existe), então gravamos o dado e simplesmente chamamos o
procedimento para reativar o estado de inserção.

6. O segundo botão é o responsável para realizar o Cancelamento dos dados para tanto de um duplo-clique
no objeto ButCancela para ativar o evento OnClick:

procedure TF_Entrada.ButCancelaClick(Sender: TObject);


begin
D_Modelo.tbPasta_Cliente.Cancel;
AcertaInsercao;
end;

Este aqui é simplesmente disparar um comando Cancel para a tabela e chamarmos o procedimento
para reativar o estado de inserção.

Programando o Cliente
A ligação entre a tabela Pasta_Cliente e Cliente deverá ser totalmente controlada aqui, poderiamos
usar do objeto CmpTerc para fazer este controle (igual fizemos no cadastro) mas preferi deixar o Cliente
solto, então vamos aos passos:

1. Selecione o objeto EditNUM_CPF e chame o evento OnExit:

procedure TF_Entrada.EditNUM_CPFExit(Sender: TObject);


begin
if EditNUM_CPF.Text <> '' then
with D_Modelo.tbCliente do
if FindKey([EditNUM_CPF.Text]) then
LabNOM_CLIENTE.Caption := FieldByName('NOM_CLIENTE').AsString
else begin
EditNUM_CPF.SetFocus;
raise exception.create('Cliente não cadastrado');
end;
end;

Inicialmente verificamos se foi preenchido algo no campo, então pesquisamos na tabela Cliente com
o valor informado, caso encontre coloca o nome do cliente no Label destinado para tal, caso contrário volta o
cursor para o objeto EditNUM_CPF e mostra a mensagem de erro.

2. O primeiro o botão localizado depois do campo é o responsável para realizar a Consulta do Cliente para
tanto de um duplo-clique no objeto ButLocCliente para ativar o evento OnClick:

procedure TF_Entrada.ButLocClienteClick(Sender: TObject);


begin
with D_Modelo do
if SelPesquisa.Execute then
EditNUM_CPF.Text := tbClienteNUM_CPF.AsString;
end;
São comando simples, executamos o objeto SelPesquisa e caso ele traga uma resposta verdadeira
apenas adicionamos o valor do campo NUM_CPF da tabela cliente ao objeto EditNUM_CPF.

3. A pior coisa de um sistema, é por exemplo o Cliente não estar cadastrado e o usuário ser obrigado a sair da
tela em que se encontra e cadastrar o cliente e depois retornar, para evitar isto o segundo botão é o
responsável para chamar o Cadastro de Cliente para tanto de um duplo-clique no objeto ButIncCliente para
ativar o evento OnClick:

procedure TF_Entrada.ButIncClienteClick(Sender: TObject);


begin
F_Cliente := TF_Cliente.Create(Application);
F_Cliente.ShowModal;
F_Cliente.Free;
end;
Aqui apenas disparamos a chamada ao formulário de Cliente, exatamente como é feito no menu
principal, não se esquece de adicionar o formulário fCliente a cláusula USES.

Massa Corporal
Outro exemplo de movimentação de entrada é o formulário para fazer a Massa Corporal, é o
momento em que o Cliente é pesado e sua massa é mostrada em um cálculo (Recorde este cálculo na apostila
referente ao Levantamento dos Dados):

1. A partir do Menu Principal vá em File | New Form e para este objeto altere apenas as seguintes
propriedades:

1.1. BorderStyle: bsDialog


1.2. Caption: Massa Corporal
1.3. Name: F_Massa
1.4. Position: poScreenCenter
1.5. Salve o formulário com o nome de fMassa.PAS

2. Crie um objeto do tipo TPanel e altere as seguintes propriedades:

2.1. BevelInner: bvLowered


2.2. BorderWidth: 4
2.3. Align: alTop

3. Crie dentro deste Panel seis objetos do tipo Label e altere as seguintes propriedades

3.1. Propriedade Caption (respectivamente):


CPF:
[Nome do Cliente]
Data:
Peso: em Kg

Massa Corporal é:

3.2. Propriedade Font para:


Font.Color = clMaroon
Font.Style = [fsBold]

Para destacar aumente a fonte do último objeto para 11.

3.3. Propriedade AutoSize para True, menos para o segundo Label

3.4. Para o segundo Label altere as seguintes propriedades

3.4.1. LabNOM_CLIENTE
3.4.2. Estique-o para ficar com o tamanho do Panel

☞Importante - Abra o Data Module D_Modelo, volte para o formulário F_Entrada e alterne para a janela
do programa e insira a seguinte declaração após a diretiva de compilação:

{$R *.DFM}

uses
dModelo;
4. Crie um objeto do tipo DataSource e altere as seguintes propriedades:

4.1. DataSet: D_Modelo.tbPeso_Cliente


4.2. Name: dsPeso_Cliente

5. Crie dentro deste Panel um objeto do tipo dbEdit e altere as seguintes propriedades

5.1. DataSource: dsPeso_Cliente


5.2. DataField: NUM_CPF
5.3. Font.Color: clNavy
5.4. Name: EditNUM_CPF

6. Ao lado deste objeto criado crie mais dois objetos do tipo SpeedButton e altere as seguintes propriedades:

6.1. Para o primeiro SpeedButton:


6.1.1. Flat: True
6.1.2. Glyph: ImgLamp.BMP
6.1.3. Hint: Localiza determinado Cliente
6.1.4. Name: ButLocCliente
6.1.5. ShowHint: True

6.2. Para o segundo SpeedButton:


6.2.1. Flat: True
6.2.2. Glyph: ImgTerc.BMP
6.2.3. Hint: Chama o cadastro de Clientes
6.2.4. Name: ButIncCliente
6.2.5. ShowHint: True

7. Crie dentro do objeto Panel1 um objeto do tipo dbDateEdit97 e altere as seguintes propriedades

7.1. DataSource: dsPeso_Cliente


7.2. DataField: DAT_MEDIDO
7.3. Font.Color: clNavy
7.4. Name: EditDAT_MEDIDO

8. Crie dentro deste Panel um objeto do tipo dbEdit e altere as seguintes propriedades

8.1. DataSource: dsPeso_Cliente


8.2. DataField: PES_MEDIDO
8.3. Font.Color: clNavy
8.4. Name: EditPES_MEDIDO

9. Acerte a propriedade TabOrder para a sequência correta.

10. Abaixo do Objeto Panel1 crie três objetos do tipo BitBtn e altere as seguintes propriedades:

10.1. Para o primeiro BitBtn:


10.1.1. Caption: &Grava
10.1.2. Glyph: ImgGrava.BMP
10.1.3. Hint: Grava os dados na Pasta do Cliente
10.1.4. Name: ButGrava
10.1.5. ShowHint: True

10.2. Para o segundo BitBtn:


10.2.1. Caption: &Cancela
10.2.2. Glyph: ImgCancela.BMP
10.2.3. Hint: Cancela e limpa a entrada dos dados
10.2.4. Name: ButCancela
10.2.5. ShowHint: True

10.3. Para o terceiro BitBtn:


10.3.1. Kind: bkClose
10.3.2. Caption: &Fechar
10.3.3. Hint: Fecha esta janela retornando ao menu do sistema
10.3.4. ShowHint: True

O trabalho final ficou desta maneira:

Programando a Massa
Novamente vou frisar que a programação aqui é uma coisa rápida é direta, ela não deve ser aplicada
em situações de risco, como por exemplo um cadastro.

1. Inicialmente alterne para a Code Editor e na seção Private crie a seguinte chamada para o procedimento:

private
procedure AcertaInsercao;
public

2. Agora abaixo da diretiva de compilação crie o procedimento proposto:

{$R *.DFM}
uses
dModelo;

procedure TF_Massa.AcertaInsercao;
begin
D_Modelo.tbPeso_Cliente.Insert;
LabNOM_CLIENTE.Caption := '';
end;

Este procedimento será chamado toda vez que for feito uma nova inclusão na tabela Peso Cliente.

3. Selecione agora o evento OnShow do formulário:


procedure TF_Massa.FormShow(Sender: TObject);
begin
with D_Modelo do begin
tbCliente.Open;
SelPesquisa.NomeTela := 'Seleciona Determinado Cliente';
SelPesquisa.Tabela := tbCliente;
tbPeso_Cliente.Open;
end;
AcertaInsercao;
end;

Toda vez que o formulário for ativado, e aberta a tabela acessória tbCliente e organizado os campos
dentro do objeto SelPesquisa localizado na D_Modelo, depois aberta a tabela em que será realizada toda a
movimentação a tbPeso_Cliente e chamado o procedimento particular para colocá-la em estado de inserção.

4. Selecione o evento OnClose do formulário:

procedure TF_Massa.FormClose(Sender: TObject; var Action: TCloseAction);


begin
with D_Modelo do begin
tbCliente.Close;
tbPeso_Cliente.Cancel;
tbPeso_Cliente.Close;
end;
end;
Aqui é relativamente simples, simplesmente fechamos as tabelas cancelando o estado de inserção da
tabela principal.

5. Vamos começar com os botões, primeiro o botão responsável para realizar a Gravação do Peso para tanto
de um duplo-clique no objeto ButGrava para ativar o evento OnClick:

procedure TF_Massa.ButGravaClick(Sender: TObject);


begin
if EditNUM_CPF.Text = '' then
raise exception.create('Cliente não informado');
if LabNOM_CLIENTE.Caption = '' then
raise exception.create('Cliente não cadastrado');
D_Modelo.tbPeso_Cliente.Post;
AcertaInsercao;
end;

Fazemos duas críticas simples apenas para controlar se o CPF foi preenchido e se o nome do cliente
foi encontrado (o que significará que o cliente existe), então gravamos o dado e simplesmente chamamos o
procedimento para reativar o estado de inserção.

6. O segundo botão é o responsável para realizar o Cancelamento dos dados para tanto de um duplo-clique
no objeto ButCancela para ativar o evento OnClick:

procedure TF_Massa.ButCancelaClick(Sender: TObject);


begin
D_Modelo.tbPeso_Cliente.Cancel;
AcertaInsercao;
end;

Este aqui é simplesmente disparar um comando Cancel para a tabela e chamarmos o procedimento
para reativar o estado de inserção.

Últimos Passos
Um passo, que até poderia copiar é o Programando o Cliente, mas ao invés de repetir todos os
comandos prefiro que você volte e veja na seção anterior como isso é feito.

A principal parte diferente aqui é quanto ao cálculo da massa corporal, então selecione o objeto
EditPES_MEDIDO e chame o evento OnExit:

procedure TF_Massa.EditPES_MEDIDOExit(Sender: TObject);


var
ind: Integer;
begin
if LabNOM_CLIENTE.Caption <> '' then begin
with D_Modelo do
ind := Round(tbPESO_CLIENTEPES_MEDIDO.AsInteger /
((tbClienteALT_CLIENTE.AsInteger / 100) *
(tbClienteALT_CLIENTE.AsInteger / 100)));
LabMAS_CLIENTE.Caption := 'Massa coorporal é: ' + IntToStr(Ind);
with LabMAS_CLIENTE do
if ind < 20 then Caption := Caption + ' (Abaixo do Peso)'
else if ind < 26 then Caption := Caption + ' (Normal)'
else if ind < 30 then Caption := Caption + ' (Excesso de Peso)'
else if ind < 40 then Caption := Caption + ' (Obsidade)'
else Caption := Caption + ' (Obsidade Mórbida)';
end;
end;

Pronto, na saída da informação do peso, é calculada a massa corporal, apensa se existir um cliente
pois precisamos saber da altura do cliente para o cálculo de sua massa, novamente vou frisar que se você não
lembra como é realizado isto recorra a apostila referente ao Levantamento dos Dados.

Finalmente
Agora basta você voltar para o formulário F_Menu para fazer a inserção dos comandos para chamar
os formulários:

procedure TF_Menu.EntradadoCliente1Click(Sender: TObject);


begin
F_Entrada := TF_Entrada.Create(Application);
F_Entrada.ShowModal;
F_Entrada.Free;
end;

procedure TF_Menu.MassaCorporal1Click(Sender: TObject);


begin
F_Massa := TF_Massa.Create(Application);
F_Massa.ShowModal;
F_Massa.Free;
end;

Também chame a partir do menu principal Project | Options... e retire os formulários F_Entrada e
F_Massa da área dos Auto-Create forms.
Na próxima apostila vamos criar uma movimentação um tanto mais complexa, portanto esteje
preparado.
14 Curso de Delphi 4.0 - Apostila 14

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Arquivos trabalhados juntos com esta apostila:

• Objeto : DBDateEdit97

• Seguintes Imagens :
• ImgCalc.BMP ImgGrava.BMP ImgLocaliza.BMP

Prefácio
Salve, nesta apostila vamos concluir as movimentações do nosso projeto.

Nesta segunda fase mostrarei como coordenar dados de Saída, não associe os dados de saída como
retirada ou qualquer outra coisa parecida, na verdade são dados já colocados nas tabelas mas que faltam a
informação final, aquele famoso Tchan para ficar completo.

Saída de Clientes
Vamos construir a parte da movimentação relativa a Saída de Clientes, é o momento em que o
Cliente está saindo do SPA e precisa efetuar o pagamento.

1. A partir do Menu Principal vá em File | New Form e para este objeto altere apenas as seguintes
propriedades:

1.1. BorderStyle: bsDialog


1.2. Caption: Saída de Clientes
1.3. Name: F_Saida
1.4. Position: poScreenCenter
1.5. Salve o formulário com o nome de fSaida.PAS

☞ Importante - Abra o Data Module D_Modelo, volte para o formulário F_Saida e alterne para a janela
do programa e insira a seguinte declaração após a diretiva de compilação:

{$R *.DFM}

uses
dModelo;

2. Crie um objeto do tipo DataSource e altere as seguintes propriedades:


2.1. DataSet: D_Modelo.tbPasta_Cliente
2.2. Name: dsPasta_Cliente

3. Crie um objeto do tipo TPanel e altere as seguintes propriedades:

3.1. Caption:
3.2. Align: alTop

4. Crie dentro do objeto Panel1 um objeto do tipo dbNavigator e altere as seguintes propriedades

4.1. DataSource: dsPasta_Cliente


4.2. Hints:
Primeiro Registro
Próximo Registro
Registro Anterior
Último Registro
4.3. Name: DbNavega
4.4. ShowHint: True
4.5. VisibleButtons: [nbFirst,nbPrior,nbNext,nbLast]

5. Crie dentro do objeto Panel1 um objeto do tipo BitBtn e altere as seguintes propriedades

5.1. Caption: &Localizar


5.2. Glyph: ImgLocaliza.BMP
5.3. Hint: Localiza Determinada Pasta do Cliente
5.4. Name: ButLocaliza
5.5. ShowHint: True

6. Crie agora um segundo objeto do tipo TPanel e altere as seguintes propriedades:

6.1. BevelInner: bvLowered


6.2. BorderWidth: 4
6.3. Align: alTop

7. Crie dentro do objeto Panel2 dez objetos do tipo Label e altere as seguintes propriedades:

7.1. Propriedade Caption (respectivamente):


Cliente:
Dt.Chegada:
Plano:
Qtd.Caloria: KCal
Observação:
Dt.Pagamento:
Valor:
Desconto:
Total a Pagar:

7.2. Propriedade Font para:


Font.Color = clMaroon
Font.Style = [fsBold]

☞Importante - Aqui vão algumas observações:


a. Deixe um espaço entre o label Cliente e Dt.Chegada
b. O label KCal fica na frente do Label Qtd.Caloria com um espaço para colocar um
campo
c. Deixe um espaço entre o Label Qtd.Caloria e o label Observação

8. Crie dentro do objeto Panel2 um objeto do tipo Bevel e altere as seguintes propriedades

8.1. Shape: bsBottomLine

☞Importante - Este objeto foi criado apenas para separar os dados, coloque-o entre os Labels Qtd.Caloria
e Observação

9. Crie dentro do objeto Panel2 três objetos do tipo dbEdit e altere as seguintes propriedades:

9.1. DataSource: dsPasta_Cliente


9.2. DataField (respectivamente): NUM_CPF, DAT_CORRENTE e QTD_CALORIA
9.3. Font.Color: clMarron
9.4. Name (respectivamente): EditNUM_CPF, EditDAT_CORRENTE e EditQTD_CALORIA
9.5. Color: clBtnFace
9.6. TabStop: False
9.7. ReadOnly: True

☞Importante - Posicione-os em frente aos labels Cliente, Dt.Chegada e Qtd.Caloria respectivamente.


10. Crie dentro do objeto Panel2 abaixo do objeto EditNUM_CPF mais um objeto do tipo dbEdit e altere as
seguintes propriedades:

10.1. DataSource: dsCliente


10.2. DataField: NOM_CLIENTE
10.3. Font.Color: clMarron
10.2. Name: EditNOM_CLIENTE
10.4. Color: clBtnFace
10.4. TabStop: False
10.4. ReadOnly: True

11. Crie dentro do objeto Panel2 na frente do Label Plano um objeto do tipo Edit e altere as seguintes
propriedades

11.1. Font.Color: clMarron


11.2. Name: EditNOM_PLANO
11.3. Color: clBtnFace
11.4. TabStop: False
11.5. ReadOnly: True

12. Crie dentro do objeto Panel2 na frente do Label Dt.Pagamento um objeto do tipo dbDateEdit97 e altere
as seguintes propriedades

12.1. DataSource: dsPasta_Cliente


12.2. DataField: DAT_PAGAMENTO
12.3. Font.Color: clNavy
12.4. Name: EditDAT_PAGAMENTO

13. Crie dentro do objeto Panel2 na frente do Label Valor e Desconto respectivamente dois objetos do tipo
dbEdit e altere as seguintes propriedades:

13.1. DataSource: dsPasta_Cliente


13.2. DataField (respectivamente): VAL_TOTAL e VAL_DESCONTO
13.3. Font.Color: clNavy
13.2. Name (respectivamente): EditVAL_TOTAL e EditVAL_DESCONTO

14. Acerte a propriedade TabOrder desses três últimos objetos para uma sequência correta a partir do zero.

15. Crie dentro do objeto Panel2 na frente do objeto EditVAL_DESCONTO um objeto do tipo
SpeedButton e altere as seguintes propriedades:

15.1. Flat: True


15.2. Glyph: ImgCalc.BMP
15.3. Hint: Calcula o Desconto Padrão
15.4. Name: ButCalcDesconto
15.5. ShowHint: True

16. Crie dentro do objeto Panel2 na frente do label Total a Pagar um objeto do tipo Panel e altere as
seguintes propriedades:

16.1. BevelOuter: bvNone


16.2. BorderStyle: bsSingle
16.3. Height: 21
16.4. Name: PnlTotal
16.5. Alignment: taRightJustify
16.6. Font.Color: clMaroon

17. Abaixo do Objeto Panel2 crie dois objetos do tipo BitBtn e altere as seguintes propriedades:

17.1. Para o primeiro BitBtn:


17.1.1. Caption: &Grava
17.1.2. Glyph: ImgGrava.BMP
17.1.3. Hint: Grava os dados na Pasta do Cliente
17.1.4. Name: ButGrava
17.1.5. ShowHint: True

17.2. Para o segundo BitBtn:


17.2.1. Kind: bkClose
17.2.2. Caption: &Fechar
17.2.3. Hint: Fecha esta janela retornando ao menu do sistema
17.2.4. ShowHint: True

O trabalho final ficou desta maneira:


Programando a Saída
A programação aqui (ainda bem que estamos tratando do Delphi) não é algo tão complicado, pode
ser se você desejar colocar coisas homéricas, a idéia é que o usuário localize na tabela Pasta Cliente a entrada
deste Cliente, mas lembre-se que o mesmo Cliente pode visitar várias vezes o SPA então precisamos
restringir os registros, acompanhe atentamente a codificação:

1. Inicialmente alterne para a Code Editor e na seção Private crie uma variável para acumular o valor de um
desconto dado.

private
VlDesconto: Double;
public

2. Selecione agora o evento OnShow do formulário:

procedure TF_Saida.FormShow(Sender: TObject);


begin
with D_Modelo do begin
SelPesquisa.NomeTela := 'Seleciona Determinada Pasta Cliente';
SelPesquisa.Tabela := tbPasta_Cliente;
with tbCliente do begin
MasterSource := dsPasta_Cliente;
MasterFields := 'NUM_CPF';
Open;
end;
with tbPasta_Cliente do begin
Filter := 'VAL_TOTAL < 0';
Filtered := True;
Open;
end;
end;
end;

Toda vez que o formulário for ativado, é organizado os campos dentro do objeto SelPesquisa
localizado na D_Modelo, e ativado um relacionamento entre a tabela tbCliente e tbPasta_Cliente e é aberta
a tabela acessória tbCliente e depois é ativado um filtro para a tabela tbPasta_Cliente permitindo que sejam
mostrados apenas os registros aonde o Valor ainda é 0 (ou menor, isso incluirá os nulos) e aberta a tabela em
que será realizada toda a movimentação a tbPasta_Cliente.

☞Importante - Abra a tabela ascessória primeiramente (no caso tbCliente), pois existirá uma dependência
no evento quando os dados serão mudados do objeto DsPasta_Cliente que necessitará que esta tabela esteje
aberta.

3. Selecione o evento OnClose do formulário:

procedure TF_Saida.FormClose(Sender: TObject; var Action: TCloseAction);


begin
with D_Modelo do begin
with tbPasta_Cliente do begin
if dsPasta_Cliente.State = dsEdit then Cancel;
Close;
Filter := '';
Filtered := False;
end;
with tbCliente do begin
Close;
MasterSource := Nil;
MasterFields := '';
end;
end;
end;

Neste momento fechamos inicialmente a tabela principal, aplicando um comando Cancel na tabela
caso os dados estejam em momento de edição (para não acontecer uma gravação equivocada, se o usuário
quer gravar então ele deve apertar o botão Grava) depois de fechada, eliminamos o filtro da tabela, o segundo
passo é fechar a tabela secundária, eliminando também a dependência entre as duas tabelas.

4. Vamos começar com os botões, primeiro o botão responsável para realizar a Gravação na Pasta para tanto
de um duplo-clique no objeto ButGrava para ativar o evento OnClick:

procedure TF_Saida.ButGravaClick(Sender: TObject);


begin
if EditDAT_PAGAMENTO.Text = '' then
Raise Exception.Create('Data de Pagamento não informada');
if EditVAL_TOTAL.Text = '' then
Raise Exception.Create('Valor não informado');
D_Modelo.tbPasta_Cliente.Post;
end;

Fazemos duas críticas simples apenas para controlar se a Data e o Valor de pagamento foram
preenchidos, então simplesmente gravamos o dado. Aqui não precisamos nos preocupar em colocar a tabela
em momento de inserção pois o Delphi trata isto automaticamente. Também, automaticamente, o registro
sumirá da tela, por causa do Filtro ativo.
5. O botão localizado ao lado da barra de navegação é o responsável para realizar a Consulta a Pasta Cliente
para tanto de um duplo-clique no objeto ButLocaliza para ativar o evento OnClick:

procedure TF_Saida.ButLocalizaClick(Sender: TObject);


begin
D_Modelo.SelPesquisa.Execute;
end;

É um simples comando aqui apenas executamos o objeto SelPesquisa ele se encarregará de


posicionar no registro correto.

6. Selecione o objeto EditVAL_TOTAL e chame o evento OnExit:

procedure TF_Saida.EditVAL_TOTALExit(Sender: TObject);


begin
if EditVal_Total.Text <> '' then
with D_Modelo.tbPasta_Cliente do
PnlTotal.Caption := Format('%10.2m', [(FieldByName('VAL_TOTAL').AsFloat - FieldByName
('VAL_DESCONTO').AsFloat)]);
end;

Aqui será feito para calcularmos o valor total a pagar, no momento da saída do campo Valor e do
campo Desconto.

7. Selecione o objeto EditVAL_DESCONTO e localize o evento OnExit, clique na seta que aparece ao lado
do campo e coloque nele a chamada EditVAL_TOTALExit.

8. O botão ao lado do EditVAL_DESCONTO é o responsável para calcular um desconto concedido para


tanto de um duplo-clique no objeto ButCalcDesconto para ativar o evento OnClick:

procedure TF_Saida.ButCalcDescontoClick(Sender: TObject);


begin
if EditVal_Total.Text <> '' then
EditVAL_DESCONTO.Text := FloatToStr(D_Modelo.tbPasta_ClienteVal_Total.AsFloat * VlDesconto)
else
MessageDlg('Informe primeiro o Valor',mtInformation,[mbOk],0);
end;

Verificamos se o Valor do Pagamento já foi preenchido, então calculamos o desconto com base na
variável VlDesconto.

9. Este agora é o coração de todo o formulário, é aqui que a maior parte foi projetada, selecione o objeto
DsPasta_Cliente e dê um duplo-clique no evento OnDataChange:

procedure TF_Saida.dsPasta_ClienteDataChange(Sender: TObject; Field: TField);

procedure AcertaDesc(ValS: String; ValN: Double);


begin
LabDesconto.Caption := 'Desconto ' + ValS + '%:';
VlDesconto := ValN;
end;

begin
with D_Modelo.tbPasta_Cliente do
if FieldByName('PLN_ADOTADO').AsString = 'A' then
EdtNOM_PLANO.Text := 'Plano Anti-Stress'
else if FieldByName('PLN_ADOTADO').AsString = 'B' then
EdtNOM_PLANO.Text := 'Plano Reeducação'
else if FieldByName('PLN_ADOTADO').AsString = 'C' then
EdtNOM_PLANO.Text := 'Plano Completo'
else if FieldByName('PLN_ADOTADO').AsString = 'D' then
EdtNOM_PLANO.Text := 'Plano Especial de Reeducação'
else
EdtNOM_PLANO.Text := '';
if EditVal_Total.Text <> '' then
with D_Modelo.tbPasta_Cliente do
PnlTotal.Caption := Format('%10.2m', [(FieldByName('VAL_TOTAL').AsFloat - FieldByName
('VAL_DESCONTO').AsFloat)])
else
PnlTotal.Caption := Format('%10.2m', [0.00]);
with D_Modelo do
with QrySQL do begin
if Active then Close;
SQL.Clear;
SQL.Add('Select Count(NUM_CPF) from ' + NmPasta_Cliente);
SQL.Add('Where (NUM_CPF = ''' + EditNUM_CPF.Text + ''')');
Open;
LabObserva.Caption := 'Observação: Não existe';
LabDesconto.Caption := 'Desconto:';
VlDesconto := 0;
if not EOF then begin
LabObserva.Caption := 'Observação: Esta é a ' + Fields[0].AsString + 'ª visita deste cliente.';
case Fields[0].AsInteger of
2: AcertaDesc('5',0.05);
3: AcertaDesc('10',0.1);
4: AcertaDesc('15',0.15);
5: AcertaDesc('16',0.16);
6: AcertaDesc('17',0.17);
7: AcertaDesc('18',0.18);
8: AcertaDesc('19',0.19);
else
if Fields[0].AsInteger > 8 then AcertaDesc('20',0.2);
end;
end;
Close;
end;
D_Modelo.tbCliente.Refresh;
end;

Olhando assim parece complicado mas não precisamos temer tanto, o brincadeira é a seguinte,
inicialmente coloquei um procedimento dentro para mostrar no LabDesconto se existe algum desconto
cedido, e setar a variável VlDesconto com este valor.

Começando o procedimento realmente, inicialmente é verificado qual é o plano que o cliente optou,
depois é calculado o valor a pagar (da mesma forma em que foi feito na saida dos campos EditVAL_TOTAL
e EditVAL_DESCONTO). Agora utilizaremos a Query ascessória para pesquisarmos dentro da tabela Pasta
Cliente quantas vezes este Cliente já veio ao SPA, e verificamos qual o valor do desconto que pode ser
concedido para este cliente (Lembra-se da regra: 2ª Visita = 5%, 3ª Visita = 10%, verifique na parte do
Levantamento dos Dados), e finalmente damos um Refresh na tabela de Cliente para que o relacionamento
feito entre ela e a tabela Pasta_Cliente possa ser efetivado, mostrando o nome do cliente corretamente.
Finalmente
Agora basta você voltar para o formulário F_Menu para fazer a inserção dos comandos para chamar
os formulários:

procedure TF_Menu.SaidadoCliente1Click(Sender: TObject);


begin
F_Saida := TF_Saida.Create(Application);
F_Saida.ShowModal;
F_Saida.Free;
end;

Também chame a partir do menu principal Project | Options... e retire o formulário F_Saida da área
dos Auto-Create forms.

Acredito que você tenha reparado os dois processos de movimentação, na anterior trabalhamos
basicamente com o momento INSERT da tabela, era apenas uma entrada simples e básica, nesta aqui
pegamos aqueles dados inseridos e trabalhamos um pouco mais, solicitando mais alguns dados para
finalmente finalizarmos este Cadastro.

Em movimentações, também é possível, e admissível, criarmos uma tabela idêntica, apenas para
servir como arquivamento dos dados, ou seja, após concluirmos esta segunda fase da movimentação, passar
os dados já gravados para uma segunda tabela, tipo um Fechamento.

Na próxima apostila vamos começar a analisar como são feitos relatórios.


15 Curso de Delphi 4.0 - Conexão Delphi com o MS-Access

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Prefácio
Antes de começarmos o nosso curso precisamos configurar o acesso ao banco de dados que será
utilizado, MS-Access.

Porque trabalhar com o Access ? Bem, poderia explicar que porque ele é o banco de dados mais fácil
de se trabalhar tanto para nós (programadores) quanto para o usuário, ou então que muitos de nós o temos, ou
ainda pode-se dizer que ele é um padrão mundial, mas fico com a explicação de que entre todos os bancos de
dados de pequeno porte (Inclui aí, MS-Access, Paradox, dBase, entre outros) ele é o que melhor se comporta
para o desenvolvimento inicial de qualquer projeto suportando as alterações feitas constantemente na base,
perda e recuperação dos índices, e por aí vai.

Existe algum problema em se migrar um sistema desenvolvido no Access para outro banco de dados,
por exemplo ORACLE ? Não existe "quase" nenhum problema na migração de sistemas com o Delphi,
normalmente não é preciso mudar uma única linha de programação para se utilizar o mesmo sistema em
bancos de dados completamente diferente (desde óbvio siga-se alguns passos básico). O único problema que
existe numa migração é quanto aos comandos SQL (Structure Query Language), pois infelizmente o Access
possui um SQL próprio não comum aos outros bancos de dados. Mas todos os problemas são facilmente
resolvidos criando-se variáveis globais para definir qual tipo de banco estamos lidando, qual o nome correto
da tabela e assim sucessivamente.

A ferramenta Delphi 4.0 possui uma conexão direta com o Banco de Dados MS-Access 97, para
tanto faz-se necessário de:

1. BDE (Borland DataBase Engine) para a versão 5.00


2. Biblioteca de acesso DAO 3.5 (IDDA3532.DLL) colocada no diretório do BDE - C:\Arquivos de
Programas\Borland\Common Files\BDE

A conexão do Delphi com o MS-Access funciona da seguinte maneira BDE - DAO - Banco Access,
então na verdade é preciso instalar o DAO (Data Access Objects), a Microsoft para as versões MS-Access
posteriores a 2.0 (que o acesso era feito com o JET) prendeu o instalador do DAO com os aplicativos de
desenvolvimento dela tais como: Visual Basic, MS-J++, MS-C++ e assim vai, então para ter a "correta"
licença de distribuição do DAO você precisa adquirir qualquer um desses aplicativos.

O DAO se faz necessário pois precisamos levar o sistema para o nosso cliente, e do mesmo modo
que você precisa instalar o sistema em Delphi, o MDB, o BDE client, você também precisará instalar o link
de conexão. Você poderá acertar o Install Shield (conforme a apostila 4) para instalar todas as bibliotecas de
acesso do DAO mas é necessário tê-las.

☞ Importante - o BDE 5.00 pode operar tanto com o DAO 3.0 quanto com o 3.5.Para definir qual será
utilizado, voce precisa informar no BDE Administrator qual a DLL que sera' utilizada para o driver
MSACCESS. A biblioteca DAO 3.0 é a IDDAO32.DLL e a Biblioteca DAO 3.5 é IDDA3532.DLL (Que
será a que utilizaremos)

Mas antes de se criar qualquer alias de conexão, entre no BDE Administrator e proceda a seguinte
troca na página Configuration, conforme a figura:

Prontinho basta agora sair e entrar novamente do BDE Administrator e criamos nossos Aliases de
conexão.
16 Curso de Delphi 4.0 - Principais Instruções em SQL

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Prefácio
Esta apostila foi desenvolvida com o auxílio on-Line do banco MS-ACCESS, este tipo de SQL para
este banco não é totalmente compatível com o SQL Padrão ANSI, que é o oficial na maioria dos bancos de
dados, então algumas cláusulas podem não funcionar em outros gerenciadores de bancos de dados.

Instrução SELECT
Instrui o programa principal do banco de dados para retornar a informação como um conjunto de registros.

Sintaxe
SELECT [predicado { * | tabela.* | [tabela.]campo1 [AS alias1] [, [tabela.]campo2 [AS alias2] [, ...]]}
FROM expressãotabela [, ...] [IN bancodedadosexterno]
[WHERE... ]
[GROUP BY... ]
[HAVING... ]
[ORDER BY... ]
[WITH OWNERACCESS OPTION]

A instrução SELECT tem as partes abaixo:

Parte Descrição
predicado Um dos seguintes predicados: ALL, DISTINCT, DISTINCTROW ou TOP.
Você usa o predicado para restringir o número de registros que retornam. Se
nenhum for especificado, o padrão será ALL.
* Especifica que todos os campos da tabela ou tabelas especificadas são
selecionados.
tabela O nome da tabela que contém os campos dos quais os registros são
selecionados.
campo1, campo2 Os nomes dos campos dos quais os dados serão recuperados. Se você incluir
mais de um campo, eles serão recuperados na ordem listada.
alias1, alias2 Os nomes que serão usados como títulos de colunas em vez dos nomes
originais das colunas na tabela.
expressãotabela O nome da tabela ou tabelas contendo os dados que você quer recuperar.
bancodedadosexterno O Nome do banco de dados que contém as tabelas em expressãotabela se não
estiver no banco de dados atual.

Comentários
Para executar esta operação, o programa principal de banco de dados procura a tabela ou tabelas
especificadas, extrai as colunas escolhidas, seleciona as linhas que satisfazem o critério e classifica ou agrupa
as linhas resultantes na ordem especificada.

A instrução SELECT não muda os dados no banco de dados.

SELECT é normalmente a primeira palavra em uma instrução SQL. A maior parte das instruções
SQL são instruções SELECT.

A sintaxe mínima da instrução SELECT é:


SELECT campos FROM tabela

Você pode usar um asterisco (*) para selecionar todos os campos na tabela. O exemplo abaixo
seleciona todos os campos na tabela Funcionários:
SELECT * FROM Funcionários;

Se o nome de um campo estiver incluído em mais de uma tabela na cláusula FROM, preceda-o com
o nome da tabela e o operador . (ponto). No exemplo abaixo, o campo Departamento está nas tabelas
Funcionários e Supervisores. A instrução SQL seleciona Departamento da tabela Funcionários e NomeSupv
da tabela Supervisores:

SELECT Funcionários.Departamento, Supervisores.NomeSupv


FROM Funcionários INNER JOIN Supervisores
WHERE Funcionários.Departamento = Supervisores.Departamento;

Ao criar um objeto Recordset, o programa principal de banco de dados do Jet usa o nome do campo
da tabela como o nome do objeto Field no objeto Recordset. Se você quiser um nome de campo diferente ou
um nome que não esteja implícito na expressão usada para gerar o campo, use a palavra reservada AS. O
exemplo abaixo usa o título Nasc para nomear o objeto Field retornado no objeto Recordset resultante:

SELECT DataNasc AS Nasc FROM Funcionários;

Sempre que você usar funções aggregate ou consultas que retornem nomes de objetos Field
ambíguos ou duplicados, você precisará usar a cláusula AS para fornecer um nome alternativo para o objeto
Field. O exemplo abaixo usa o título Contagem para nomear o objeto Field retornado no objeto Recordset
resultante:

SELECT COUNT(FuncionárioID) AS Contagem FROM Funcionários;

Você pode usar outras cláusulas na instrução SELECT para restringir e organizar posteriormente os
seus dados retornados.

Cláusula GROUP BY
GROUP BY é opcional. Valores de resumo são omitidos se não houver qualquer função aggregate
SQL na instrução SELECT. Os valores Null nos campos GROUP BY são agrupados e não omitidos. No
entanto, os valores Null não são avaliados em qualquer função aggregate SQL. Use a cláusula WHERE para
excluir linhas que você não quer agrupadas e use a cláusula HAVING para filtrar os registros após eles terem
sido agrupados.
A não ser que contenha dados Memo ou OLE Object, um campo na lista de campos GROUP BY
pode fazer referência a qualquer campo em qualquer tabela listada na cláusula FROM. Mesmo que o campo
não esteja incluído na instrução SELECT, fornecida a instrução SELECT, inclua pelo menos uma função
SQL. O programa principal de banco de dados do Jet não pode agrupar campos Memo ou OLE Objects.

Todos os campos na lista de campos SELECT devem ser incluídos na cláusula GROUP BY ou
incluídos como argumentos em uma função aggregate SQL.

Cláusula HAVING
HAVING é opcional. HAVING é semelhante a WHERE, que determina quais registros são
selecionados. Depois que os registros são agrupados com GROUP BY, HAVING determina quais registros
são exibidos:

SELECT CategoriaID, Sum(UnidadesNoEstoque) FROM Produtos


GROUP BY CategoriaID
HAVING Sum(UnidadesNoEstoque) > 100 AND LIKE "BOS*";

Uma cláusula HAVING pode conter até 40 expressões vinculadas por operadores lógicos, como And
ou Or.

Cláusula ORDER BY
ORDER BY é opcional. Entretanto, se você quiser exibir seus dados na ordem classificada, você
deve utilizar ORDER BY. O padrão ordem de classificação é ascendente (A a Z, 0 a 9). Os dois exemplos
abaixo classificam os nomes dos funcionários pelo sobrenome.

SELECT Sobrenome, Nome FROM Funcionários ORDER BY Sobrenome;

SELECT Sobrenome, Nome FROM Funcionários ORDER BY Sobrenome ASC;

Para classificar em ordem descendente (Z a A, 9 a 0), adicione a palavra reservada DESC ao final de
cada campo que você quiser classificar em ordem descendente. O exemplo abaixo seleciona salários e os
classifica em ordem descendente

SELECT Sobrenome, Salário FROM Funcionários ORDER BY Salário DESC, Sobrenome;

Se você especificar um campo que contém dados Memo ou OLE Objects na cláusula ORDER BY,
um erro ocorrerá. O programa principal de banco de dados do Jet não classifica campos deste tipo. ORDER
BY é normalmente o último item em uma instrução SQL.

Você pode incluir campos adicionais na cláusula ORDER BY. Os registros são classificados
primeiro pelo primeiro campo listado depois de ORDER BY. Os registros que tiverem valores iguais naquele
campo são classificados pelo valor no segundo campo listado e assim por diante.

Cláusula WITH OWNERACCESS OPTION


A declaração WITH OWNERACCESS OPTION é opcional. O exemplo abaixo habilita o usuário a
ver as informações de salário (mesmo que não tenha outra permissão para ver a tabela Folha de Pagamentos)
desde que o proprietário da consulta tenha tal permissão:

SELECT Sobrenome, Nome, Salário FROM Funcionários ORDER BY Sobrenome


WITH OWNERACCESS OPTION;
Se, por outro lado, um usuário for impedido de criar ou anexar a uma tabela, você poderá usar WITH
OWNERACCESS OPTION para habilitá-lo a executar uma consulta construção de tabela ou consulta
anexação. Se você quiser reforçar as configurações de segurança do grupo de trabalho e as permissões dos
usuários, não inclua a declaração WITH OWNERACCESS OPTION. Esta opção exige que você tenha acesso
ao arquivo System.mda associado ao banco de dados. É realmente útil em implementações de multiusuários
seguras.

Exemplo da instrução SELECT, cláusula FROM


Esse exemplo seleciona os campos "Sobrenome" e "Nome" de todos os registros da tabela
"Funcionários".

SELECT Sobrenome, Nome FROM Funcionários

Esse exemplo seleciona todos os campos da tabela "Funcionários".

SELECT Funcionários.* FROM Funcionários;

Esse exemplo conta o número de registros que têm uma entrada no campo "CódigoPostal" e nomeia
o campo retornado como "Tcp".

SELECT Count(CódigoPostal) AS Tcp FROM Clientes;

Esse exemplo mostra qual seria o salário se cada funcionário recebesse um aumento de 10 porcento.
Não altera o valor original dos salários.

SELECT Sobrenome, Salário AS Atual, Salário * 1.1 AS Proposto FROM Funcionários;

Esse exemplo coloca o título Nome no topo da coluna "Sobrenome". O título Salário é exibido no
topo da coluna "Salário".

SELECT Sobrenome AS Nome, Salário FROM Funcionários;

Esse exemplo mostra o número de funcionários e os salários médio e máximo.

SELECT Count(*) AS [Total de Funcionários], Avg(Salário) AS [Salário Médio], Max(Salário) AS [Salário


Máximo] FROM Funcionários;

Para cada registro, mostra Sobrenome e Salário no primeiro e último campos. A seqüência de
caracteres "tem um salário de" é retornada como o campo do meio de cada registro.

SELECT Sobrenome, 'tem um salário de', Salário FROM Funcionários;

Exemplo de cláusula GROUP BY


Esse exemplo cria uma lista de nomes de departamentos únicos e o número de funcionários em cada
um destes departamentos.

SELECT Departamento, Count([Departamento]) AS Tbc FROM Funcionários


GROUP BY Departamento;

Para cada título de função único, calcula o número de funcionários do departamento de Vendas que
têm este título.

SELECT Título, Count(Título) AS Tbc FROM Funcionários


WHERE Departamento = 'Vendas' GROUP BY Título;
Esse exemplo calcula o número de itens em estoque para cada combinação de número e cor do item.

SELECT Item, Sum(Unidades) AS Tbc FROM ItensEmEstoque


GROUP BY Item, Cor;

Exemplo de cláusula HAVING


Esse exemplo seleciona os títulos de cargos do departamento de Produção atribuídos a mais de 50
funcionários.

SELECT Título, Count(Título) FROM Funcionários WHERE Departamento = 'Produção'


GROUP BY Título HAVING Count(Título) > 50;

Esse exemplo seleciona os departamentos que tenham mais de 100 funcionários.

SELECT Departamento, Count([Departamento]) FROM Funcionários


GROUP BY Departamento HAVING Count(Departamento) > 100;

Exemplo de cláusula ORDER BY


As instruções SQL mostradas abaixo usam a cláusula ORDER BY para classificar os registros em
ordem alfabética e depois por categoria.

Esse exemplo ordena os registros pelo sobrenome, em ordem descendente (Z-A).

SELECT Sobrenome, Nome FROM Funcionários ORDER BY Sobrenome DESC;

Esse exemplo ordena, primeiro, por categoria ID e depois por nome do produto.

SELECT CategoriaID, ProdutoNome, PreçoUnit FROM Produtos


ORDER BY CategoriaID, NomeProduto;

Instrução INSERT INTO


Adiciona um ou vários registros a uma tabela. Isto é referido como consulta anexação.

Sintaxe
Consulta anexação de vários registros:

INSERT INTO destino [IN bancodedadosexterno] [(campo1[, campo2[, ...]])]


SELECT [origem.]campo1[, campo2[, ...]
FROM expressãodetabela
Consulta anexação de um único registro:

INSERT INTO destino [(campo1[, campo2[, ...]])]


VALUES (valor1[, valor2[, ...])

A instrução INSERT INTO tem as partes abaixo:

Parte Descrição
destino O nome da tabela ou consulta em que os registros devem ser anexados.
bancodedadosexterno O caminho para um banco de dados externo. Para uma descrição do
caminho, consulte a cláusula IN.
origem O nome da tabela ou consulta de onde os dados devem ser copiados.
campo1, campo2 Os nomes dos campos aos quais os dados devem ser anexados, se
estiverem após um argumento destino ou os nomes dos campos dos quais
se deve obter os dados, se estiverem após um argumento origem.
expressãodetabela O nome da tabela ou tabelas das quais registros são inseridos. Este
argumento pode ser um único nome de tabela ou uma combinação
resultante de uma operação INNER JOIN, LEFT JOIN ou RIGHT JOIN
ou de uma consulta gravada.
valor1, valor2 Os valores para inserir em campos específicos do novo registro. Cada valor
é inserido no campo que corresponde à posição do valor na lista: Valor1 é
inserido no campo1 do novo registro, valor2 no campo2 e assim por
diante. Você deve separar os valores com uma vírgula e colocar os
campos de textos entre aspas (" ").

Comentários
Você pode usar a instrução INSERT INTO para adicionar um único registro a uma tabela usando a
sintaxe de consulta anexação de um único registro como mostrado acima. Neste caso, seu código especifica o
nome e o valor de cada campo do registro. Você precisa especificar cada um dos campos do registro para os
quais um valor deve ser designado e um valor para este campo. Quando você não especifica cada campo, o
valor padrão ou Null é inserido nas colunas omitidas. Os registros são adicionados no final da tabela.

Você também pode usar INSERT INTO para anexar um conjunto de registros de outra tabela ou
consulta usando a cláusula SELECT ... FROM como é mostrado acima na sintaxe consulta anexação de vários
registros. Neste caso, a cláusula SELECT especifica os campos para acrescentar à tabela destino especificada.

A tabela de origem ou de destino pode especificar uma tabela ou uma consulta. Se uma consulta for
especificada, o programa principal de banco de dados do Microsoft anexa a qualquer e a todas as tabelas
especificadas pela consulta.

INSERT INTO é opcional, mas quando incluída, precede a instrução SELECT.

Se sua tabela de destino contém uma chave primária, você deve acrescentar valores únicos, não Null
ao campo ou campos da chave primária. Caso contrário, o programa principal de banco de dados do Jet não
anexará os registros.

Se você anexar registros a uma tabela com um campo Counter e quiser numerar novamente os
registros anexados, não inclua o campo Counter em sua consulta. Inclua o campo Counter na consulta se
quiser manter os valores originais do campo.

Use a cláusula IN para anexar registros a uma tabela de outro banco de dados. Para achar quais
registros serão anexados, antes de você executar a consulta anexação, primeiro execute e veja os resultados de
uma consulta seleção que use o mesmo critério de seleção.
Uma operação de consulta anexação copia os registros de uma ou mais tabelas em outra. As tabelas
que contêm os registros que você anexa não são afetadas pela operação de consulta anexação.

Em lugar de acrescentar registros existentes de outra tabela, você pode especificar o valor de cada
campo em um único registro novo usando a cláusula VALUES. Se você omitir a lista de campo, a cláusula
VALUES deve incluir um valor para cada campo na tabela; caso contrário, um erro ocorrerá em INSERT.
Use uma instrução adicional INSERT INTO com uma cláusula VALUES para cada registro adicional que
você quiser criar.

Exemplo de instrução INSERT INTO


Esse exemplo seleciona todos os registros de uma tabela hipotética "Novos Clientes" e os adiciona à
tabela "Clientes" (quando não são designadas colunas individuais, os nomes das colunas das tabelas SELECT
devem corresponder exatamente aos da tabela INSERT INTO).

INSERT INTO Clientes SELECT [Novos Clientes].*


FROM [Novos Clientes];

Esse exemplo cria um novo registro na tabela "Funcionários"

INSERT INTO Funcionários (Nome,Sobrenome, Título)


VALUES ("André", "Pereira", "Estagiário");

Esse exemplo seleciona todos os estagiários de uma tabela hipotética "Estagiários" que foram
contratados há mais de 30 dias e adiciona seus registros à tabela "Funcionários".

INSERT INTO Funcionários SELECT Estagiários.*


FROM Estagiários WHERE DataContrato < Now() - 30;

Declaração UPDATE
Cria uma consulta atualização que altera os valores dos campos em uma tabela especificada com base em
critérios específicos.

Sintaxe
UPDATE tabela
SET valornovo
WHERE critério;

A instrução UPDATE tem as partes abaixo:

Parte Descrição
tabela O nome da tabela cujos os dados você quer modificar.
valornovo Uma expressão que determina o valor a ser inserido em um campo específico nos
registros atualizados.
critério Uma expressão que determina quais registros devem ser atualizados. Só os registros
que satisfazem a expressão são atualizados.

Comentários
UPDATE é especialmente útil quando você quer alterar muitos registros ou quando os registros que
você quer alterar estão em várias tabelas. Você pode alterar vários campos ao mesmo tempo. O exemplo
abaixo aumenta o Valor do Pedido em 10 por cento e o valor do Frete em 3 por cento para embarques do
Reino Unido:

UPDATE Pedidos SET ValorPedido = ValorPedido * 1.1, Frete = Frete * 1.03


WHERE PaísEmbarque = 'RU';

UPDATE não gera um conjunto de resultados. Se você quiser saber quais resultados serão alterados,
examine primeiro os resultados da consulta seleção que use os mesmos critérios e então execute a consulta
atualização.

Exemplo de instrução UPDATE


Esse exemplo muda os valores no campo "RelatórioPara" para 5 para todos os registros de
funcionários que atualmente têm valores de RelatórioPara de 2.

UPDATE Funcionários SET RelatórioPara = 5 WHERE RelatórioPara = 2;

Esse exemplo aumenta o "PreçoUnit" de todos os produtos não suspensos do fornecedor 8 em 10


porcento.

UPDATE Produtos SET PreçoUnit = PreçoUnit * 1.1


WHERE FornecedorID = 8 AND Suspenso = No;

Esse exemplo reduz o PreçoUnit de todos os produtos não suspensos fornecidos pela Tokyo Traders
em 5 porcento. As tabelas "Produtos" e "Fornecedores" têm uma relação um para vários.

UPDATE Fornecedores INNER JOIN Produtos

ON Fornecedores.FornecedorID = Produtos.FornecedorID SET PreçoUnit = PreçoUnit * .95


WHERE NomeEmpresa = 'Tokyo Traders' AND Suspenso = No;

Instrução DELETE
Cria uma consulta exclusão que remove registros de uma ou mais tabelas listadas na cláusula FROM que
satisfaz a cláusula WHERE.
Sintaxe
DELETE [tabela.*]
FROM tabela
WHERE critério

A instrução DELETE tem as partes abaixo:

Parte Descrição
tabela.* O nome opcional da tabela da qual os registros são excluídos.
tabela O nome da tabela da qual os registros são excluídos.
critério Uma expressão que determina qual registro deve ser excluído.

Comentários

DELETE é especialmente útil quando você quer excluir muitos registros. Para eliminar uma tabela
inteira do banco de dados, você pode usar o método Execute com uma instrução DROP.

Entretanto, se você eliminar a tabela, a estrutura é perdida. Por outro lado, quando você usa
DELETE, apenas os dados são excluídos. A estrutura da tabela e todas as propriedades da tabela, como
atributos de campo e índices, permanecem intactos.

Você pode usar DELETE para remover registros de tabelas que estão em uma relação um por vários
com outras tabelas. Operações de exclusão em cascata fazem com que os registros das tabelas que estão no
lado "vários" da relação sejam excluídos quando os registros correspondentes do lado "um" da relação são
excluídos na consulta. Por exemplo, nas relações entre as tabelas Clientes e Pedidos, a tabela Clientes está do
lado "um" e a tabela Pedidos está no lado "vários" da relação. Excluir um registro em Clientes faz com que os
registros correspondentes em Pedidos sejam excluídos se a opção de exclusão em cascata for especificada.

Uma consulta de exclusão exclui registros inteiros e não apenas dados em campos específicos. Se
você quiser excluir valores de um campo específico, crie uma consulta atualização que mude os valores para
Null.

Importante
Após remover os registros usando uma consulta exclusão, você não poderá desfazer a operação. Se
quiser saber quais arquivos foram excluídos, primeiro examine os resultados de uma consulta seleção que use
o mesmo critério e então, execute a consulta exclusão. Mantenha os backups de seus dados. Se você excluir os
registros errados, poderá recuperá-los a partir dos seus backups.

Exemplo de instrução DELETE


Esse exemplo exclui todos os registros de funcionários cujo título seja Estagiário. Quando a cláusula
FROM inclui apenas uma tabela, não é necessário indicar o nome da tabela na instrução DELETE.

DELETE *FROM Funcionários WHERE Título = 'Estagiário';

Esse exemplo exclui todos os registros de funcionários cujo título seja Estagiário e que também
tenham um registro na tabela "FolhadePagamento". As tabelas "Funcionários" e "FolhadePagamento" têm
uma relação um por um.

DELETE Funcionários.* FROM Funcionários INNER JOIN FolhaDePagamento


ON Funcionários.FuncionárioID = FolhadePagamento.FuncionárioID
WHERE Funcionários.Título = 'Estagiário';
Subconsultas SQL
Uma subconsulta é uma instrução SELECT aninhada dentro de uma instrução SELECT, INSERT,
DELETE ou UPDATE ou dentro de uma outra subconsulta.

Sintaxe
Você pode usar três formas de sintaxe para criar uma subconsulta:

comparação [ANY | ALL | SOME] (instruçãosql)


expressão [NOT] IN (instruçãosql)
[NOT] EXISTS (instruçãosql)

Uma subconsulta tem as partes abaixo:

Parte Descrição
comparação Uma expressão e um operador de comparação que compara a expressão com o resultado
da subconsulta.
expressão Uma expressão para a qual o resultado definido da subconsulta é procurado.
instruçãosqlt Uma instrução SELECT de acordo com as mesmas regras e formato de qualquer outra
instrução SELECT. Ela deve estar entre parênteses.

Comentários
Você pode usar uma subconsulta em vez de uma expressão na lista de campo de uma instrução
SELECT ou em uma cláusula WHERE ou HAVING. Em uma subconsulta, você usa uma instrução SELECT
para fornecer um conjunto de um ou mais valores específicos para avaliar as expressões das cláusulas
WHERE ou HAVING.

Use o predicado ANY ou SOME, que são sinônimos, para recuperar registros na consulta principal
que satisfaçam a comparação com quaisquer registros recuperados na subconsulta. O exemplo abaixo retorna
todos os produtos cujo preço unitário é maior que o preço de qualquer produto vendido com um desconto de
25 por cento ou mais:

SELECT * FROM Produtos WHERE PreçoUnit > ANY


(SELECT PreçoUnit FROM PedidoDetalhes WHERE Desconto >= .25);

Use o predicado ALL para recuperar apenas os registros na consulta principal que satisfaçam a
comparação com todos os registros recuperados na subconsulta. Se você mudou ANY para ALL no exemplo
acima, a consulta retornaria apenas os produtos cujo preço unitário fosse maior que o de todos os produtos
vendidos com um desconto de 25 por cento ou mais. Isto é muito mais restritivo.

Use o predicado IN para recuperar apenas os registros na consulta principal para os quais alguns
registros na subconsulta contêm um valor igual. O exemplo abaixo retorna todos os produtos com um
desconto de 25 por cento ou mais:
SELECT * FROM Produtos WHERE ProdutoID IN
(SELECT ProdutoID FROM PedidoDetalhes WHERE Desconto >= .25);

De maneira contrária, você pode usar NOT IN para recuperar apenas os registros na consulta
principal para os quais não existam registros com valores iguais na subconsulta. Utilize o predicado EXISTS
(com a palavra reservada NOT opcionalmente) em comparações true/false para determinar se a subconsulta
retorna algum registro.

Você também pode usar aliases de nomes de tabelas em uma subconsulta para fazer referência a
tabelas listadas em uma cláusula FROM fora da subconsulta. O exemplo abaixo retorna os nomes dos
funcionários cujos salários sejam iguais ou superiores à média de salários de todos os funcionários na mesma
função. Para a tabela Funcionários é dada o alias "T1":

SELECT Sobrenome, Nome, Título, Salário FROM Funcionários AS T1


WHERE Salário >= (SELECT Avg(Salário)
FROM Funcionários WHERE T1. T1.Título = Funcionários.Título) Order by Title;

No exemplo acima, a palavra reservada AS é opcional. Algumas subconsultas são aceitas em


consultas de tabela cruzada especialmente como predicados (as da cláusula WHERE). Subconsultas como
saída (as da lista SELECT) não são aceitas em tabelas de referência cruzada.

Exemplos de subconsultas SQL


Esse exemplo lista o nome, título e salário de todos os representantes de vendas cujos salários sejam
superiores aos de todos os gerentes e diretores.
SELECT Sobrenome, Nome, Título, Salário FROM Funcionários
WHERE Título LIKE "*Repr Vendas*" AND Salário > ALL
(SELECT Salário FROM Funcionários WHERE (Título LIKE "*Gerente*")
OR (Título LIKE "*Diretor*"));

Esse exemplo lista o nome e preço unitário de todos os produtos cujo preço unitário seja igual ao do
Licor de Cacau.

SELECT NomeProduto, PreçoUnit FROM Produtos


WHERE PreçoUnit = (SELECT PreçoUnit FROM [Produtos]
WHERE NomeProduto = "Licor de Cacau");

Esse exemplo lista a empresa e o contato de cada empresa de todos os clientes que fizeram pedidos
no segundo trimestre de 1995.

SELECT NomeContato, NomeEmpresa, ContatoTítulo, Fone FROM Clientes


WHERE ClienteID IN (SELECT ClienteID FROM Pedidos
WHERE DataPedido BETWEEN #1/04/95# AND #1/07/95#);

Esse exemplo lista os funcionários cujo salário seja maior que a média dos salários de todos os
funcionários.

SELECT Sobrenome, Nome, Título, Salário FROM Funcionários T1


WHERE Salário >= (SELECT AVG(Salário) FROM Funcionários
WHERE Funcionários.Título = T1.Título) ORDER BY Título;

Esse exemplo seleciona o nome de todos os funcionários que tenham registrado pelo menos um
pedido. Isto também poderia ser feito com INNER JOIN.
SELECT Nome, Sobrenome FROM Funcionários AS E
WHERE EXISTS (SELECT * FROM Pedidos AS O
WHERE O.FuncionárioID = E.FuncionárioID);

Altera o campo Efetuado do arquivo de serviços para 2 caso o mesmo tenha parecer técnico da
entidade encaminhanhamento diferente de nulo.
UPDATE servico SET efetuado = 2
WHERE numero_servico = ANY (SELECT servico.numero_servico
FROM servico INNER JOIN encaminhamento
ON (servico.numero_servico = encaminhamento. numero_servico)
AND (servico. ano_servico = encaminhamento.ano_servico)
WHERE (((servico.efetuado) Is Null) AND ((encaminhamento.parecer_tecnico) Is Not Null))
GROUP BY servico.numero_servico ORDER BY servico.numero_servico);
17 Curso de Delphi 4.0 - Programação Orientada a Objetos

Autor: Fernando Antonio F. Anselmo


eMail: fernandoans@geocities.com
Pré-Requisitos:

• Windows 98
• Delphi 4.0 versão Client/Server Suite
• BDE 5.00
• MS-Access 97

Prefácio
Para você poder compreender melhor o ambiente de desenvolvimento Delphi, é necessário
que seja apresentado alguns conceitos da POO (Programação Orientada a Objetos). Não os
confunda com POE (Programação Orientada a Eventos), muito difundido com a linguagem
encontrada com o MS-Access, o Access-Basic (um ambiente baseado em Objetos). Vou tentar expor
aqui as sensíveis diferenças que existem entre esses dois conceitos.
A POO e a POE são facilmente confundidas, mas lembre-se, a POO contém a POE, mas a
POE não contém a POO; um objeto pode existir mesmo que para ele não exista nenhum evento
associado, mas é impossível existir um evento se não houver um objeto associado. Outra
característica que pode causar confusão, são ambientes Orientados a Objetos e ambientes
Baseados em Objetos. Em ambiente Orientado a Objetos existe a possibilidade da criação e
manipulação de objetos, enquanto que o Baseado em Objetos esta possibilidade é totalmente
inexistente o que existe é a simples manipulação ou no máximo uma derivação (criação de um a
partir de outro já existente) dos objetos.

A POO é um conceito desenvolvido para facilitar o uso de códigos de desenvolvimento em


interfaces gráficas. Sendo a Inprise, uma das primeiras a entrar neste novo conceito, possui suas
principais linguagens de programação (tais como Object Pascal e Object C), totalmente voltadas
para este tipo de programação. A POO atraiu muitos adeptos principalmente pelo pouco uso de
código que o Projeto (diferente de Sistema) carrega no programa fonte, ao contrário de linguagens
mais antigas como o Clipper’87 muito utilizado no final da década de 80 e início da década de 90.
O resultado desta “limpeza” resulta que uma manutenção no projeto é muito mais simples.

Para entender o sistema POO, vamos tentar pensar simples, imagine que você acabou de
adquirir uma caixa de bloquinhos de Lego, você pode criar várias coisas com eles, mas você possui
um número limitado de peças, você pode aumentar sua coleção, aumentando também a
possibilidade do número de coisas que você poderá criar, formando verdadeiras cidades de Lego.
Depois do comercial, a POO é basicamente isto, adquirindo o Delphi você está adquirindo um
ambiente totalmente flexível para a criação de um número de determinados sistemas, você pode
aumentar sua produtividade simplesmente aumentando o número de objetos. Os conceitos que vou
apresentar a seguir existem desde que foi sonhada a Orientação a Objetos, provavelmente você
deve conhecer uma boa parte, se não, então é a hora de você se familiarizar com este ambiente.
Conceitos da Orientação a Objeto
Antes de começarmos a falar realmente de linguagem orientada a objetos e necessário que
você possua os conceitos básicos da orientação a objetos, são eles:

Objeto - é qualquer estrutura modular que faz parte de um produto. Uma janela por exemplo, é
um objeto de uma casa, de um carro ou de um software com interface gráfica para o
usuário.
Atributos - São as características do objeto, como cor e tamanho, a janela, por exemplo, tem
atributos como o modelo, tamanho, abertura simples ou dupla, entre outros.
Encapsulação - é um mecanismo interno do objeto “escondido” do usuário. Uma pessoa pode
abrir uma janela girando a tranca sem precisar saber o que há dentro dela.
Ação - é a operação efetuada pelo objeto. Todas as janelas, por exemplo, controlam a
iluminação e temperatura ambiente, dependendo do seu design.
Herança - um objeto novo nem sempre é criado do zero. Ele pode “herdar” atributos e ações de
outros já existentes. Um basculante herda atributos das janelas e das persianas.
Polimorfismo - é a capacidade de objetos diferentes reagirem segundo a sua função a uma
ordem padrão. O comando “abre”, por exemplo, faz um objeto entrar em ação, seja ele uma
janela, uma porta ou uma tampa de garrafa.
Ligação - é quando um objeto conecta a sua ação a outro. Um sensor de claridade, por
exemplo, ativa o acendimento automático da iluminação de rua.
Embutimento - Permite a um objeto incorporar funções de outros, como um liqüidificador que
mói carne com a mudança do tipo da lâmina.
Linguagem Object Pascal
Object Pascal é uma linguagem Orientada a Objetos não é pura, mas, híbrida, por possuir
características de programação não só visual mas também escrita, para os programadores que já
conhecem técnicas de estruturas de programação, tais como C, Basic, Pascal ou xBASE entre outras
linguagens a Object Pascal providência uma migração de forma natural oferecendo um produto de
maior complexibilidade. Object Pascal força a executar passos lógicos. Isto torna mais fácil o
desenvolvimento em ambiente gráficos (tais como o Windows), de aplicações livres, ou que
utilizam banco de dados do tipo Cliente/Servidor. A linguagem trabalha com o uso de ponteiros
para a alocação de memória e todo o poder de um código totalmente compilável. Além disso,
possibilita a criação e reutilização (vantagem de re-uso tão sonhado com a Orientação a Objetos)
de objetos e bibliotecas dinâmicas (Dynamic Link Libraries - DLL).

Object Pascal contém todo o conceito da Orientação a Objetos, incluindo a herança, o


encapsulamento e o polimorfismo. Algumas extensões foram incluídas para facilitar o uso tais como
conceitos de propriedades, particulares e públicas, e tipos de informações em modo run-time,
manuseamento de exceções, e referências de classes. O resultado de toda esta junção faz com que
Object Pascal consiga suportar as facilidades de um baixo nível de programação, tais como:

• Controle e acesso das subclasses do Windows (API);


• Passar por cima das mensagens de loop do Windows;
• Mensagens semelhantes as do Windows;
• Código puro da linguagem Assembler.

Como deu para perceber a base de toda a programação Delphi é a linguagem Object Pascal
nunca diga então que você programa em Delphi e sim que você programa em Object Pascal, assim
como você nunca programou em Clipper mas em xBase, vamos aprender alguns conceitos básicos
dentro deste tipo de programação.

Símbolos Especiais
A Object Pascal aceita os seguintes caracteres ASCII:
• Letras - do Alfabeto Inglês: A até Z e a até z.
• Dígitos - Decimal: 0 até 9 e HexaDecimal: 0 até 9 e A até F (ou a até f)
• Brancos - Espaço (ASCII 32) e todos os caracteres de controle ASCII (ASCII 0 até ASCII
31), incluindo final de linha e Enter (ASCII 13).
• Especiais - Caracteres: + - * / = < > [ ] . , ( ) : ; ^ @ { } $ #
• Símbolos - Caracteres: <= >= := .. (* *) (. .) //

☞ Importante - O colchetes esquerdo “[” e equivalente ao “(.” e o colchetes direito “]” e


equivalente a “.)”.

☞ Importante - Os comentários são formados por chave esquerda “{” e equivalente ao


“(*” e fechados com a chave direita “}” e equivalente a “*)”. O comentário de uma linha é o “//”
(não é aceito pelo Delphi 1.0).
for i := 1 to 10 do // Este é o exemplo de um comentário apenas desta linha
for i := 1 to 10 do { Este é o exemplo de um comentário que pode ser em várias linhas }
for i := 1 to 10 do (*Este é o exemplo de um comentário que pode ser em várias linhas *)

Palavras Reservadas
Object Pascal se utiliza das seguintes palavras reservadas, não podendo as mesmas serem
utilizadas ou definidas:
And Exports Library Set
Array File Mod Shl
As Finnaly Nil Shr
Asm For Not String
Begin Function Object Then
Case Goto Of To
Class If On Try
Const Implementation Or Type
Constructor In Packed Unit
Destructor Inherited Procedure Until
Div Initialization Program Uses
Do Inline Property Var
Downto Interface Raise While
Else Is Record With
End Label Repeat Xor
Except

Uma outra lista a seguir, apresenta as diretivas que são utilizadas em contextos de
identificação de objetos:
Absolute Export Name Published
Abstract External Near Read
Assembler Far Nodefault Resident
At Forward Override Stored
Cdecl Index Private Virtual
Default Interrupt Protected Write
Dynamic Message Public

Números
É possível definir variáveis ou constantes com tipos Inteiros ou Numéricos de ponto
flutuante, a diferença entre os diversos tipos permitidos se deve a capacidade de armazenamento e o
espaço ocupado, veja a comparação nas tabelas abaixo:

Para os tipos Inteiros

Tipo Range Formato


Integer -2147483648..2147483647 32-bit + sinal
Shortint -128..127 8-bit + sinal
Smallint -32768..32767 16-bit + sinal
Longint -2147483648..2147483647 32-bit + sinal
Int64 -2^63..2^63-1 64-bit + sinal
Cardinal 0..4294967295 32-bit
Byte 0..255 8-bit
Word 0..65535 16-bit
Longword 0..4294967295 32-bit

Para os tipos Ponto Flutuante


Tipo Range Dígitos Significantes Tamanho em Bytes
Real48 2.9 x 10^-39 .. 1.7 x 10^38 11-12 6
Real 5.0 x 10^-324 .. 1.7 x 10^308 15-16 8
Single 1.5 x 10^-45 .. 3.4 x 10^38 7-8 4
Double 5.0 x 10^-324 .. 1.7 x 10^308 15-16 8
Extended 3.6 x 10^-4951 .. 1.1 x 10^4932 19-20 10
Comp -2^63+1 .. 2^63 -1 19-20 8
Currency -922337203685477.5808.. 19-20 8
922337203685477.5807

var
i : double; // Aqui crio uma variável i sendo Float
z : integer; // Aqui crio uma variável z sendo Inteira
t : real; // Aqui crio uma variável t sendo Real
begin
i := StrToFloat('10.23');
z := Round(i);
t := i;
end;

Constantes
Uma constante é um identificador com valor(es) fixo(s). Um bloco de declarações constante
possui a seguinte expressão:

[Declaração Constante] [Identificador] (=) [constante] (;)

A lista abaixo apresenta um conjunto de funções que podem ser utilizadas para a declaração
das constantes:
Ab Length Ord SizeOf
Chr Lo Pred Succ
Hi Low Ptr Swap
High Odd Round Trunc

Alguns exemplos para a definição de Constantes:


const
Min = 0;
Max = 100;
Centro = (Max - Min) div 2;
Beta = Chr(225);
NumLetras = Ord('Z') - Ord('A') + 1;
MensOla = 'Instrução inválida';
MensErro = ' Erro: ' + MensOla + '. ';
PosErr = 80 - Length(MensErro) div 2;
Ln10 = 2.302585092994045684;
Ln10R = 1 / Ln10;
DigNumericos = ['0'..'9'];
LetrasAlpha = ['A'..'Z', 'a'..'z'];
AlphaNum = LetrasAlpha + DigNumericos;
Expressões
As expressões em Object Pascal (como em qualquer linguagem) são formadas por
operadores e operandos; os operadores são divididos em quatro categorias básicas:
Únicos @, Not
Multiplicativos >, /, div, mod, and, shl, shr, as
Adicionais +, -, or, xor
Relacionais =, < >, <, >, < =, > =, in, is

As expressões obedecem as regras básicas de lógica para a precedência da execução das


operações.

Identificadores
Identificadores podem ser constantes, tipos, variáveis, procedures, funções, unidades,
programas e campos de registros.

Não existe limite de caracteres para o nome de um identificador mas apenas os 63 primeiros
caracteres são significantes (não podendo ser idêntico ao nome das palavras reservadas). O nome de
um identificador deve ser iniciado por Letras ou o caracter underscore ( _ ). O resto é formado por
Letras, Dígitos, caracter underscore (ASCII $5F). Não é permitido a utilização de espaços para a
formação do nome.

☞Importante - Exemplo de identificadores válidos: Form1, SysUtils.StrLen,


Label1.Caption

with... do...;
Delimita um determinado bloco de declarações para um identificador específico evitando a
declaração deste identificador. A sintaxe do comando é: WITH {nome do identificador} DO
{comandos};. Ex.:

begin
{ ... comandos iniciais ... }
with form1 do
begin
Caption := ‘Teste’; // Equivalente a Form1.Caption
BorderStyle := bsSizable; // Equivalente a Form1.BorderStyle
end;
end;

array [ ... ] of ...;


Define um conjunto de variáveis ou constantes de um mesmo tipo. A sintaxe do comando é:
array [{quantidade de ocorrências}] of {Tipo};. Os arrays são controlados por três funções:

Função Valor de Retorno


Low Primeiro elemento
High Aponta para o último elemento
SizeOf Tamanho do array
Ex.:
const
t: array [1..50] of Char { Declara 50 elementos para o tipo Char }
var
s : array[1..100] of Real { Declara 100 elementos para o tipo real }
ind: Integer;
begin
for Ind := Low(s) to High(s) do s[Ind] := 0; { Zera os elementos do array S }
if SizeOf(t) = ‘C’ then exit; { Se o último elemento do array T for ‘C’ sai do bloco }
{ ... outros comandos... }
end;

Declarações
Declarações descrevem ações de um algorítmo a serem executadas.

begin... end;
Prende um conjunto de declarações em um bloco de comandos determinado. A sintaxe do
comando é: BEGIN {comandos} END;. Ex.:

begin
{ ... comandos iniciais ... }
begin
{ ... bloco 1 ... }
end;
begin
{ ... bloco 2 ... }
end;
{ ... comandos finais ... }
end;

if... then... else...;


Esta expressão escolhe entre o resultado de uma condição booleana o caminho verdadeiro
(then) ou falso (else). A sintaxe do comando é: IF {condição} THEN {bloco de comandos} ELSE
{bloco de comandos};. Ex.:

begin
{ ... comandos iniciais ... }
if x > 2 then
{ ... Bloco verdadeiro ... }
else
{ ... Bloco falso ... };
end;

goto... ;
Transfere a execução de um programa para o ponto determinado pelo Label. A sintaxe do
comando é: GOTO {Label};. Ex.:

label
primeiro;
begin
{ ... comandos iniciais ... }
if x = 2 then
goto primeiro;
{ ... outros comandos ... }
Primeiro:
{ ... comandos do Primeiro ... }
end;

case... of... else... end;


Consiste de uma lista de declarações que satisfaz a condição de um seletor de expressões, se
nenhuma parte da lista satisfizer ao seletor executa os comandos do sub-comando else. Para o
seletor serão válidos os tipos definidos, tipo Inteiros ou LongInt. A sintaxe do comando é: CASE
{seletor} OF {Expressão 1}: {comando da expressão 1}; {Expressão 2}: {comando da
expressão 2}; {Expressão n}: {comando da expressão n} ELSE {comando}; end;. Ex.:

begin
{ ... comandos iniciais ... }
case x of
1: { ... Bloco para x = 1 ... }
2, 3: { ... Bloco para x = 2 ou X = 3... }
4..6: { ... Bloco para 4 <= x <= 6 ... }
else
{ ... Bloco para x < 1 ou x > 6 ... };
end;
end;

repeat... until;
Repete um determinado bloco de declarações até a condição booleana do subcomando until ser
satisfeita. A sintaxe do comando é: REPEAT {comandos}; until {condição};. Ex.:

begin
{ ... comandos iniciais ... }
x := 0;
repeat
x := x + 1
until (x = 2);
end;

for... to (downto)... do...;


Incrementa em 1 uma determinada variável inteira, repetindo um bloco de comandos, até que
esta atinja o valor final do intervalo, o subcomando downto realiza o incremento reverso. A sintaxe
do comando é: FOR {variável} := {valor inicial} to (downto) {valor final} do {bloco de
comandos};. Ex.:

begin
{ ... comandos iniciais ... }
for i := 1 to 10 do // Executa o [comandos A] para i = 1,2,3,4,5,6,7,8,9 e 10
{ ... Comandos A ... }
for s := 10 downto 1 do // Executa o [comandos B] para i = 10,9,8,7,6,5,4,3,2 e 1
{ ... Comandos B... }
end;

while... do...;
Repete um bloco de comandos enquanto que determinada condição booleana seja satisfeita. A
sintaxe do comando é: WHILE {condição} DO {bloco de comandos};. Ex.:

begin
{ ... comandos iniciais ... }
while i := 1 do // Repete o [Bloco de comandos] enquanto i = 1
{ ... Bloco de comandos ... }
end;

break; ou continue...;
O comando break interrompe um bloco de repetição for, while ou repeat saindo do bloco. A
sintaxe do comando é: BREAK; enquanto que o comando continue retorna a primeira instrução do
bloco de repetição for, while ou repeat. A sintaxe do comando é: CONTINUE;. Ex.:

begin
{ ... comandos iniciais ... }
for i := 1 to 10 do
begin
if i = 8 then
break; // Salta para os [comandos C]
{... comandos A...}
if i = 5 then
continue; // Retorna para o comando for pulando os [comandos B]
{... comandos B ...}
end;
{... comandos C ...}
end;

Blocos de Procedimentos ou Funções


As procedures ou funções são declaradas na seção de tipos de declarações (abaixo do
comando type) pertencendo ao objeto ou serem do tipo public (públicas - executadas por outras
unidades) ou private (particulares - restritas a unidade local).

Procedure
procedure {cabeçalho}; var {declaração das variáveis}; {bloco de comandos};

O cabeçalho da procedure é composto pelo nome do procedimento e variáveis que serão


recebidas (ou modificadas através da declaração var, ex.: “procedure teste(var x:string);”).

procedure soma(a,b: integer); // Início enviando as variáveis A e B do tipo inteiro.


var // Declaração de variáveis locais a procedure
c: integer;
begin // Corpo do procedimento.
c := a + b;
end;

Function
function {cabeçalho} : {resultado}; var {declaração das variáveis}; {bloco de comandos};

As funções se diferem dos procedimentos pela obrigatoriedade do retorno de um resultado,


podendo este resultado ser retornado pela declaração: {nome da função} := valor ou result :=
valor.

function soma(a,b: integer) : integer; // Início enviando as variáveis A e B do tipo inteiro.


begin // Corpo do procedimento.
soma := a + b; // ou result := a + b;
end;

☞ Importante - Junto com o Delphi vem o manual Object Pascal Reference em formato
.HLP, caso a linguagem seja novidade para você aconselho que você dê uma boa olhada (o Delphi
1.0 traz o mesmo manual, mas em formato .PDF), mas não se preocupe com o que foi explicado
acima já está mais do que suficiente para um bom entendimento com o Object Pascal.

Tudo o que vimos acima é o que normalmente temos em outras linguagens comuns, mas o
caracteriza realmente a linguagem Orientada em Objetos é o trabalho e a manipulação com os
mesmos.