Você está na página 1de 179

Apostila

Delphi 4.0

Captulo 1
CAPTULO 1 ..............................................................................................................................................2 CAPTULO 01 - INICIANDO O DELPHI...............................................................................................8 ......................................................................................................................................................................8 PRINCPIOS DA PROGRAMAO WINDOWS ................................................................................................9 INICIANDO O DELPHI ...............................................................................................................................10 CRIANDO UM PRIMEIRO PROGRAMA........................................................................................................12 Propriedades do Formulrio ..............................................................................................................12 Colocando Componentes ....................................................................................................................12 Alterando as Propriedades dos Componentes ....................................................................................13 Respondendo a Eventos ......................................................................................................................13 Testando o Programa .........................................................................................................................14 Salvando o Programa .........................................................................................................................14 AMBIENTE DE PROGRAMAO ................................................................................................................14 Programao Orientada a Objeto (POO) ..........................................................................................14 EVENTOS E PROCEDIMENTOS...................................................................................................................14 COMPONENTES ........................................................................................................................................15 Viso Geral dos Componentes............................................................................................................15 PROPRIEDADES ........................................................................................................................................16 MTODOS ................................................................................................................................................16 OBJECT PASCAL E BIBLIOTECAS ..............................................................................................................17 VCL - VISUAL COMPONENT LIBRARY .....................................................................................................17 OBJETOS ..................................................................................................................................................17 RESUMO ..................................................................................................................................................17 PROJETOS ................................................................................................................................................17 Salvando o Projeto em Disco..............................................................................................................18 Comandos para trabalhar com Projetos ............................................................................................18 GRUPOS DE PROJETOS .............................................................................................................................19 Comandos para tabalhar com grupos de projetos..............................................................................19 EDIES DO DELPHI ................................................................................................................................19 CAPTULO 3 EXEMPLOS ADICIONAIS............................................................................................21 EXEMPLO: CALCULADORA ......................................................................................................................22 Criando os Componentes....................................................................................................................22 Tratando os Eventos ...........................................................................................................................23 Executando o Programa .....................................................................................................................24 Melhoras de Interface .........................................................................................................................24 Salvando o Projeto..............................................................................................................................24 CAPTULO 4 VARIVEIS E TIPOS DE DADOS ...............................................................................25 TIPOS DE DADOS......................................................................................................................................26 Tipos Numricos .................................................................................................................................26 O tipo Char .........................................................................................................................................27 O tipo String .......................................................................................................................................27 O tipo Boolean ....................................................................................................................................28 O tipo TDateTime ...............................................................................................................................28 FUNES DE CONVERSO........................................................................................................................29 OPERAES ARITMTICAS ......................................................................................................................29 TIPOS ORDINAIS ......................................................................................................................................30 ESCOPO DE VARIVEIS ............................................................................................................................31 Variveis Locais .................................................................................................................................31 Variveis Globais da Unidade............................................................................................................31 Variveis Globais do Projeto..............................................................................................................31

CONSTANTES ...........................................................................................................................................31 CAPTULO 5 ESTRUTURAS DE CONTROLE ..................................................................................33 INSERINDO COMANDOS COM O CODEINSIGHT ..........................................................................................34 ESTRUTURAS DE DECISO .......................................................................................................................34 O Comando if...then...else...................................................................................................................34 O Comando case...of...........................................................................................................................35 ESTRUTURAS DE LAOS...........................................................................................................................37 O comando for ....................................................................................................................................37 O comando while...do... ......................................................................................................................37 O comando repeat..until .....................................................................................................................37 OUTROS COMANDOS ...............................................................................................................................38 Comandos para sair de laos .............................................................................................................38 O comando exit ...................................................................................................................................38 CAPTULO 6 PROPRIEDADES E EVENTOS COMUNS..................................................................39 TIPOS DE PROPRIEDADES .........................................................................................................................40 PROPRIEDADES MAIS USADAS .................................................................................................................41 Propriedades para Todos os Componentes ........................................................................................41 Propriedades de Tamanho e Posio .................................................................................................41 Propriedades do Formulrio ..............................................................................................................41 Propriedades de Controles .................................................................................................................42 EVENTOS COMUNS ..................................................................................................................................43 Eventos de Mouse ...............................................................................................................................43 Eventos de Teclado .............................................................................................................................43 Eventos do Formulrio .......................................................................................................................44 Outros Eventos....................................................................................................................................44 DETALHES DO TRATAMENTO DE EVENTOS ..............................................................................................45 Tratando um Evento para Vrios Controles: OnKeyPress.................................................................45 Renomeando um Procedimento de Evento..........................................................................................45 Associando um Procedimento Existente .............................................................................................46 Eliminando um Procedimento de Evento............................................................................................46 CAPTULO 7 USANDO VRIOS FORMULRIOS...........................................................................47 CAIXAS DE DILOGO ...............................................................................................................................48 FUNES DE MENSAGEM.........................................................................................................................48 Mensagens Informativas .....................................................................................................................48 Mensagens de Confirmao................................................................................................................48 EXEMPLO: CALCDATA ............................................................................................................................49 Pedindo Confirmao ao Usurio ......................................................................................................50 Criando um Novo Formulrio ............................................................................................................50 Salvando o Projeto..............................................................................................................................51 Executando um Arquivo......................................................................................................................51 GERENCIANDO OS ARQUIVOS DO PROJETO ..............................................................................................52 Usando a Speedbar ou Menus ............................................................................................................53 Usando o Project Manager.................................................................................................................53 DEFININDO O FORMULRIO PRINCIPAL ...................................................................................................56 CAPTULO 8 ESTRUTURA DAS UNIDADES ....................................................................................57 ESTRUTURA GERAL DAS UNIDADES ........................................................................................................58 O CDIGO GERADO PELO DELPHI ............................................................................................................58 Seo de Interface...............................................................................................................................58 UNIDADES ASSOCIADAS E INDEPENDENTES.............................................................................................59 COMPILAO DE UNIDADES ....................................................................................................................60 USANDO UMA UNIDADE ..........................................................................................................................60 RESOLVENDO CONFLITOS DE NOMES ......................................................................................................62 CAPTULO 9 OUTROS TIPOS DE DADOS E DEPURAO ..........................................................63 TIPOS ENUMERADOS................................................................................................................................64

Operaes com Ordinais ....................................................................................................................64 Tipos Enumerados no Delphi..............................................................................................................64 TIPOS FAIXA ............................................................................................................................................65 Opo "Range Checking" ...................................................................................................................65 VETORES .................................................................................................................................................65 Vetores Estticos.................................................................................................................................65 Verificao de Faixa para Vetores .....................................................................................................66 Usando Outros Tipos de ndice ..........................................................................................................66 Vetores Dinmicos..............................................................................................................................67 Vetores Multidimensionais..................................................................................................................67 EXEMPLO: CLCULO DE MDIA ..............................................................................................................68 Declarando o Vetor ............................................................................................................................68 Adicionando um Elemento ..................................................................................................................68 Limpando a Lista ................................................................................................................................69 Calculando a Mdia dos Elementos....................................................................................................69 Testando o Programa .........................................................................................................................69 Salvando o Projeto..............................................................................................................................70 CONJUNTOS .............................................................................................................................................70 Verificando Elementos ........................................................................................................................70 Operaes com Conjuntos ..................................................................................................................70 Propriedades de Conjunto ..................................................................................................................71 DEPURAO ............................................................................................................................................72 Colocando um Ponto de Parada.........................................................................................................72 Executando Passo a Passo..................................................................................................................72 Executando At o Cursor ....................................................................................................................72 Vendo Valores de Variveis................................................................................................................73 Monitorando o Valor de uma Varivel Dinamicamente .....................................................................73 Forando a Finalizao do Programa ...............................................................................................74 Outras Ferramentas de Depurao ....................................................................................................74 10 - PROCEDIMENTOS E FUNES..................................................................................................75 PROCEDIMENTOS GERAIS ........................................................................................................................76 Criando um Procedimento Geral........................................................................................................76 UNIDADES INDEPENDENTES.....................................................................................................................76 Criando uma Unidade Independente ..................................................................................................77 Transferindo o Procedimento .............................................................................................................77 Usando a Unidade no Mesmo Projeto ................................................................................................77 Usando a Unidade em Outros Projetos ..............................................................................................77 Gerenciando um Projeto com Unidades Independentes .....................................................................78 Criando uma Biblioteca de Rotinas ....................................................................................................78 FUNES .................................................................................................................................................79 Criando uma Funo ..........................................................................................................................79 Retornando um Valor..........................................................................................................................79 Chamando a Funo...........................................................................................................................79 PASSAGEM DE PARMETROS ...................................................................................................................80 Declarao de Parmetros e Argumentos ..........................................................................................80 Tipos de Passagem..............................................................................................................................80 CAPTULO 11 OBJETOS .......................................................................................................................82 O QUE CONTM UM OBJETO....................................................................................................................83 CLASSES E OBJETOS ................................................................................................................................83 HERANA ................................................................................................................................................84 Hierarquia de Classes do Delphi........................................................................................................84 O Object Browser ...............................................................................................................................84 Simplificando o Acesso aos Campos...................................................................................................84 FORMULRIOS COMO OBJETOS ................................................................................................................86 A Classe de Formulrio ......................................................................................................................86 Procedimentos na classe de formulrio..............................................................................................87 VARIVEIS DE OBJETO ............................................................................................................................87

LISTAS DE STRINGS .................................................................................................................................90 Propriedades da String List ................................................................................................................90 Mtodos da String List ........................................................................................................................90 Criando String Lists Independentes....................................................................................................90 OBJETOS PREDEFINIDOS ..........................................................................................................................91 O Objeto Application ..........................................................................................................................91 O Objeto Clipboard ............................................................................................................................91 O Objeto Screen..................................................................................................................................92 CODE EXPLORER .....................................................................................................................................92 PROGRAMAO ORIENTADA A OBJETOS .................................................................................................93 CAPTULO 12 APLICAES DE BANCO DE DADOS ....................................................................95 TERMOS USADOS .....................................................................................................................................96 DESKTOP X CLIENTE/SERVIDOR ..............................................................................................................97 FORMATOS DE BANCOS DE DADOS ..........................................................................................................97 CRIANDO TABELAS..................................................................................................................................98 Definindo um Diretrio de Trabalho ..................................................................................................98 Definindo a Estrutura dos Campos.....................................................................................................98 Salvando a Tabela ..............................................................................................................................99 Entrando com Dados ..........................................................................................................................99 EXEMPLO: USANDO O DATABASE FORM WIZARD .................................................................................101 Criando um campo autoincremento..................................................................................................101 Criando um Formulrio para Acessar a Tabela com Form Wizard.................................................101 Testando o Programa .......................................................................................................................102 Salvando o Projeto............................................................................................................................102 RESUMO DOS COMPONENTES DE DADOS ...............................................................................................102 APELIDOS DE BANCOS DE DADOS ..........................................................................................................103 CAPTULO 13 RECURSOS ADICIONAIS ........................................................................................105 DEFININDO TABELAS .............................................................................................................................106 Reestruturando a Tabela "Cliente"...................................................................................................106 Criando um ndice Secundrio .........................................................................................................107 Criando a Tabela "Venda"................................................................................................................107 Criando Integridade Referencial ......................................................................................................107 Criando a Tabela de Itens.................................................................................................................107 Criando a tabela Fornecedores ........................................................................................................108 CRIANDO O MENU PRINCIPAL................................................................................................................109 O MenuDesigner: criando menus .....................................................................................................109 Tratando Eventos de Menus..............................................................................................................111 Teclas de Acesso e Teclas de Atalho.................................................................................................111 ALTERANDO O MENU PRINCIPAL...........................................................................................................112 Alterando Propriedades....................................................................................................................112 Acrescentando os formulrios anteriores .........................................................................................112 Associando os formulrios aos itens de menu ..................................................................................112 USANDO O CONTROLE DBGRID ............................................................................................................113 Criando os Componentes de Dados..................................................................................................113 Manipulando dados no DBGrid........................................................................................................113 Usando o Editor de Campos .............................................................................................................114 Alterando a Mscara de Edio .......................................................................................................114 CAPTULO 14 VALIDAO E PESQUISAS ....................................................................................116 EXEMPLO: CLIENTE POR ESTADO ..........................................................................................................117 EXEMPLO: CLIENTES - ALTERANDO ......................................................................................................117 VALIDAO DE CAMPOS E REGISTROS ..................................................................................................118 Validando Campos............................................................................................................................118 Validando Registros..........................................................................................................................120 TRATAMENTO DE EXCEES .................................................................................................................121 Visualizando Informaes sobre Excees .......................................................................................122 Classes de Excees..........................................................................................................................122

PESQUISAS NA TABELA ..........................................................................................................................122 Adicionando um DBGrid ..................................................................................................................122 Utilizando um ndice Secundrio......................................................................................................123 Pesquisando pelo Nome....................................................................................................................124 Pesquisando pelo Cdigo .................................................................................................................124 BLOCOS PROTEGIDOS ............................................................................................................................125 CAPTULO 15 ACESSO S/ CONTROLE DE DADOS ......................................................................126 ESTADOS DE UMA TABELA ....................................................................................................................127 MTODOS PARA PERCORRER DADOS .....................................................................................................128 Mtodos de Abertura e Fechamento .................................................................................................128 Mtodos para Percorrer Registros ...................................................................................................128 Exemplo: Percorrendo a Tabela de Itens .........................................................................................129 MTODOS PARA MODIFICAR DADOS .....................................................................................................131 Editando Registros............................................................................................................................131 Acrescentando Registros...................................................................................................................131 Excluindo Registros ..........................................................................................................................132 Outros Mtodos.................................................................................................................................132 EVENTOS DOS COMPONENTES DE DADOS ..............................................................................................134 Eventos do Componente Table..........................................................................................................134 MANIPULAO DE DATAS .....................................................................................................................135 EXEMPLO: CRIANDO FORMULRIO SEM UTILIZAR O DBNAVIGATOR......................................................137 TRATAMENTO DO ERRO 'KEY VIOLATION.' ............................................................................................140 USANDO UM CONTROLE DBLOOKUPCOMBOBOX .................................................................................140 CAPTULO 16 UTILIZANDO MESTRE/DETALHE .......................................................................142 CRIANDO UM FORMULRIO MESTRE/DETALHE .....................................................................................143 Usando o DFW para criar o formulrio...........................................................................................143 Testando o Formulrio Gerado ........................................................................................................144 Analisando o Formulrio..................................................................................................................144 Alterando Propriedades do Formulrio ...........................................................................................145 Salvando o Projeto............................................................................................................................145 USANDO TRS TABELAS NO FORMULRIO ............................................................................................146 Ligando os Componentes de Dados..................................................................................................146 Criando Controles de Dados ............................................................................................................146 Criando Campos Calculados............................................................................................................147 Usando um campo Lookup................................................................................................................147 Testando e Salvando o Projeto .........................................................................................................148 Atualizando Quantidade em Estoque ...............................................................................................149 CAPTULO 17 CONSULTAS E SQL ..................................................................................................151 EXEMPLO: USANDO CONSULTAS ...........................................................................................................152 Criando o Formulrio ......................................................................................................................152 Obtendo um Resultado Modificvel ..................................................................................................153 Simplificando o Select.......................................................................................................................153 Alterando a Consulta ........................................................................................................................153 Alterando a Consulta Dinamicamente ..............................................................................................153 Alterando Outras Partes da Consulta...............................................................................................155 EXEMPLO: CONSULTANDO VRIAS TABELAS ........................................................................................156 Consulta com Duas Tabelas .............................................................................................................156 Consultando Trs Tabelas ................................................................................................................157 Usando Campos Calculados no SQL................................................................................................157 Usando Funes de Resumo .............................................................................................................157 OUTROS COMANDOS SQL .....................................................................................................................158 Testando Comandos SQL..................................................................................................................158 Alterando Registros ..........................................................................................................................158 Excluindo Registros ..........................................................................................................................159 Inserindo e Copiando Registros........................................................................................................159 Executando um Comando de Atualizao.........................................................................................159

CONSULTAS NUM AMBIENTE CLIENTE/SERVIDOR .................................................................................159 MTODOS E EVENTOS DO COMPONENTE QUERY ...................................................................................160 CAPTULO 18 INSTALADOR E ALIAS LOCAL .............................................................................161 USANDO UM ALIAS LOCAL ....................................................................................................................162 Usando o Componente Database......................................................................................................162 Alterando os Componentes de Dados ...............................................................................................163 Alterando o Caminho em Tempo de Execuo .................................................................................163 CRIANDO UM PROGRAMA INSTALADOR .................................................................................................164 Iniciando o InstallShield ...................................................................................................................164 Criando um Instalador......................................................................................................................164 Definindo as Opes de Instalao ..................................................................................................165 Definindo os Arquivos Utilizados .....................................................................................................165 Escolhendo as caixas de dilogo ......................................................................................................165 Definindo os cones do Programa ....................................................................................................166 Gerando os disquetes de instalao..................................................................................................167 CAPTULO 19 RELATRIOS.............................................................................................................167 CONCEITOS DO QUICKREPORT ..............................................................................................................168 A pgina QReport .............................................................................................................................168 Construindo o Relatrio ...................................................................................................................169 USANDO O QUICKREPORT WIZARD .......................................................................................................170 Imprimindo o Relatrio ....................................................................................................................170 Analisando o Relatrio Gerado ........................................................................................................171 CRIANDO UM RELATRIO COM VRIAS TABELAS .................................................................................171 Inserindo um Nmero de Pgina ......................................................................................................172 Visualizando o Relatrio...................................................................................................................173 Acrescentando Vrias Tabelas ao Relatrio.....................................................................................173 Conectando as Tabelas .....................................................................................................................173 Criando Sub-detalhes para Vendas ..................................................................................................174 Criando Sub-detalhes para Itens de Venda ......................................................................................174 Formatando os Campos....................................................................................................................175 Criando um Campo Calculado .........................................................................................................175 Criando um Sub-total........................................................................................................................177 Chamando o Relatrio a Partir do Menu .........................................................................................177 BIBLIOGRAFIA SUGERIDA ......................................................................................................................179

Captulo 01 - Iniciando o Delphi


Princpios da Programao Windows Iniciando o Delphi Criando um Primeiro Programa

Princpios da Programao Windows


Antes de comear a trabalhar com o Delphi, importante ter algumas noes do que est envolvido na programao Windows e no Delphi em particular. Algumas coisas tornam a tarefa de programao no Windows bem diferente de outros ambientes: Independncia do Hardware:No Windows, o acesso aos dispositivos de hardware feito com intermdio de drivers fornecidos pelo fabricante de hardware, o que evita que o programador tenha que se preocupar com detalhes especficos do hardware. Configurao Padro: O Windows armazena centralmente as configuraes de formato de nmeros, moeda, datas e horas, alm da configurao de cores, livrando o programador de se preocupar com esses detalhes especficos. Multitarefa: No DOS, um programa geralmente toma o controle da mquina s para si, e outros programas no rodam enquanto isso. J no Windows vrios programas so executados de maneira simultnea e no h como evitar isso. Controle da Tela: No DOS geralmente um programa ocupa todo o espao de telas, e o usurio v e interage apenas com aquele programa. J no Windows [janelas], toda informaes mostradas e todas entradas recebidas do usurio so feitas por meio de uma janela, uma rea separada da tela que pode ser sobreposta por outras janelas (de outros programas por exemplo). Padres de Interface: No Windows, todos os elementos de interface aparecem para o usurio e interagem da mesma forma. Alm disso, existem padres definidos pela Microsoft que so recomendados para conseguir a consistncia entre aplicativos. Falaremos de alguns deles no curso, mas a melhor forma de aprend-los praticar com os aplicativos Windows mais usados do mercado. Cooperao com o Sistema: Num programa DOS, a execuo segue uma ordem prestabelecida pelo programador, e o programa s chama o sistema operacional quando precisa de alguma coisa dele. J no Windows, o programa deve responder a eventos, que so ativados pelo Windows quando alguma coisa acontece externamente (ou seja, uma ao do usurio, ou uma aviso do sistema). Isso, como veremos, afeta radicalmente o estilo de programao e a forma de pensar no programa. A sequncia de execuo do programa depende da sequencia de eventos.

Iniciando o Delphi
Inicie o Delphi atravs do seu cone no Windows, se voc j tiver um atalho para o do Windows e depois em programa na sua rea de trabalho. Seno, clique no menu Programas|Borland Delphi 4|Delphi 4. A tela bsica do Delphi tem os seguintes elementos:

Ao pressionar F12 ir aparecer a seguinte tela:+

Nota: para criar um atalho para o Delphi, consulte a documentao do Windows. Localize o arquivo executvel DELPHI32.EXE sob o diretrio de instalao. Formulrio (Form1): Um formulrio a janela do seu programa, o local onde voc projeta a sua interface com o usurio. Durante o projeto, o formulrio aparece de forma praticamente

10

idntica ao que o usurio final ver, mas permite que voc faa alteraes no posicionamento dos componentes (elementos de tela) e em suas propriedades (caractersticas); Speedbar: Uma barra de botes na janela principal do Delphi, que contm botes para executar os comandos mais usados do Delphi; Paleta de Componentes: Tambm na janela principal, dividida em vrias pginas, onde cada uma contm vrios tipos de componentes que voc pode escolher para colocar no formulrio; Object Inspector: [inspetor de objeto]: Dividido em duas pginas, onde uma contm as propriedades do componente selecionado, e a outra uma lista de eventos associados a este componente, que define as aes externas as quais voc pode tratar; Menu Principal: Contm os comandos do ambiente de programao do Delphi, por exemplo, para tratamento de arquivos, definio de opes, etc. Code Editor: (Aparece atrs do formulrio, inicialmente). Contm o cdigo-fonte do projeto. Com ele, voc pode facilmente mudar entre os vrios arquivos utilizados no projeto ou mesmo abrir um arquivo de texto qualquer.

11

Criando um Primeiro Programa


No Delphi voc inicia o projeto da sua aplicao escolhendo componentes, que so os objetos de interface com o usurio e alterando as caractersticas desses componentes como por exemplo, cor, tamanho, fonte de caracteres, atravs das propriedades. Por ltimo, voc decide quais eventos voc quer tratar e escreve o cdigo de programa que executado por esses eventos. Nosso primeiro programa ir mostrar uma lista de nomes e permitir ao usurio adicionar itens na lista, limpar a lista e ordenar a lista em ordem alfabtica. O programa ter uma interface como a seguir, com uma lista de itens, um quadro de texto que permite digitar o prximo item da lista, e botes para manipular a lista:

Para cri-lo, precisamos alterar propriedades do formulrio e colocar componentes em cima dele.

Propriedades do Formulrio
Propriedades do formulrio so as caractersticas que definem sua aparncia, e algumas vezes, seu comportamento. O Object Inspector lista todas as propriedades do formulrio, que so inicializadas com valores padro quando o projeto criado. Por exemplo, o ttulo que aparece no formulrio (inicialmente Form1) uma propriedade que voc pode alterar no Object Inspector. Selecione a propriedade Caption no Object Inspector. Clique na coluna da direita (que contm o valor da propriedade) e digite o texto Primeiro Programa Delphi. medida que voc digita, o formulrio reflete essa alterao na sua barra de ttulo.

Colocando Componentes
Um formulrio vazio no muito til, portanto vamos colocar componentes nesse formulrio. A Paleta de Componentes contm vrios cones, onde cada um representa um tipo de componente que voc pode colocar no formulrio. Ela tambm dividida em pginas, que podem ser acessadas clicando no marcador de pgina correspondente. Quando voc passa o cursor do mouse por cima de um cone, ela mostra o nome daquele componente. Clique na pgina Standard e depois clique no cone (Edit). Agora clique no formulrio. Vai aparecer um quadro de edio chamado "Edit1". Depois iremos alterar esse nome padro. Para mud-lo de posio no formulrio, posicione o cursor em cima dele, pressione e segure o boto do mouse, e arraste-o para outra posio, ao arrastar o componente ser mostrado as coordenadas (x, y) indicando a posio do componente no formulrio . Ou, se preferir, usando o teclado, segure a tecla [Ctrl] e use as teclas de seta para moviment-lo. Agora precisamos de um quadro de lista. Clique no cone (ListBox) da paleta de componentes, na mesma pgina Standard, depois clique no formulrio, um pouco abaixo do quadro de texto (no se preocupe com alinhamento). Para aumentar seu tamanho lateral, clique na ala mais direita, segure o boto do mouse e arraste-o para a direita. Ou, usando o teclado, segure [Shift] e pressione a seta para a direita.

12

Vamos colocar trs botes no formulrio. Como so vrios controles do mesmo tipo, podemos fazer o seguinte: segure [Shift] e clique no cone (Button) da paleta de componentes. Agora clique trs vezes no formulrio, colocando um boto abaixo do outro. No se preocupe com o alinhamento por enquanto Depois clique no cone do ponteiro ( formulrio deve ficar parecido com o seguinte: ).O

Clique no boto (Run) da SpeedBar. O Delphi ir compilar o programa, gerando um arquivo executvel e vai iniciar sua execuo. Durante a execuo, voc pode digitar texto no quadro de texto, e clicar nos botes. Depois tecle [Alt+F4] para terminar o programa (ou feche a janela com o mouse). Repare que o Delphi cuida de toda a parte de interface com o usurio. Voc no precisa escrever cdigo para mostrar uma janela na tela nem seus componentes. Mas para definir o que o programa vai fazer, isto , como ele reage aos eventos externos, voc precisa escrever cdigo.

Alterando as Propriedades dos Componentes


Para mudar a aparncia dos componentes, alteraremos suas propriedades. importante notar que o Object Inspector disponibiliza as propriedades do componente que estiver selecionado, ou seja, com as alas de marcao. Quando voc clica em um componente com o mouse, ele selecionado e voc pode alterar suas propriedades. Quando voc clica numa regio vazia do formulrio (ou pressiona [Esc]), voc pode alterar as propriedades do formulrio. Selecione o quadro de texto e depois clique na propriedade Text no Object Inspector. Apague o valor atual (que Edit1). Assim esse componente no vai mais comear mostrando "Edit1" no seu contedo. Agora clique no primeiro boto (Button1) e altere sua propriedade Caption para Adicionar. Isso define o texto do boto. Clique no segundo boto (Button2) e altere Caption para "Ordenar" e no terceiro boto, altere Caption para "Limpar".

Respondendo a Eventos
Todo o cdigo no Delphi executado, direta ou indiretamente, em resposta a eventos. Quando voc (ou o usurio) clica em um boto por exemplo, isso provoca um evento. Se existir um trecho de programa associado a esse evento (um procedimento de evento), esse trecho ser executado. Seno, o evento no vai fazer nada. Clique no boto Adicionar para selecion-lo. No Object Inspector, clique no marcador de pgina "Events". Essa pgina lista quais eventos so reconhecidos pelo componente. O primeiro deles, OnClick, acontece quanto o boto recebe um clique do mouse. Clique duas vezes na coluna da direita, e o Delphi vai abrir o editor de cdigo, contendo o seguinte texto: procedure TForm1.Button1Click(Sender: TObject); begin end; O cursor est posicionado entre os delimitadores begin e end, indicando onde voc deve escrever o cdigo, que ser executado ao clicar no boto Adicionar. Escreva o seguinte (diferenas entre maisculas e minsculas no importam): ListBox1.Items.Add(Edit1.Text);

13

Edit1.Clear; Pressione a tecla [F12] para voltar ao formulrio. Clique no boto Ordenar e depois clique duas vezes no valor do evento OnClick. Isso vai gerar um tratador de evento para o boto Ordenar. Escreva o seguinte entre o begin e o end: ListBox1.Sorted := True; Finalmente retorne ao formulrio, selecione o boto Limpar e siga o mesmo processo. Digite o seguinte cdigo: ListBox1.Clear; ListBox1.Sorted := False;

Testando o Programa
Agora execute o programa clicando no boto . Voc pode digitar um valor no quadro de texto, e clicar no boto Adicionar (ou teclar [Enter]). O item digitado ser acrescentado lista. Depois de acrescentar alguns itens, clique em Ordenar. A lista ser colocada em ordem alfabtica. Para esvaziar a lista, clique em Limpar.

Salvando o Programa
Para que voc possa usar esse programa mais tarde, clique em File|Save All (menu File, item Save All) ou no boto da SpeedBar. O Delphi vai pedir um nome para o arquivo do formulrio. Digite AULA1 e clique Ok. Depois o Delphi vai perguntar o nome do arquivo de projeto. Digite AULA1P e clique Ok (no use o mesmo nome que o formulrio). Nota: Voc tambm pode clicar no formulrio ou no editor de cdigo com o mouse, mas geralmente o mtodo mais rpido de alternar entre os dois usar a tecla [F12].

Ambiente de Programao
O Delphi possui um ambiente integrado de desenvolvimento (IDE - Integrated Development Environment) onde voc utiliza a maioria das funes de desenvolvimento. Nesse ambiente voc projeta o programa e depois executa o programa para testar o seu funcionamento. Sempre que voc executa o programa, o Delphi compila o programa, isto , gera um programa executvel com cdigo de mquina a partir do programa fonte que voc criou. Esses programas executveis se tornam independentes do Delphi e podem rodar separadamente.

Programao Orientada a Objeto (POO)


Para compreendermos melhor ambiente de desenvolvimento do Delphi necessrio que voc entenda os conceitos de Programao Orientada a Objetos(POO). A POO um forma de gerenciar a complexidade do programa, de forma que facilite a manuteno e a reutilizaco de partes do programa. O programa dividido em partes relativamente isoladas que podem ser alteradas de forma independente e podem ser reutilizadas mais facilmente em outros programas.Estas partes so chamadas de Classes (Iremos discutir em Objetos).

Eventos e Procedimentos
Programas DOS convencionais seguem um fluxo seqencial, em que um comando segue o outro de forma definida pelo programador. O usurio deve agir de acordo com os "modos" de operao do programa e saber o momento certo para entrar com comandos. Programas em uma interface multitarefa, como o Windows, apresentam todas as opes ao usurio, para que ele possa selecion-los na ordem em que desejar. O Windows intercepta as aes realizadas pelo usurio e informa ao programa onde, como e quando elas acontecem. O programa deve reagir de forma apropriada nos momentos determinados pelo usurio. Cada resultado de uma ao do usurio chamada de evento, por exemplo: clique do mouse, digitao de uma tecla, etc.

14

Como conseqncia, o programa no mais um bloco nico, mas dividida em pequenas sees, cada uma responsvel pela tarefa a realizar em resposta a um determinado evento. Essas sees so os procedimentos de evento do Delphi. Cada evento associado a um componente e cada componente tem uma lista de eventos que so acionados por ele em situaes especficas (o Object Inspector mostra esta lista na pgina Events). Com isso, o projeto de um programa feito iniciando pelo projeto de sua interface (seus componentes) e depois escrevendo-se os procedimentos de evento. No obrigatrio definir todos os eventos para um componente. Se no existe um procedimento para um evento especfico, simplesmente no acontece nada para aquele evento. Como veremos mais tarde, alm dos procedimentos de evento, voc pode dividir o seu programa, usando rotinas auxiliares. Nota: para melhor utilizao do ambiente de programao e da linguagem, consulte o help do Delphi. Os procedimentos de evento so armazenados na unidade, que um arquivo de texto associado ao formulrio. Voc pode editar todas as unidades no editor de cdigo do Delphi.

Componentes

A paleta de componentes lista tipos de componentes que podem ser utilizados no programa, como botes de pressionar, barras de rolagem, grades de dados e editores de texto. Para criar um componente, voc seleciona o cone correspondente e depois clica no formulrio para coloc-lo. Voc tambm pode cri-lo j com o tamanho desejado, pressionando o boto do mouse sobre o formulrio e arrastando para definir o tamanho. Nota: todos os componentes so descritos em detalhe no Help do Delphi, com todas suas propriedades, mtodos e eventos. Clique em um cone de componente e pressione F1 para ver o texto de help sobre ele. Note que h mais pginas do que cabe na tela em dado momento. Para ver as pginas que restantes, como Dialogs, Midas, Win 3.1, Samples e ActiveX, clique nos botes ficam na extremidade direita da janela do Delphi. Alguns componentes no aparecem para o usurio durante a execuo do programa, apesar de aparecer no formulrio, e serem manipulados pelo cdigo do programa. So os componentes no-visuais (veremos alguns deles no decorrer do curso). Mas a maioria aparece como um objeto de interface durante a execuo. So os controles (ou componentes visuais). importante lembrar que todo controle um componente, mas nem todo componente um controle. O prprio formulrio tambm considerado um componente, embora seja tratado de forma diferente, e geralmente contm vrios outros componentes.

Viso Geral dos Componentes


A paleta de componentes se divide em vrias pginas para facilitar a organizao. Ns veremos alguns deles no curso, mas importante ter uma noo geral do contedo dessas pginas. Standard: componentes padro da interface do Windows, usados para barras de menu, exibio de texto, edio de texto, seleo de opes, iniciar aes de programa, exibir listas de itens etc. Geralmente so os mais usados. Additional: componentes especializados que complementam os da pgina Standard. Contm botes com capacidades adicionais, componentes para exibio e edio de tabelas, exibio de imagens, grficos etc. Win32: componentes comuns de interface que so fornecidos pelo Windows 95/NT para os programas. Contm componentes para dividir um formulrio em pginas, edio de texto

15

formatado, barras de progresso, exibio de animaes, exibio de dados em rvore ou em forma de cones, barras de status e de ferramentas etc. System: componentes que utilizam funes avanadas do sistema operacional, como temporizao, multimdia, OLE e DDE. Internet: componentes para acesso aos recursos e protocolos da Internet, como criao de pginas Web dinmicas, acesso aos protocolos FTP, NNTP, POP, SMTP, TCP, UDP. Data Access: componentes para acesso a banco de dados. Data Controls: componentes visuais para mostrar dados em aplicaes de bancos de dados. So semelhantes aos componentes padro (Standard). Decision Cube (apenas Delphi Client/Server): componentes para anlise multidimensional de dados, com capacidades de tabulao cruzada [crosstab], criao de tabelas e grficos etc. QReport: QuickReport um gerador de relatrios que acompanha o Delphi. Os componentes desta pgina permitem desenhar o seu relatrio dentro do Delphi. Dialogs: O Windows tem caixas de dilogo comuns, como veremos, que facilitam mostrar uma interface padro dentro do seu programa para as tarefas comuns, como abrir e salvar arquivos, impresso, configurao de cores e fontes etc. Esta pgina tem componentes que permitem utilizar essas caixas de dilogo comuns. Midas (apenas Delphi Client/Server e Enterprise) : componentes utilizados para criar aplicaes multi-tiered. Win3.1: Esta pgina contm controles considerados obsoletos, que esto disponveis apenas para compatibilidade com programas antigos. No crie programas novos que utilizam esses controles. Samples: contm exemplos de componentes para que voc possa estud-los e aprender a criar seus prprios componentes. O cdigo fonte desses exemplos est no subdiretrio SOURCE\SAMPLES do diretrio de instalao do Delphi. ActiveX: um componente ActiveX um tipo de componente que pode ser criado em outra linguagem e utilizado no Delphi. Esta pgina contm alguns exemplos de componentes ActiveX prontos para utilizar, que tm funes de grficos, planilha, etc.

Propriedades
Componentes tm propriedades [properties], que definem suas caractersticas especficas e eventos, que so acontecimentos externos, geralmente relacionados com aes do usurio. Por exemplo o formulrio tem como propriedades o ttulo da janela (Caption), sua cor (Color), sua posio na tela (Left e Top). Um quadro de texto tem uma propriedade que define o texto que este contm (Text), entre outras. Quando o usurio clica com o mouse em um controle, isso causa um evento OnClick, e quando ele pressiona uma tecla, causa um evento OnKeyDown (entre outros). Para alterar propriedades durante o projeto da interface, voc seleciona o componente desejado (por exemplo Edit1), depois seleciona a propriedade desejada (por exemplo, Text) no Object Inspector e digita seu valor. Durante a execuo do programa, o cdigo pode alterar uma propriedade dinamicamente (em resposta a um evento). Para isso, basta inserir no cdigo de programa um comando como o seguinte: Edit1.Text := 'Bem-vindo ao Delphi'; Nota: se voc clicar em uma propriedade e teclar [F1], o Delphi mostrar o texto de help relacionado quela propriedade.

Mtodos
Mtodos so nomes para aes executadas por um componente. No programa anterior, por exemplo, usamos o mtodo Clear, que quando executado, limpa o contedo de um controle. Por exemplo, no programa anterior, o procedimento de evento do boto Adicionar faz: Edit1.Clear;

16

Quando esse comando executado, o controle esvaziado. Repare que todo mtodo chamado usando-se primeiro o nome do componente, depois o nome do mtodo, da mesma forma que uma propriedade. Mtodos s tem utilidade no cdigo do programa, por isso no aparecem no Object Inspector (mas veremos mais tarde que possvel consultar a lista de mtodos disponveis).

Object Pascal e Bibliotecas


Todo cdigo de programa no Delphi escrito em Object Pascal, que a linguagem de programao usada por ele. Essa linguagem derivada da linguagem Pascal original, e tem sido aperfeioada pela Borland por vrios anos, nas diversas verses do Turbo Pascal. A definio da linguagem contm as regras de sintaxe e os tipos de dados bsicos que voc pode usar. A maioria das rotinas teis do Delphi no fazem parte da linguagem em si, mas so implementados pela biblioteca de tempo de execuo [run-time library] do Delphi.

VCL - Visual Component Library


Os componentes, suas propriedades, eventos e mtodos so implementados pela biblioteca visual de componentes [Visual Component Library], tambm chamada VCL. O cdigo fonte da VCL fornecido com o Delphi e permite voc modificar os componentes ou estudar como eles foram feitos. Voc tambm pode criar novos componentes, escrevendo-os em Object Pascal. O prprio Delphi foi criado em Delphi, utilizando-se a linguagem Object Pascal e verses sucessivas do ambiente. Nota: se voc digitar apenas o nome do componente e um ponto, o CodeInsight do Delphi mostrar a lista das propriedades e mtodos disponveis. Ao continuar digitando, feita uma busca incremental nessa lista. Nota: para obter ajuda sobre qualquer elemento do Object Pascal ou da VCL, clique na palavra desejada, no editor de cdigo e pressione a tecla [F1].

Objetos
Componentes so apenas um tipo de objetos, que um termo bastante utilizado no Delphi. O prprio nome Object Pascal indica que se trata de uma linguagem orientada a objetos. Um objeto, numa definio prtica, uma rea de memria separada, contendo dados (variveis) e o cdigo que manipula esses dados. No caso de um componente, os dados aparecem como propriedades e o cdigo que os manipula composto de mtodos. Basicamente todo objeto contm propriedades e mtodos, mesmo que ele no possa ser colocado num formulrio e editado. Mais tarde veremos vrios exemplos de objetos que no so componentes

Resumo
Para dominar a programao em Delphi, preciso conhecer os componentes da VCL, os objetos das bibliotecas do Delphi e a linguagem Object Pascal, que o fundamento no qual tudo se baseia.

Projetos
O Delphi trata cada aplicativo que voc cria como um projeto, que uma lista dos arquivos necessrios para construir um programa. Para saber quais so os formulrios, as unidades correspondentes, etc., o Delphi nos fornece o Project Manager, que pode ser acessado atravs

17

do Menu View, opo Project Manager. A janela de ttulo do Delphi sempre tem, no ttulo, o nome Delphi - Nome do projeto. Um projeto em Delphi se compe de: Formulrios: um formulrio uma janela que projetamos no Delphi. Normalmente toda aplicao contm um ou mais formulrios. Cada formulrio tem uma unidade associada, que um arquivo contendo todo o cdigo associado a eventos; Unidades independentes: uma unidade independente contm cdigo do Delphi que no est necessariamente associado a nenhum formulrio ou controle em particular. Unidades independentes geralmente contm variveis e rotinas usadas por toda aplicao. Lembre-se que um projeto apenas uma lista dos arquivos usados para construir o programa, mas no os contm propriamente.

Salvando o Projeto em Disco


Ao gravar o projeto em disco, o Delphi cria vrios arquivos: dois para o projeto em si, e outros para cada formulrio e cada unidade independente usada. Os arquivos tm as seguintes extenses: Projeto: .DPR e .OPT (opes) Formulrios: .DFM e .PAS (unidade associada) Unidades independentes: .PAS Alm disso, o Delphi gera outros arquivos no diretrio do projeto, a maioria deles quando voc compila o programa (por exemplo, automaticamente ao executar): Unidade compilada: nome-da-unit.DCU Arquivo de recursos: nome-do-projeto.RES Programa compilado: nome-do-projeto.EXE Arquivos de backup: *.~PA, *.~DF, *.~DP Para salvar o projeto, juntamente com seus arquivos, use o item de menu File|Save All do Delphi. Da primeira vez que voc salva o projeto, o Delphi pede o nome do arquivo de formulrio (o padro "Unit1.PAS") e o nome do arquivo de projeto (o padro "Project1.dpr"). No necessrio digitar as extenses, pois o Delphi cuida de acrescent-las. Quando voc salva um arquivo de formulrio, o Delphi salva dois arquivos: a unidade associada ao arquivo [unit], com uma extenso .PAS, que um arquivo contendo todo o cdigo de programa associado aos eventos, bem como todo o cdigo gerado pelo Delphi, e outro arquivo contendo as propriedades do formulrio e de todos os componentes, com o mesmo nome de arquivo, mas com a extenso .DFM. O arquivo de projeto um arquivo .DPR, que corresponde ao cdigo principal do programa executvel. A partir desse arquivo, o Delphi localiza os outros arquivos necessrios. Nota: o nome do arquivo de projeto deve ser diferente de qualquer unidade do projeto.

Comandos para trabalhar com Projetos


Vrios comandos do menu File do Delphi so usados para trabalhar com os projetos e os arquivos que fazem parte deles: Cria um novo projeto vazio New Application Cria um novo formulrio e sua unidade New Form Abre um projeto ou unidade existente. Open... Mostra os arquivos utilizados recentemente e permite reabrir qualquer um deles. Reopen Salva o arquivo atual (unidade). Se esta a primeira vez que est sendo salvo, Save pergunta pelo nome. Salva uma cpia do arquivo atual com outro nome ou em outro diretrio. Save As... Salva o arquivo de projeto. Sempre pede o nome. Save Project As... Salva todos os arquivos do projeto e o prprio arquivo de projeto. S pede nomes de Save All arquivos para os que no foram salvos ainda.

18

Fecha o arquivo atual. Close Fecha todos os arquivos e o projeto atual. Close All Alm desses comandos, existem cones na SpeedBar que podem ser usados para essas tarefas: Equivale a File|Open, mas mostra apenas os arquivos de projeto. (Open project) O mesmo que File|Save all (Save all) O mesmo que File|Open Project... (Open Project) O mesmo que File|Save (Save ) Adiciona um arquivo ao projeto atual. (Add file to project) Remove um arquivo do projeto atual. (Remove file from project)

Grupos de Projetos
O delphi 4.0 permite trabalhar com mais de um projeto aberto, esses projetos podem ser definidos em um grupo. No menu View|Project Manager informado os projetos que pertencem a um determinado grupo.O arquivo de um grupo tem a extenso ".BPG"

Comandos para tabalhar com grupos de projetos


Vrios comandos do menu Project so usados para trabalhar com grupos de projetos , os principais so: Adiciona um novo projeto ao grupo. Add New Project Adiciona um projeto existente ao grupo Add Existing Project Compila somente as units que foram modificadas, do projeto ativo. Compile (Projeto Atual) Compila todas as units do projeto ativo, independente se foram ou no Build ( Projeto modificadas. Atual) Compila somente as units que foram modificadas, dos projetos pertencentes Compile All ao grupo. Projects Compila todas as units dos projetos pertencentes ao grupo, independente se Build All Projects foram ou no modificadas.

Edies do Delphi
O Delphi est atualmente na verso 4. Essa verso geralmente compatvel com programas desenvolvidos nas verses anteriores, embora alguns necessitem de modificao para funcionar, especialmente os feitos para a verso 1.0. importante saber tambm que existem vrias edies diferentes do Delphi, desde a Standard (a mais simples), passando pela Professional, que tem mais recursos, at a edio Client/Server Suite, mais sofisticada e com recursos teis para grandes empresas: Standard: muito limitada em recursos. Indicada apenas para quem tem interesse em desenvolvimento de pequenos programas ou para fins de aprendizado. Professional: inclui mais recursos que a edio Standard. Recomendada para desenvolvedores profissionais. Client/Server : inclui mais recursos que a Professional, especificamente voltados para grandes desenvolvedores que utilizam bancos de dados no padro cliente/servidor.

19

Note que o Delphi 4 s funciona para ambientes de 32 bits, ou seja, Windows 95/98/etc. e Windows NT. Se voc quiser desenvolver programas compatveis com Windows 3.x, voc deve utilizar a verso 1.0.

20

Captulo 3 Exemplos Adicionais


Exemplo: Calculadora

21

Exemplo: Calculadora
O nosso objetivo criar uma calculadora simples, que apenas soma dois nmeros fornecidos e mostra o resultado, semelhante figura:

Criando os Componentes
Para comear, inicie o Delphi ou, se o Delphi estiver aberto, crie um novo projeto com File |New Application e altere a propriedade Caption da janela principal (Form1) para "Calculadora". Agora grave o projeto usando File | Save All no menu do Delphi. D os nomes de CALC ao formulrio e CALCP ao projeto. Isso vai salvar trs arquivos em disco, como j vimos: CALC.PAS A unidade unidade associada ao formulrio CALC.DFM Contm a definio do formulrio e seus controles. CALCP.DPR O arquivo de projeto, que lista os nomes dos outros. D dois cliques no cone Edit para criar um quadro de edio no formulrio. Mova-o at o topo do formulrio e altere a sua propriedade Name, para "editOperando1". A propriedade Name determina o nome que ser usado no programa para manipular esse componente, que ser usado para receber o primeiro operando digitado. Repita as mesmas aes para criar outro quadro de texto para o segundo operando. Ele dever ficar logo abaixo do primeiro. D o nome "editOperando2". Agora crie um boto de comando, com um clique duplo na ferramenta . Altere o seu tamanho para ficar igual ao dos quadros de texto. Nota: Quando voc cria um componente, ele recebe um nome default como Edit1, Button1, etc. recomendvel dar um nome mais descritivo para que seja mais fcil entender o programa mais tarde. Nota: No curso adotaremos um padro para nomes de componentes: um prefixo de trs ou quatro letras que diz o tipo de componente (edit para Edit, btn para Button, etc.) seguido de um nome descritivo (no caso, Operando1). Veremos que esse padro facilita a compreenso dos programas.

Altere sua propriedade Caption para "=" (sinal de igual). Altere Name para "btnCalcula". Finalmente crie um quadro de texto, posicionando-o abaixo do boto de comando, que vai conter o resultado. D o nome de "editResultado".

22

Agora, para mostrar o sinal de "+" vamos usar um componente Label (rtulo), que apenas mostra um texto para o usurio, no permitindo alterao. Selecione o cone e desenhe um rtulo esquerda do editOperando2, como na figura. Altere sua propriedade Caption para conter um sinal de +. Para fazer com que esse sinal fique maior, selecione a propriedade Font, que corresponde s caractersticas do texto, e clique duas vezes do seu lado direito. Selecione "MS Sans Serif" na lista de fontes e um tamanho maior na lista "Tamanho". Depois clique Ok.

Tratando os Eventos
A interface da calculadora est pronta, mas ela ainda no executa a funo desejada. Precisamos acrescentar cdigo que leia os dois operandos, some os seus valores e coloque o resultado no ltimo quadro de texto. Clique duas vezes no boto 'btnCalcula', no formulrio. Isso vai criar um tratador de eventos para o evento padro do boto, que o evento OnClick. O Delphi vai gerar o seguinte cdigo: procedure TForm1.btnCalculaClick(Sender: TObject); begin end; Para fazer o clculo precisaremos de variveis. Uma varivel uma rea de memria que tem um nome e armazena um determinado valor. No Delphi, toda varivel tambm tem um tipo, que determina quais os valores que ela pode conter. Depois veremos todos os tipos de dados em detalhes, mas por enquanto, usaremos o tipo de dados 'double', que permite armazenar valores numricos com parte fracionria, com a preciso de 15 a 16 dgitos significativos. Nota: Voc pode tambm selecionar o evento no Object Inspector e criar o tratador a partir do nome dele, mas para o evento padro, mais rpido um clique duplo no prprio componente. Variveis so declaradas com a palavra var, informando-se o nome e o tipo das variveis. Antes da palavra reservada begin, acrescente o seguinte: var op1, op2: double; res: double; Isso declara trs variveis: 'op1', 'op2' e 'res', todas do tipo double. Repare que duas variveis do mesmo tipo podem ser declaradas separando-as por vrgula antes do tipo ou em uma declarao separada.No necessrio repetir o var para vrias declaraes, pois elas terminam quando se encontra o begin. Agora vamos utilizar essas variveis para obter os valores digitados pelo usurio. Para ler o valor digitado em um controle Edit, devemos ler a propriedade Text, s que essa propriedade tem um valor alfanumrico (pode conter letras e nmeros), logo precisamos convert-la para numrico. Isso feito com a funo StrToFloat: op1 := StrToFloat(editOperando1.Text); op2 := StrToFloat(editOperando2.Text); Depois basta somar as variveis e mostrar o resultado, utilizando novamente uma funo de converso: res := op1 + op2; editResultado.Text := FloatToStr(res); O resultado final, com todo o cdigo acrescentado, ser o seguinte: procedure TForm1.btnCalculaClick(Sender: TObject); begin op1 := StrToFloat(editOperando1.Text); op2 := StrToFloat(editOperando2.Text); res := op1 + op2; editResultado.Text := FloatToStr(res); end; Repare que foi utilizada a identao (deslocamento direita) dos comandos, mas isso no obrigatrio no Delphi. Foi utilizado apenas para facilitar a legibilidade. Nota: Nomes de variveis em Object Pascal podem ter at 63 caracteres e podem conter letras (A-Z, a-z), nmeros e o caractere '_'. O primeiro caractere no pode ser nmero. O Object Pascal no diferencia maisculas de minsculas (no case-sensitive).

23

Executando o Programa
Execute o programa com o boto ou a tecla [F9]. Digite um nmero no editOperando1 e outro no editOperando2 e depois clique no btnCalcula. Repare que voc pode usar a tecla [Tab] para passar de um controle para outro utilizando o teclado (e no [Enter], como no DOS). O controle que responde s teclas em determinado momento tem o foco de teclado. Cada controle indica o foco de forma diferente. Por exemplo, um controle Edit mostra o cursor de texto quando ele tem o foco, j um controle Button mostra um retngulo tracejado em volta do texto. Como veremos, esta ordem de foco pode ser alterada.

Melhoras de Interface
Alguns detalhes podem ser melhorados: primeiro, o quadro de edio 'editResultado' no deveria receber o foco quando o usurio pressiona [Tab] e no deveria permitir edio do texto, pois no faz muito sentido. Para isso, selecione o controle e altere sua propriedade TabStop para False. Voc pode fazer isso selecionando o valor a partir da lista (com o boto de seta) ou com um clique duplo no valor da propriedade, que alterna de True para False. Essa propriedade, quando False, faz com que o controle seja "pulado" pela tecla [Tab]. Tambm altere a propriedade ReadOnly para True, o que faz com que o controle no permita edio de seu valor. Outra mudana: como o usurio no usar a tecla [Enter], podemos fazer com que ela acione o boto "=". Basta alterar a propriedade Default do boto 'btnCalcula' para True (verdadeiro). Isso faz com que ele seja o boto default, que sempre acionado quando o usurio tecla [Enter]. Execute o programa e teste as modificaes. Ao executar o projeto podemos observar que os quadros de edio 'editOperando1', 'editOperando2' e 'editResultado' aparecem com seus respectivos nomes , o ideal seria aparecer inicialmente sem nenhuma informao, para fazer esta modificao vamos retornar ao projeto e alterar a propriedade Text de cada componente edit . a propriedade Text que indica o contedo do componente naquele momento, ao criar o componente edit e modificar a propriedade Name o delphi automaticamente coloca o mesmo contedo desta propriedade na propriedade Text, caso esta no tenha sido modificada antes.

Salvando o Projeto
Para salvar o projeto e todos os arquivos, basta usar File|Save All ou clicar no boto da SpeedBar. Com isso o Delphi vai salvar todas as alteraes feitas no projeto, como foi informado o nome do projeto e da unit ele no ir pedir novamente.

24

Captulo 4 Variveis e Tipos de Dados


Tipos de Dados Funes de Converso OPeraes Aritmticas Tipos Ordinais Escopo de Variveis Constantes

25

Tipos de Dados
Toda varivel tem um tipo, que determina quais os valores que voc pode colocar nessa varivel e quais as operaes que podem ser executadas sobre ela. Uma varivel de um tipo numrico, por exemplo, s pode receber valores numricos. Esses valores podem ser constantes, valores de outras variveis, ou expresses com operaes sobre valores. Para colocar um valor em uma varivel, usa-se o operador de atribuio: ':=' (dois-pontos-igual), que lido como "recebe". Por exemplo: procedure TForm1.Button1Click(Sender: TObject); var a: integer; { 'a' uma varivel do tipo Integer } b: integer; { 'b' idem } begin a := 2; b := a; b := b + 3; end; Geralmente, com algumas excees, uma varivel de um determinado tipo s pode receber valores deste tipo. No permitido, por exemplo, o seguinte: a := 'Nome'; ...pois apenas valores numricos podem ser colocados na varivel 'a'. Existem vrios tipos de dados numricos, e cada um tem uma determinada faixa de valores e ocupa um certo espao de memria. No permitido colocar em uma varivel um valor que esteja fora da faixa do seu tipo.

Tipos Numricos
A linguagem Object Pascal tem vrios tipos de dados para variveis numricas, que so os seguintes: Tipo Bytes Faixa de Valores Preciso(dgitos) Tipos Inteiros Shortint 1 -128 a 127 N/A Byte 1 0 a 255 N/A Smallint 2 -32768 a32767 N/A Word 2 0 a 65535 N/A Integer 4 -2 bilhes a 2 bilhes N/A (-2.147.483.648 a 2.147.483.647) Longint 4 -2.147.483.648 a 2.147.483.648 N/A Cardinal 4 0 a 4.294.967.295 N/A Longword 4 0 a 4.294.967.295 N/A Int64 8 - 2 63 a 2 63 N/A Tipos Reais Single Real48 Real Double Comp Currency Extended 1.5x10-45 a 3.4x1038 2.9x10-39 a 1.7x1038 5x10-324 a 1.7x10308 5x10-324 a 1.7x10308 -263 a 263
-922337203685477.5808 a 922337203685477.5807

4 6 8 8 8 8 10

3.6x10-4951 a 1.1x104932

7-8 11-12 15-16 15-16 19-20 19-20 19-20

*Nota: No Delphi 4, o tipo Real idntico ao tipo Double. No Delphi 3, o tipo Real tem uma faixa de valore menor que o Double e equivale ao tipo Real48 do Delphi 4. No recomendvel utilizar Real48, porque ele muito mais lento para clculos. A coluna "bytes" diz quantos bytes de memria so ocupados por uma varivel do tipo. Quanto maior a faixa de valores, em geral, maior o espao de memria. Os tipos numricos se dividem em tipos inteiros (ou integrais), que s permitem valores inteiros e tipos reais (ou de ponto flutuante [floating point]), que permitem valores com parte fracionria. Uma forma de entender a diferena que tipos inteiros so usados para contagem de

26

elementos, enquanto tipos reais so usados para medir alguma coisa. E essa medida nem sempre exata. Ao fazer clculos com variveis reais, nem sempre o resultado igual ao esperado. Por exemplo: var fracao, a, b: real; {'real' um tipo real} begin a := 1.0; { o mesmo que 1 } fracao := a / 3; b := fracao * 3; if a = b then ... { faz alguma coisa } end; Teoricamente no programa, 'a' igual a 'b', mas como tipos reais no representam valores exatos, a igualdade no exata. A varivel 'b' pode ter um valor de 0.99999999..., que ao ser comparado, no igual a 1.0. Cada tipo real tem uma certa preciso, indicada na tabela, que diz quantos dgitos significativos (dgitos excetuando zeros esquerda e direita) a varivel pode guardar, sem perda de preciso nos clculos. Assim, importante lembrar que os valores guardados em um desses tipos nem sempre exato. Geralmente os tipos inteiros so mais eficientes para clculos, e tambm mantm valores exatos para qualquer operao, desde que o resultado no saia da sua faixa de valores. Os tipos mais utilizados so smallint, para valores inteiros pequenos, integer ou Longint para valores inteiros maiores, e Double para valores reais com uma preciso razovel. Os tipos Shortint e Byte so utilizados quando preciso guardar um contador bem pequeno e necessrio economizar memria.Quando os tipos integer ou longint no so suficientes podemos usar os tipos longWord e int64 que existe somente nesta verso. O tipo Comp considerado como real, mas ele permite apenas valores inteiros. Ele til para valores monetrios.

O tipo Char
O tipo Char permite criar variveis que guardam caracteres individuais, como letras, dgitos, sinais de pontuao e caracteres de controle. Cada varivel do tipo Char s pode conter um caractere. Caracteres comuns (imprimveis) so representados entre aspas simples (apstrofos): var minhaVariavel: Char; ... ... minhaVariavel := 'A'; Um caractere tambm pode ser representado atravs do cdigo ASCII/ANSI correspondente. Isso til principalmente com caracteres de controle, que no podem ser impressos nem digitados normalmente no programa, como caracteres de backspace, fim de linha, retorno de carro etc. Por exemplo, para guardar o caractere 13 (retorno de carro), usa-se a sintaxe: minhaVariavel := #13; Se o cdigo estivesse numa varivel em vez de uma constante, no pode ser usada essa sintaxe. Nesse caso, pode-se usar a funo Chr: codigoASCII := 13; minhaVariavel := Chr(codigoASCII); Nota: para ver os caracteres da tabela ANSI (exceto os de controle), use o aplicativo Mapa de Caracteres do Windows (em Iniciar | Programas | Acessrios).

O tipo String
Para guardar mais de um caractere, preciso usar o tipo String. Um valor constante do tipo String representado entre apstrofos, como por exemplo: var nome: string; begin nome := 'Joo da Silva'; Uma varivel string normalmente no tem limite de tamanho definido. O espao de memria que ela ocupa muda dinamicamente de acordo com o contedo atribudo a ela, por exemplo: nome := '123'; {3 caracteres}

27

nome := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; {26 caracs.} nome := ''; {zero caracteres} No ltimo caso, tem-se uma string vazia, que representada por '' (apstrofos sem caracteres dentro), que ocupa zero caracteres. Ela usada para "limpar" o contedo de uma varivel. Nota: O Windows usa uma tabela de caracteres chamada tabela ANSI, que associa um cdigo numrico a cada caractere. Nota: o Windows permite caracteres acentuados e especiais, como , , , , , , etc. Mas uma varivel string pode ser declarada com um tamanho fixo, da seguinte forma: var nome: string[50]; telefone: string[10]; Nesse caso, a varivel ocupa um espao fixo de memria, de acordo com o tamanho declarado. No exemplo, nome ocupa 50 caracteres e telefone ocupa 10. Se voc tentar atribuir mais caracteres do que cabe na varivel, os caracteres restantes so ignorados. Se voc atribuir menos, o tamanho lgico da string passa a ser menor que o tamanho fsico. O Object Pascal usa um byte a mais para armazenar o tamanho lgico. Voc pode concatenar (juntar) duas ou mais strings com o operador +. Por exemplo: var prefixo, linguagem, titulo: string; begin prefixo := 'Curso'; linguagem := 'Delphi'; titulo := prefixo + ' de ' + linguagem; { O resultado uma string 'Curso de Delphi' } Para obter caracteres individuais de uma string, voc pode usar o nome da varivel e mais um valor entre colchetes. Por exemplo, se voc quiser guardar o 7 caractere do nome numa varivel char, basta fazer: c := nome[7]; Existem vrias propriedades que tambm so do tipo String, como Caption e Text, por exemplo. Assim, possvel atribuir uma constante ou varivel do tipo String para elas, por exemplo: btnIniciar.Caption := '&Iniciar'; memoTempoTotal.Text := s; Nota: existem vrias funes de manipulao de strings, por exemplo, para obter uma parte de uma string. Consulte o help do Delphi e procure por 'String manipulation functions'.

O tipo Boolean
Vrias propriedades (e variveis tambm) podem conter os valores True (verdadeiro) e False (falso), indicando uma condio lgica ou um "flag" (ligado/desligado, habilitado/desabilitado, sim/no). Para isso utiliza-se o tipo Boolean, que s tem dois valores possveis: True e False. Por exemplo: tmrMarca.Enabled := False; O Delphi tambm utiliza o tipo Boolean internamente, ao fazer qualquer comparao lgica, em um comando if, por exemplo. E uma varivel do tipo Boolean sozinha j uma condio lgica, portanto pode ser usada em um comando if diretamente, por exemplo: var ValorCorreto: Boolean; begin ... if ValorCorreto then ... ... { Enabled uma propriedade do tipo Boolean } if tmrMarca.Enabled then ... ... end;

O tipo TDateTime
Para trabalhar com datas em Delphi, voc pode usar o tipo TDateTime. Veremos as operaes de data mais em detalhe em Manipulao de datas.

28

Funes de Converso
Qualquer varivel numrica pode receber um valor do mesmo tipo ou de um outro tipo numrico, exceto que uma varivel inteira (Integer, Longint, Word etc.) no pode receber um valor real, pois este pode conter uma parte fracionria. Por exemplo: var a: integer; b: longint; x: double; y: extended; begin b := 10; a := b; {ok: inteiro recebe inteiro} x := a; {ok: real recebe inteiro} y := x; {ok: real recebe real} x := 3.7; b := x; {errado: inteiro recebe real} end; Nesse caso preciso usar uma funo de converso, que ou descarta a parte fracionria (funo trunc) ou arredonda o valor (funo round): x := 3.7; a := trunc(x); {a vai valer 3} b := round(x); {b vai valer 4} Existem vrias funes que convertem valores de tipos numricos para o tipo String e viceversa. Ns j vimos algumas em programas-exemplo: var varReal: double; varInteira: integer; varString: string; begin { de String para numrico: } varReal := StrToFloat(varString); varInteira := StrToInt(varString); varInteira64 := StrToInt64(varInteira64); { de numrico para String: } varString := FloatToStr(varReal); varString := IntToStr(varInteira); {VarInteira pode ser de qualquer tipo inteiro,inclusive int64 } end; Alm dessas, existe a funo Str, do Pascal padro, que converte um nmero qualquer para String, permitindo especificar uma largura de campo (o nmero alinhado direita com espaos) e a quantidade de casas depois da vrgula. Por exemplo: segundos := 34.749; Str(segundos:7:2, s); A varivel 's' vai ser preenchida com uma string 'oo34.75' (cada o representa um espao em branco). Ou seja, vai conter no mnimo 10 caracteres, com os dgitos alinhados direita e duas casas depois da vrgula (casas a mais so arredondadas).

Operaes Aritmticas
Os tipos de dados inteiros suportam as operaes aritmticas usuais: soma: a := x + y; subtrao: a := x - y; multiplicao: a := x * y; diviso: a := x / y;

29

Se os dois operandos so do mesmo tipo, o resultado desse tipo. Se um deles tem uma faixa de valores maior (por exemplo, um Double e um Integer), o resultado ser do tipo deste operando (no exemplo, Double). Para os nmeros inteiros o resultado ser do tipo int64 somente se tiver uma varivel deste tipo, caso contrrio o resultado ser do tipo integer. Se os dois operandos so inteiros, o resultado ser inteiro e pode ser atribudo para uma varivel inteira. Uma exceo que no caso da diviso, o resultado sempre real, mesmo quando os dois operandos so inteiros. Portanto, no permitido fazer: a := b / c; quando 'a' uma varivel inteira. Mas pode-se utilizar uma funo de converso, como trunc: a := trunc( b /c ); ou usa-se o operador de diviso inteira div (os dois operandos dever ser inteiros), por exemplo: b := 13; c := 4; a := b div c; {retorna a parte inteira da diviso = 3} Existe tambm o operador mod, que calcula o resto da diviso: x := b mod c; {retorna o resto de 13 div 4, que = 1} Expresses podem ser combinadas com vrios operadores e operandos. Multiplicao e diviso so executadas primeiro, depois soma e subtrao, a menos que sejam usados parnteses, por exemplo: x := a + b * c; {multiplica 'b' e 'c' e soma com 'a'} y := (a + b)*c; {soma 'a' e 'b' e multiplica por 'c'}

Tipos Ordinais
Um tipo de dados considerado um tipo ordinal quando existe uma seqncia definida entre seus elementos, ou seja, a partir de um elemento sempre possvel passar para o prximo elemento do tipo. Os tipos ordinais predefinidos pela linguagem (veremos que voc pode criar outros) so: Todos os tipos inteiros (Integer, Word, Cardinal, Longint,Enumerados...); O tipo Char (os caracteres so ordenados pela tabela ASCII/ANSI); O tipo Boolean (s tem dois elementos: False,True nessa ordem). Notas: Os tipos reais no so considerados tipos ordinais. Algumas operaes podem ser feitas com qualquer tipo ordinal. A funo succ retorna o prximo elemento do tipo, enquanto pred retorna o anterior: var c1, c2: char; x, y: integer; a, b: boolean; begin c1 := 'G'; c2 := succ(c1); {vai ser = 'H'} c2 := pred(c1); {vai ser = 'F'} x := 299; y := succ(x); {succ(x) = x + 1 e pred(x) = x - 1} a := False; b := succ(a); {vai ser = True} end; Se voc chamar succ para o ltimo elemento da seqncia ou pred para o primeiro elemento, isso vai causar um erro de execuo (por exemplo, 'succ(True)' no permitido). A funo ord retorna a posio numrica do elemento dentro do tipo. No caso de um nmero inteiro, retorna o prprio nmero, portanto no tem utilidade prtica. No caso de um caractere, retorna o cdigo ASCII (ANSI) do caractere, que sua posio na tabela ASCII (ANSI): x := ord('G'); {x vai ser 71} No caso do tipo Boolean, ord(False) = 0 e ord(True) = 1. Isso pode ser usado para converter uma condio lgica em valor numrico. Mais tarde veremos outras operaes que podem ser executadas em tipos ordinais. Notas : As funes succ e pred podem ser utilizadas para variveis do tipo int64, mas o mesmo no vlido para a funo ord.

30

Escopo de Variveis
O lugar onde declarada uma varivel determina o escopo de uma varivel, ou seja, qual a regio do programa onde a varivel pode ser acessada e o tempo de vida da varivel, ou seja, qual o intervalo de tempo durante o qual ela mantm seu valor. Qualquer varivel s pode ser utilizada no programa depois do ponto onde foi declarada.

Variveis Locais
Uma varivel declarada dentro de um procedimento uma varivel local. Ela s pode ser utilizada dentro do procedimento (o escopo da varivel o corpo do procedimento). O tempo de vida de uma varivel local o tempo durante a execuo do procedimento. Quando a execuo do procedimento iniciada, a varivel est indefinida, ou seja, seu valor pode ser qualquer dado que existia anteriormente na memria. Se esse valor for utilizado, os resultados so imprevisveis. Depois que o procedimento termina, a memria ocupada pela varivel liberada, e seu valor anterior perdido. Como j vimos, variveis locais so declaradas com a palavra var, logo aps o cabealho do procedimento, mas antes do begin que inicia os comandos: procedure btnCalculaClick(Sender: TObject); var op1, op2, res: double; begin ... end;

Variveis Globais da Unidade


Se uma varivel precisa ser usada em vrios procedimentos, mantendo o seu valor, preciso declarar a varivel como global, ou seja, fora de qualquer procedimento. O escopo dessa varivel passa a ser desde o ponto onde foi declarada at o fim da unidade. Por exemplo: implementation {$R *.DFM} var VariavelGlobal: integer; Variveis globais so inicializadas com valores padro: zero para numricas, False para booleans, '' (texto vazio) para strings, etc. Elas mantm seus valores durante toda a execuo do programa. Ao declarar uma varivel global, voc pode fornecer um valor inicial diferente do padro. Para isto, a varivel deve ser declarada em separado de outras (no em uma lista) e depois do tipo de dados, voc deve colocar um "=" e o valor inicial, que deve ser constante. Por exemplo: var VariavelGlobal: integer = 1; Titulo: string = 'Ttulo inicial'; AtivaTimer: boolean = true;

Variveis Globais do Projeto


Uma varivel global, se declarada na parte implementation, s pode ser acessada dentro daquela unidade. Se for declarada na parte interface, pode ser usada por outra unidade, desde que essa outra tenha uma clusula uses para a unidade que contm a varivel. Veremos mais sobre isso em Estrutura das Unidades.

Constantes
Constantes so valores que podem ser colocados em variveis, usados em expresses etc. Uma constante literal um valor sem nome, escrito explicitamente, como os seguintes: 20 3.5 (constantes numricas - integer e double) 'Testando' (constante do tipo string) False True (constantes do tipo boolean) 'x' #8 (constantes do tipo char)

31

O tipo de dados de uma constante determinado pela forma desta. Nmeros sem parte fracionria so considerados constantes inteiras (isso se o nmero couber na faixa de valores de um tipo inteiro). Uma constante inteira tambm pode ser especificada como um valor hexadecimal, prefixado por '$', por exemplo: x := $2F3; Nmeros hexadecimais contm tambm os dgitos A at F, alm de 0 a 9. Uma constante real tambm pode ser escrita em notao cientfica, especificando-se um valor e uma potncia de 10: y := 3.5e4; { = 3.5 x 104 = 35000 } z := 2.78e-6; { = 2.78 x 10-6 = 0.00000278 } Voc pode criar constante especificando o tipo que esta constante ir retornar , por exemplo: const Inteiro64 = int64(17) Desta forma o tipo que a constante ir retornar int64. Voc tambm pode criar constantes nomeadas, que so simplesmente substitudas pelos valores correspondentes durante a compilao do programa. Elas facilitam a manuteno do programa, quando um valor utilizado em vrios lugares. Para isso, usa-se a declarao const: const TAMANHO = 30; METADE = TAMANHO/2; PI = 3.1415926536; MENS_ERRO = 'Valor incorreto. Digite novamente.'; > Constantes nomeadas so utilizadas como qualquer outra constante: x := TAMANHO * 8; angulo := PI*graus/180; Mas no so variveis, portanto no podem receber outro valor: TAMANHO := 15; { erro de compilao } Da mesma forma que variveis, uma constante pode ser local (se declarada em um procedimento) ou global (se declarada fora).

32

Captulo 5 Estruturas de Controle


Inserindo Comandos com o CodeInsight Estruturas de Deciso Estruturas de Laos Outros Comandos

33

Inserindo comandos com o CodeInsight


Para facilitar a digitao dos comandos da linguagem e reduzir os erros, o CodeInsight do Delphi possui um recurso chamado modelos de cdigo [code templates], que permite inserir rapidamente um comando da linguagem contendo apenas a estrutura bsica, que depois voc pode preencher. Por exemplo, digite casee no editor de cdigo e tecle [Ctrl+J]. O CodeInsight ir inserir um comando case com uma clusula else e espaos em branco para voc completar: case of : ; : ; else ; end; O cursor ficar posicionado entre case e of. Voc pode completar com um nome de varivel, valores constante e os comandos a serem executados. Para ver uma lista completa dos modelos de cdigo, tecle [Ctrl+J]. Veja por exemplo, os modelos ife, ifb, ifeb, ifs, forb, fore, whileb, whiles, caseb, cases. Note que os outros usam comandos do Object Pascal que ainda no foram vistos. ] Nota: voc pode alterar os modelos de cdigo ou criar novos. Para isso clique em Tools|Environment Options e na pgina CodeInsight. Nesta mesma pgina, voc pode tambm desmarcar a opo "Code Completion" se quiser. Essa opo mostra a lista de propriedades e mtodos de um componente quando voc digita o nome do componente e um ponto.

Estruturas de Deciso
O Comando if...then...else...
Ns j vimos o comando if em vrias situaes. A sua sintaxe bsica : if condio then comando1 else comando2; { OU sem o else: } if condio then comando1; A identao de comandos, ou a separao do comando em vrias linhas no so obrigatrias em nenhuma situao no Object Pascal. Mas geralmente um comando if escrito em vrias linhas, para maior legibilidade: if condio then comando1 else comando2; Dica: No editor de cdigo, para identar um bloco de comandos (deslocar direita), use [Ctrl+Shift+I]. Para deslocar esquerda, use [Ctrl+Shift+U]. Nessa sintaxe, condio qualquer expresso que gere um resultado do tipo Boolean (True para verdadeiro, False para falso), podendo ser uma nica varivel booleana, embora na maioria das vezes seja construda usando operadores de comparao, como '=', '>' etc. Note que no permitido o ';' (ponto-e-vrgula) logo depois do then ou logo antes ou depois do else. S pode haver ';' depois do fim do comando if. Se no houver o else, o ';' colocado depois do comando1. Por exemplo: if memoEditor.SelLength <> 0 then menuEdiRecortar.Enabled := True else menuEdiRecortar.Enabled := False; Quando, em lugar de comando1 ou comando2 preciso executar vrios comandos, usa-se os delimitadores begin e end para criar um comando composto. Um comando composto tratado pelo Object Pascal como um nico comando, por exemplo: if condio then begin comando1; comando2;

34

end else begin comando3; comando4; end; Dentro do comando composto, os comandos so separados por ';', mas fora dele se aplicam as regras do if. Um comando if pode ser usado dentro de outro, mas isso pode dificultar o entendimento se um deles inclui uma clusula else. Nesse caso o else fica ligado ao if mais prximo. Mais de uma condio pode ser usada no if, combinando-as com and (e), or (ou) e not (no). Mas nesse caso, so obrigatrios parnteses em volta das condies: if (Key < '0') or (Key > '9') then Key := #0; O operador and tem precedncia sobre o or, e o not tem precedncia sobre os dois, portanto preciso levar isso em conta em condies mais complexas, e utilizar parnteses para especificar o que se deseja avaliar primeiro: if ((Key < '0') or (Key > '9')) and (Key <> #8) then Key := #0; E o operador not pode ser usado para inverter o resultado de uma condio: if ((Key < '0') or (Key > '9')) and not (Key = #8) then Key := #0; Dica: para encontrar um fecha-parnteses perdido, coloque o cursor antes do abre-parnteses e tecle [Ctrl+Q+[ ] (ctrl+Q+abre-colchetes).

O Comando case...of...
Muitas vezes preciso comparar uma varivel com vrios valores. Isso pode ser feito com vrios comandos if aninhados: if dia = 1 then desconto = 30 else if dia = 2 then desconto = 20 else if dia = 3 then desconto = 10; Mas o mesmo pode ser feito com o comando case, especificando a varivel, e seus valores possveis: case dia of 1: desconto = 30; 2: desconto = 20; 3: desconto = 10; end; A sintaxe geral desse comando : case expresso of rtulo1: comando1; rtulo2: comando2; ... else comandoElse; end; Onde expresso pode ser qualquer varivel ou expresso que retorne um valor de um tipo ordinal. Cada rtulo pode ser uma constante sozinha, vrias constantes separadas por vrgulas, ou uma faixa de valores. Por exemplo: case dia of 1: nome := 'primeiro'; { constante } 2: nome := 'segundo'; 3..10: nome := 'terceiro'; { valores entre 3 e 10 } 11,13,15: nome := 'quarto'; { valores 11, 13 e 15 } end; Cada comando na sintaxe pode ser um comando simples ou um comando composto formado pelos delimitadores begin e end.

35

A parte do else opcional e indica um comando a ser executado se nenhum dos valores corresponde ao valor da expresso.

36

Estruturas de Laos
Estruturas de lao permitem repetir um conjunto de comandos. Cada um dos comandos de lao especifica uma forma diferente de iniciar e testar o lao.

O comando for
O comando for permite repetir um lao um nmero especificado de vezes, incrementando ou decrementando uma varivel a cada passagem do lao. Voc deve especificar o valor inicial e final da varivel. A forma de uso a seguinte: for varivel := valor_inicial to valor_final do comando; O comando, como antes, pode ser um comando simples, ou um comando composto. A varivel, o valor inicial e o valor final devem ser todos de um tipo ordinal. Se no incio da execuo o valor inicial maior do que o final, o comando nem chega a ser executado. O seguinte lao mostra os valores numricos de 1 at 20 dentro de um componente ListBox: var valor: integer; s: string; begin for valor := 1 to 20 do begin s := IntToStr(valor); ListBox1.Items.Add(s); end; end; A varivel tambm pode ser do tipo Char, pois este um tipo ordinal: for letra := 'A' to 'Z' do ... Para decrementar a varivel durante o lao, ao invs de incrementar, usa-se downto no lugar da palavra to: for letra := 'Z' downto 'A' do ... for valor := 20 downto 1 do ... Note que o incremento ou decremento sempre 1.

O comando while...do...
O lao while repete um comando enquanto determinada condio verdadeira. Sua sintaxe de forma geral : while condio do comando; Por exemplo: i := valorAnt; while i < 1000 do begin Processar(i); i := i + incremento; end; Antes da primeira iterao do lao, a condio verificada. Se ela for falsa, o comando no chega a ser executado. Se for verdadeira, o comando executado, e a condio verificada novamente e assim por diante.

O comando repeat..until
O repeat..until semelhante ao while, mas testa a condio no final, depois de executar o comando, e termina a execuo se a condio for verdadeira (o contrrio do while). Sua sintaxe geral : repeat comando1; comando2; ...

37

until condio; Por exemplo: i := valorAnt; repeat Processar(i); i := i + incremento; until i >= 1000; O comando repeat sempre executa uma iterao do lao pelo menos. Note que ele no precisa de begin e end para delimitar a lista de comandos, pois as prprias palavras repeat e until j formam delimitadores.

Outros Comandos
Comandos para sair de laos
Durante a execuo de um lao, comum precisar terminar sua execuo antes do tempo. Para isso, pode ser usado o comando break. Este comando sai imediatamente do lao mais interno (seja for, while, ou repeat) e vai para o prximo comando depois do lao. Por exemplo: for i := 1 to 1000 do begin encontrou := ProcuraValor(i); if Encontrou(i) then break; end; { o break salta para esta linha } Alm desse, existe o comando continue. Ele fora a execuo da prxima iterao (repetio) do lao, ignorando os comandos restantes dentro do bloco do lao. Por exemplo, o prximo lao mostra em uma list box os nmeros de 1 a 300, exceto os mltiplos de 7: for x := 1 to 300 do begin if x mod 7 = 0 then { um mltiplo de 7? } continue; { vai para o prximo } s := IntToStr(x); ListBox1.Items.Add(s); end;

O comando exit
Para sair imediatamente de um procedimento, usa-se o comando exit. Use-o quando ocorre alguma condio de erro, por exemplo: if valorErrado then begin mostrarMensagem; exit; end;

38

Captulo 6 Propriedades e Eventos Comuns


Tipos de Propriedades Propriedades Mais Usadas Eventos Comuns Detalhes do Tratemnto de Eventos

39

Tipos de Propriedades
Existem vrias formas de editar o valor de uma propriedade, dependendo da propriedade especfica. Ns j vimos a maioria delas, que so basicamente as seguintes: Propriedades que aceitam qualquer valor: voc precisa digitar o valor diretamente. Exemplo: Caption, Text. A propriedade Name s aceita um identificador vlido (mesmas regras que nomes de variveis). Propriedades numricas: O Delphi permite digitar qualquer coisa, mas quando voc teclar [Enter] ou sair, ele vai verificar se um valor numrico. Exemplo: Left, Top, MaxLength (do componente Edit). Propriedades de lista: Um boto aparece ao lado do valor. Ao clicar nele, abre-se uma lista de valores, e possvel selecionar um deles:

Exemplo: BorderStyle, Color, WindowState, Align. Geralmente o valor s pode ser um dos disponveis na lista, mas algumas propriedades permitem digitar outros valores, como Color. Propriedades booleanas: uma propriedade do tipo Boolean, que s tem dois valores possveis: False e True. Exemplo: Enabled, Visible, Ctl3D. Voc pode selecionar um deles na lista, mas mais fcil usar , com um clique duplo no valor, o contedo ser alternado entre True e False ou clicar no boto . Propriedades expansveis: um sinal de "+" aparece ao lado da propriedade e, clicando duas vezes no nome, ela se expande em sub-propriedades. Exemplo: Font.

Para fechar a lista de sub-propriedades, clique duas vezes no nome da propriedade. Para usar essa propriedade em tempo de projeto, utiliza-se um ponto a mais e o nome da subpropriedade, por exemplo: memoEditor.Font.Color := clBlack; Propriedades de conjunto: So parecidas com propriedades expansveis. As "subpropriedades" que aparecem so todas booleanas (True/False). Exemplo: BorderIcons, Font.Style. O valor que aparece um conjunto de valores, que como veremos mais tarde, exige uma sintaxe diferente para ser usado no programa.

Para alterar a propriedade dentro do programa, use por exemplo: BorderIcons := [biSystemMenu, biMaximize]; Propriedades com editor: Algumas propriedades mostram um valor como (TFont) ou (TStringList), que no pode ser editado, e um boto , que quando clicado mostra um editor de propriedade especializado. Exemplo: Lines (do componente Memo), Font (que tambm

40

pode ser editada abrindo as sub-propriedades). O editor tambm pode ser chamado com um clique duplo na coluna de valor.

Propriedades Mais Usadas


Propriedades para Todos os Componentes
Duas propriedades existem para qualquer componente (inclusive para o formulrio, que considerado um componente): so Name (o nome do componente) e Tag. Esta ltima uma propriedade numrica (tipo integer) que o Delphi no utiliza. Ela pode ser usada para guardar uma informao qualquer associada ao componente, apenas para uso interno.

Propriedades de Tamanho e Posio


Voc pode alterar o tamanho e a posio do formulrio, ou de um controle, movendo-o na tela ou arrastando suas bordas. Mas voc tambm pode digitar suas coordenadas de posio e tamanho manualmente. Essas coordenadas so medidas em pixels, que so os pontos fsicos da tela, e so especificadas pelas propriedades Left, Top, Width e Height:

Para um formulrio, Left a distncia deste extremidade esquerda da tela, Top a distncia em relao ao topo da tela. Para um controle, essas medidas so feitas em relao rea interna do formulrio (excluindo as bordas). O tamanho do formulrio ou controle especificado por Width (na horizontal) e Height (na vertical). Todas essas propriedades podem ser alteradas tambm atravs de comandos de programa, para alterar dinamicamente a posio e tamanho de um controle.

Propriedades do Formulrio
Outras propriedades alteram o posicionamento e tamanho do formulrio. A maioria dessas propriedades s mostra efeito ao executar o programa. A propriedade WindowState controla como o formulrio vai aparecer: wsNormal estado normal wsMinimized janela minimizada (aparece na forma de um cone) wsMaximized janela maximizada (ocupando a tela inteira) A propriedade Position determina se o Windows pode alterar a posio ou o tamanho que voc definiu para o formulrio. O valor padro 'poDesigned': poDesigned posio e tamanho de acordo com o projetado poScreenCenter centraliza o formulrio na tela poDefault o Windows pode mudar a posio e tamanho poDefaultPosOnly o Windows s pode mudar a posio poDefaultSizeOnly o Windows s pode alterar o tamanho A propriedade BorderStyle controla o estilo da borda do formulrio: bsSizeable permite o usurio alterar o tamanho da janela bsSingle no permite alterar tamanho (estilo de borda fina) bsDialog no permite alterar tamanho (estilo de borda dupla) bsNone nenhuma borda, nem barra de ttulo (no permite mover) bsToolWindow como bsSingle, mas com ttulo menor bsSizeToolWin como bsSizeable, mas com ttulo menor

41

O valor padro 'bsSizeable'. A diferena entre 'bsSingle' e 'bsDialog' uma questo de padres de interface, como veremos depois. A propriedade BorderIcons, que se expande em "sub-propriedades", determina quais cones de controle aparecem na barra de ttulo do formulrio. Cada valor correspondente aos elementos da barra, e alterando-o para True ou False pode-se ativar ou desativar um deles (o efeito s aparece ao executar o programa):

O outro valor, biHelp, coloca um boto de ajuda com uma interrogao na borda. Esse boto pode ser usado para chamar uma tela de help. S funciona se biMinimize e biMaximize estiverem desativados. A propriedade AutoScroll, como padro, verdadeira (contm o valor True). Isso faz com que o formulrio mostre barras de rolagem automaticamente quando os controles no cabem na rea visvel da tela. Para testar, crie um controle qualquer, como um Edit e mova-o at deixar metade dele fora do formulrio em alguma das extremidades. Vai aparecer uma barra de rolagem (horizontal ou vertical), que voc pode usar para ver a rea que atualmente no visvel. Se voc quiser, pode desativar AutoScroll, colocando um valor False. Com isso, controles que estiverem fora da rea do formulrio no podem ser acessados pelo usurio.

Propriedades de Controles
Controles (ou componentes visuais), alm das quatro propriedades de posio (Left, Top, Width e Height) tm propriedades que alteram sua aparncia, a maioria existe tambm no formulrio. A propriedade Font determina as caractersticas do texto mostrado pelo controle. No caso do formulrio, ela afeta os controles contidos nele, no o prprio. Para testar, coloque trs controles Label no formulrio. Altere a propriedade Font do formulrio, mudando o nome da fonte para "Times New Roman". Isso vai afetar os dois controles. Agora altere a propriedade Font de um dos controles, "Label1", mudando Font.Name para "Arial". S esse controle ser afetado. Se voc novamente alterar a fonte do formulrio, apenas "Label2" e "Label3" sero alterados. O que determina se um controle usa uma fonte prpria ou a do formulrio a propriedade ParentFont. Note que ParentFont False para o "Label1" (que foi alterado) e True para os outros dois. Quando voc altera a fonte individualmente de um controle, ParentFont automaticamente mudado para False. Se voc mudar ParentFont para True, a fonte do controle vai ser alterada para ficar igual do formulrio. A propriedade Color determina a cor do formulrio ou controle. Existem vrias formas de escolher uma cor. Voc pode selecionar da lista o nome de uma cor especfica (clBlack = preto, clBlue = azul, etc.) e nesse caso, a cor ser sempre a que voc especificou. Outra opo usar nomes de cores relativas configurao do Windows, como clWindow = cor de janela, clBtnFace = cor de boto, clWindowText = cor de texto de janela etc. Nesse caso, a cor real que ser utilizada depende da configurao de cores do Windows no computador do usurio. Para cada controle que tem a propriedade Color, existe tambm uma propriedade ParentColor, que determina se o controle usa a cor definida pelo formulrio ou sua prpria cor individual (de forma anloga a Font e ParentFont). Como j vimos, um controle ou um item de menu pode ser habilitado ou desabilitado com a propriedade Enabled (True ou False). Voc tambm pode esconder um controle ou item de menu do usurio alterando a propriedade Visible para False. Ele continua aparecendo em tempo de projeto, e voc ainda pode utiliz-lo no programa, mas o usurio no vai v-lo durante a execuo. O texto mostrado por um controle definido pela propriedade Caption, se ele no permite edio, ou Text, se ele permite edio pelo usurio. Uma facilidade que o Delphi fornece a capacidade de colocar "dicas" [hints] que so mostradas quando o usurio passa o mouse por cima de um controle. A propriedade Hint de um controle define qual o texto da dica. Para que a dica seja exibida, a propriedade ShowHint deve ter o valor True. Essa propriedade pode ser definida para cada controle individualmente, ou para o formulrio (nesse caso, ParentShowHint, em cada controle, define qual das duas usada).

42

A propriedade Cursor define qual o tipo de ponteiro (ou cursor) do mouse que ser mostrado. O valor padro (crDefault) diz para utilizar o cursor padro atual (geralmente uma seta). Outros valores determinam ponteiros diferentes, por exemplo crArrow (seta), crHourglass (ampulheta).

Eventos Comuns
Crie um novo projeto. Nesse projeto, veremos os eventos mais utilizados pela maioria dos componentes, e tambm algumas propriedades vistas anteriormente.

Eventos de Mouse
O evento OnClick, como j vimos, ocorre quando o boto do mouse pressionado e solto sobre o controle (mas alguns controles, como botes, tambm acionam este evento quando so ativados pelo teclado). Esse evento no fornece nenhuma informao sobre as coordenadas do mouse. Alm desse, existe o evento OnDblClick, que informa um clique duplo (dois cliques em seqncia rpida). Os eventos OnMouseDown e OnMouseUp so acionados quando um boto do mouse pressionado ou liberado, respectivamente, quando o cursor do mouse est posicionado sobre o controle. Esses eventos informam a posio do mouse, qual boto foi pressionado e quais das teclas de modificao ([Shift], [Ctrl] e [Alt]) estavam pressionadas no momento. O evento OnMouseMove ocorre quando o cursor do mouse movimentado sobre o controle. Ele informa a posio atual do cursor do mouse. Vamos tratar o evento OnClick para o formulrio. Digite o seguinte no procedimento de evento: procedure FormClick(Sender: TObject); begin if Cursor = crDefault then {cursor o padro?} Cursor := crHourglass {muda para ampulheta} else Cursor := crDefault; {seno muda pra default} end; importante notar que Cursor uma propriedade do formulrio. Nesse caso, no preciso escrever o nome do formulrio na frente (o que seria Form1.Cursor), basta o prprio nome. Execute para testar. Agora quando voc clicar no formulrio, o ponteiro vai mudar para uma ampulheta. Clicando novamente ele retorna ao valor padro.

Eventos de Teclado
Existem trs eventos de teclado, que so acionados em momentos diferentes. Cada um deles fornece informao sobre a tecla pressionada, mas de formas diferentes. Para cada tecla que pressionada, o evento OnKeyDown acionado, e quando a tecla solta, OnKeyUp acionado. Ambos informam para o procedimento de evento o cdigo da tecla pressionada. Esse cdigo identifica a tecla, mas no o caractere digitado. Por exemplo, no possvel distinguir entre maisculas e minsculas, ou entre dois caracteres na mesma tecla. Alm disso, um caractere pode ser gerado pelo pressionamento de mais de uma tecla. Quando necessrio distinguir os caracteres digitados, e no as teclas, pode ser utilizado o evento OnKeyPress. Ele informa o caractere digitado como uma varivel do tipo Char. Note que nem toda tecla aciona um evento OnKeyPress. Teclas que no geram digitao, como [F1], [Insert], [Home], [Ctrl], acionam apenas os eventos OnKeyDown e OnKeyUp. Vamos tratar esses eventos para o formulrio. Crie o seguinte procedimento de evento, associado ao OnKeyPress: procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin if Key = '*' then Close; end; Nota: A varivel 'Key' um parmetro do procedimento de evento, que preenchido pelo Delphi. Alguns eventos tm parmetros, que contm informaes adicionais fornecidas pelo Delphi.

43

Com isso, quando for pressionada a tecla ('*'), o formulrio ser fechado, usando o mtodo Close. Agora vamos tratar as teclas de seta, fazendo a movimentao do formulrio na direo da seta utilizada. Inicialmente, crie um procedimento de evento para OnKeyDown: procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin end; Repare que o procedimento tem vrios parmetros: 'Key', que desta vez numrica (tipo Word) informa o cdigo da tecla pressionada e 'Shift' informa o estado das teclas de modificao. Para tratar as setas, precisamos comparar o valor de Key com cada um dos cdigos de teclas de seta. Na verdade no preciso saber o valor numrico de todos os cdigos. O Delphi tem constantes predefinidas correspondentes aos valores. Entre o begin e o end digite o seguinte: case Key of vk_Left: Left := Left - 10; vk_Right: Left := Left + 10; vk_Up: Top := Top - 10; vk_Down: Top := Top + 10; end; O comando case..of.., como veremos, compara uma varivel com vrios valores numricos e executa um comando dependendo do valor. No caso os valores so dados pelas constantes 'vk_Left', 'vk_Right',... As propriedades Left e Top determinam a posio do formulrio na tela. Para mover o formulrio, basta alterar seus valores. Execute e teste as teclas de seta para movimentar e a tecla '*' para fechar o formulrio. Salve esse projeto como EVENTOS.PAS e EVENTOSP.DPR.

Eventos do Formulrio
Outros eventos do formulrio correspondem a situaes importantes de serem tratadas, por exemplo: OnCreate: Quando o formulrio criado, ou seja, na inicializao do programa. executado antes de qualquer outro evento do formulrio. Voc pode usar para inicializar componentes. OnDestroy: Quando o formulrio est sendo destrudo, ou seja, a sua rea de memria ser liberada. Ocorre geralmente quando o programa est terminando. OnShow: Logo antes do formulrio ser mostrado na tela (pode ocorrer vrias vezes durante a execuo). OnCloseQuery: O usurio est tentando fechar o formulrio. Voc pode cancelar o fechamento (fazendo CanClose := False) ou, por exemplo, confirmar se ele deseja salvar os dados. OnClose: O formulrio est sendo fechado. Voc pode cancelar o fechamento ou determinar uma ao diferente, como minimizar, ou destruir o formulrio. OnActivate: O formulrio passou a ser a janela ativa (recebeu o foco). OnDeactivate: O formulrio passou a ser uma janela inativa. OnResize: Quando o usurio altera o tamanho do formulrio. OnPaint: til para desenho de grficos.

Outros Eventos
Os controles que podem receber o foco de teclado tm eventos que so acionados quando o foco de teclado muda. O evento OnEnter acionado quando o controle recebe o foco de teclado, depois de um clique do mouse, por exemplo, ou depois que o usurio tecla [Tab] a partir do controle anterior. J o evento OnExit acionado quando o controle perde o foco de teclado, depois que o usurio passa para outro controle por exemplo. Controles de edio e similares possuem um evento OnChange. Esse evento acionado quando ocorre uma modificao no contedo do texto, por exemplo, acrescentar ou apagar um caractere.

44

Detalhes do Tratamento de Eventos


Vamos retornar ao projeto CALCP. Acione o menu File|Open... ou o cone SpeedBar e abra o CALCP.DPR. da

Tratando um Evento para Vrios Controles: OnKeyPress


Como vimos, existem trs eventos relacionados ao teclado, que permitem interceptar cada tecla digitada pelo usurio. Podemos usar o evento OnKeyPress para validar a digitao e s permitir digitao de nmeros. Nota: existem formas bem mais fceis de fazer validao de teclas no Delphi, como usar o componente MaskEdit da pgina Additional, mas faremos dessa forma apenas para fins de aprendizagem. Mas o tratamento deve ser o mesmo para os dois componentes Edit. Isso quer dizer que os dois acionaro um mesmo procedimento de evento. Selecione no formulrio os controles 'editOperando1' e 'editOperando2'. No Object Inspector, abra a pgina de eventos, clique em OnKeyPress e clique duas vezes no valor do evento. Lembre-se: para selecionar dois controles, clique no primeiro, segure [Shift] e clique no outro. O Delphi vai criar um procedimento da forma: procedure editOperando1KeyPress(Sender:TObject; var Key: Char); begin end; O nome do procedimento ("editOperando1KeyPress") baseado no primeiro controle, mas isso no importa. Quando voc cria um procedimento de evento dessa forma, ele fica associado a todos os componentes selecionados e vai ser executado quando o evento acontece com qualquer um deles no caso, quando o usurio digita uma tecla em um deles. O parmetro "Key" que passado contm a tecla digitada. Vamos verificar se ela numrica, e se no for, rejeitar a tecla: procedure TForm1.editOperando1KeyPress( Sender: TObject; var Key: Char); begin if (Key < '0') or (Key > '9') then Key := #0; { rejeita a tecla } end; O caractere #0 no a mesma coisa que '0'. O primeiro o chamado caractere nulo (cdigo ASCII 0) que no corresponde a nenhum caractere imprimvel. O outro o dgito zero (cdigo ASCII 48). Quando o procedimento altera 'Key' para o valor #0, isso faz com que seja cancelada a digitao. Execute o programa e verifique que apenas caracteres numricos aparecem. Outros so simplesmente ignorados. Mas existe um problema: a tecla [Backspace] no funciona mais. Isso acontece porque [Backspace] gera um evento OnKeyPress, com o cdigo ASCII 8 (caractere #8). Para corrigir isso, altere o if para o seguinte: if ((Key < '0') or (Key > '9')) and (Key <> #8) then Key := #0; { rejeita a tecla }

Renomeando um Procedimento de Evento


O nome de um procedimento de evento aparece no cdigo depois de "procedure TForm1.". Esse nome criado pelo Delphi juntando o nome do componente que foi selecionado para tratar eventos, com o nome do evento (sem o "On"). Mas quando um mesmo procedimento acionado por vrios eventos (ou componentes) melhor mudar esse nome. Quando voc percorre o arquivo da unidade, o nome ajuda a reconhecer a funo daquele procedimento. Para mudar o nome, selecione qualquer um dos dois componentes, clique no Object Inspector, no evento OnKeyPress. Substitua o nome atual "editOperando1KeyPress" por "TratarTecla" e tecle [Enter]. Depois clique duas vezes nesse nome e verifique que na unidade, o Delphi renomeou o procedimento:

45

procedure TForm1.TratarTecla(Sender: TObject; var Key: Char); begin if ((Key < '0') or (Key > '9')) and (key <> #8) then Key := #0; { rejeita a tecla } end; Voc no deve mudar o nome diretamente no texto da unidade. Se fizer isso, o Delphi no conseguir localizar mais o procedimento e mostrar vrias mensagens de erro.

Associando um Procedimento Existente


Se depois de criar um procedimento, voc criar um novo componente, ou se voc esqueceu algum componente de fora ao criar o procedimento, voc pode lig-lo a um procedimento j existente. Selecione no formulrio apenas o componente 'editResultado' (clique nele sem usar o [Shift]). Clique no evento OnKeyPress e no boto de seta . Aparece na lista o nome do procedimento de evento "TratarTecla". Selecione esse nome. Basta isso para associar o cdigo dos procedimentos com os eventos correspondentes do controle. Nesse caso, no til associar esse procedimento, porque o "editResultado" no aceita digitao ( somente leitura). Clique no evento OnKeyPress novamente e apague o nome do procedimento. Isso desfaz a associao.

Eliminando um Procedimento de Evento


Se voc quiser eliminar um procedimento de evento, no apague o corpo dele no cdigo. Apague apenas os comandos entre o begin e o end , necessrio tambm excluir as declaraes de variveis, se houver. Quando voc compila o programa, o Delphi nota que o procedimento est vazio, e o remove automaticamente do programa. S para teste, clique duas vezes no componente 'editOperando1'. Isso vai criar um procedimento para o evento OnChange, que executado quando o contedo do controle alterado. comum criar um procedimento por acidente, dessa forma. Agora salve o projeto. Repare que o procedimento vai desaparecer automaticamente. Nota: os procedimentos que aparecem na lista so apenas aqueles compatveis com o evento. Um procedimento compatvel quando a lista de parmetros (entre parnteses, no cabealho) est de acordo com o que o evento espera.

46

Captulo 7 Usando Vrios Formulrios


Caixas de Dilogo Funes de Mensagem Exemplo: CalcData Gerenciando os Arquivos do Projeto Definindo o Formulrio Principal

47

Caixas de Dilogo
Um programa em Delphi geralmente tem um formulrio principal, que aparece inicialmente, e com o qual o usurio interage. A partir desse formulrio, o usurio pode abrir outros formulrios do programa. Os formulrios auxiliares, chamados a partir do principal, geralmente so caixas de dilogo. Uma caixa de dilogo uma janela com a qual o usurio interage e depois retorna ao principal. Algumas funes do Delphi mostram caixas de dilogo predefinidas e voc no precisa criar um formulrio para us-las. Mas geralmente, quando voc precisa de alguma coisa a mais, voc deve criar um formulrio e utiliz-lo como uma caixa de dilogo.

Funes de Mensagem
Mensagens Informativas
O procedimento ShowMessage permite mostrar uma mensagem simples para o usurio, contendo apenas um boto de Ok. O ttulo da aplicao aparece no ttulo da mensagem. Por exemplo, a chamada: ShowMessage('Erro de digitao no campo Nome. ' + 'Digite novamente.'); mostra uma mensagem como a seguinte (supondo que o ttulo da aplicao 'Meu Programa'):

Nota: para definir o ttulo da aplicao, abra o menu Project|Options, clique no marcador "Application", e digite o novo ttulo em Title. Esse ttulo ser usado em todas as mensagens de agora em diante. Esse procedimento geralmente usado para mensagens curtas, que no precisam de nenhum retorno do usurio. Note que se o texto da mensagem muito longo, voc pode dividir a string em partes, usando o operador "+". Se voc precisar de quebras de linha na mensagem, voc pode inserir os caracteres de fim de linha, #13 e #10. Por exemplo: ShowMessage('Erro de digitao no campo Nome. '#13#10 + 'Digite novamente.');

Mensagens de Confirmao
A funo MessageBox, que um mtodo do objeto Application, mostra uma mensagem com botes que o usurio pode clicar para responder. De forma geral, a sintaxe para usar essa funo : varivel := Application.MessageBox(mensagem, ttulo, flags); onde: mensagem: o texto da mensagem ttulo: o ttulo que aparece na janela de mensagem. flags: uma combinao de valores que determina quais botes ou cones so usados na janela de mensagem. (Ver abaixo) varivel:recebe um valor inteiro que indica qual boto foi pressionado. Esse valor pode ser um dos seguintes: IDOK boto Ok IDCANCEL boto Cancelar IDABORT boto Anular IDRETRY boto Repetir IDIGNORE boto Ignorar IDYES boto Sim IDNO boto No

48

O valor de flags pode ser uma combinao de um ou mais dos seguintes valores: MB_OK 0 s boto Ok (default) MB_OKCANCEL 1 botes Ok e Cancelar MB_ABORTRETRYIGNORE 2 botes Anular, Repetir e Ignorar MB_YESNOCANCEL 3 botes Sim, No e Cancela MB_YESNO 4 botes Sim e No MB_RETRYCANCEL 5 botes Repetir e Cancelar MB_ICONERROR 16 sinal de erro crtico MB_ICONQUESTION MB_ICONEXCLAMATION MB_ICONINFORMATION 32 sinal de pergunta 48 sinal de advertncia 64 sinal de informao MB_DEFBUTTON1 0 primeiro boto tem o foco (default) MB_DEFBUTTON2 256 segundo boto tem o foco MB_DEFBUTTON3 512 terceiro boto tem o foco Veremos exemplos dessas funes no prximo projeto.

Exemplo: CalcData
Vamos criar um pequeno programa que permite mostrar um calendrio e executa a calculadora do Windows . Crie um novo projeto. No ttulo do formulrio coloque "Menu Principal" e na propriedade Name, troque "Form1", que o nome default, por "FormPrincipal".Para o formulrio ficar centralizado altere a propriedade Position para "poScreenCenter". Em outros projetos, no colocamos nome no formulrio porque ele no era utilizado dentro do cdigo do programa. Coloque no formulrio trs componentes "Button" ( ) , um componente "Edit"( )e

) . Altere as seguintes propriedades: um componente "Label" ( "Button1" btnCalendario Name Caption Calendrio "Button2" Name btnCalculadora Calculadora Caption "Button3" btnFechar Name Fechar Caption "Edit" Name editData Text "Label" Data Caption O formulrio ir ficar da seguinte forma:

49

Pedindo Confirmao ao Usurio


Agora vamos tratar o evento OnClick do item do "Button" Fechar . No procedimento de evento digite o seguinte: if Application.MessageBox( 'Tem certeza que quer sair?', 'Confirmao', MB_IconQuestion + MB_YesNo) = idYes then Close; Isso chama a funo MessageBox, informando o texto da mensagem. O ltimo argumento, no caso 'MB_IconQuestion + MB_YesNo', diz para mostrar um cone de pergunta e especifica quais os botes da mensagem (no caso, "Yes" e "No"). A funo retorna um valor indicando qual o boto pressionado. Esse valor pode ser 'idYes' ou 'idNo' no caso. Se for idYes, executamos o mtodo Close para fechar o formulrio. Execute o programa e clique no boto "Fechar". Notas:Para alternar do formulrio para o editor de cdigo pressione a tecla F12. Ento ao clicar no boto "Fechar" ir aparecer a mensagem perguntando se deseja sair do formulrio. Mas esta no a nica forma de fechar o formulrio, o usurio pode usar as teclas [ALT+F4] ou clicar no cone . Mas ao fechar o formulrio, so gerados os eventos, OncloseQuery e o OnClose. No primeiro podemos cancelar a tentativa do usurio de fechar o formulrio, mas no segundo o formulrio foi fechado. Para mostrar a mensagem independente do modo que o usurio ir fechar , coloque o seguinte procedimento no evento OnCloseQuery do formulrio "frmPrincipal" : if Application.MessageBox('Tem certeza que quer sair?', 'Confirmao',MB_IconQuestion + MB_YesNo) = idNo then CanClose := false A varivel CanClose passada como parmetro pelo evento OnCloseQuery, ao sair do procedimento se esta varivel for False, quer dizer que voc esta interrompendo a tentativa do usurio de fechar o formulrio.O default dessa varivel True. Vamos retirar a mensagem que aperece quando clicar o boto "Fechar", pois se deixarmos como est, se o usurio clicar neste boto ir aparecer duas mensagens perguntando se deseja fechar o formulrio, neste procedimento iremos deixar somente o mtodo close.

Criando um Novo Formulrio


Para criar um novo formulrio no projeto, use o item File|New Form no menu do Delphi ou use o boto New Form: na SpeedBar. O novo formulrio vai aparecer como "Form1" e ainda no tem nenhum componente. Altere o seu nome (Name) para "formCalendario" e o ttulo (Caption) para "Calendrio". Altere tambm a propriedade Position do formulrio para "poScreenCenter". ) que fica na pasta "Win32", altere sua Coloque o componente "MonthCalendar"( propriedade Name para "MtCData". Para mostrar mais de um ms necessrio alterar o tamanho deste componente, podemos tambm alterar o valor da propriedade Width para 377.

50

Este componente mostra um calendrio. Seu formulrio ir ficar como a figura abaixo:

Agora vamos acrescentar dois botes neste formulrio, vamos usar o componente "BitBtn" da . Esse tipo de componente permite pgina "Additional" - o primeiro cone da pgina, mostrar figuras junto com o texto. Para o primeiro boto, defina a propriedade Kind [espcie] com o valor 'bkOk'. Isso altera automaticamente as propriedades Caption (para "Ok"), Default (para True), ModalResult (para 'mrOk') e Glyph (para conter uma imagem correspondente ao Ok). Para o outro boto, defina Kind com o valor 'bkCancel'. Isso vai alterar Caption para "Cancel", Cancel para True, ModalResult para mrCancel, e Glyph para conter o desenho de um "x". Altere Caption para o valor "Cancelar". A propriedade ModalResult de um boto (de um Button "normal" ou de um BitBtn) importante com caixas de dilogo. Quando ModalResult contm um valor diferente de 'mrNone' (o default), o boto fecha o formulrio e retorna esse valor para quem "chamou" o formulrio. Esse valor numrico, mas existem constantes predefinidas para facilitar, como 'mrOk' e 'mrCancel'. A propriedade Default, como j vimos, faz com que o boto seja acionado por [Enter] e a propriedade Cancel faz com que o boto seja acionado pela tecla [Esc]. Notas: A propriedade no componente "BitBtn" que permite colocar imagem a propriedade Glyph.

Salvando o Projeto
Salve o projeto nesse ponto para dar nome aos arquivos. O Delphi vai pedir os nomes na ordem segundo formulrio,: formulrio principal e projeto. Chame-os respectivamente de: EXECCALEN.PAS (era "Unit2.PAS", segundo formulrio) EXECPRIN.PAS (era "Unit1.PAS", primeiro formulrio) CALCDATA.DPR (era "Project1.DPR", arquivo de projeto) Em projetos com mais de um formulrio, no usaremos o mesmo padro de nomes dos outros, que era acrescentar um "P" ao nome do projeto. melhor salvar o projeto agora porque vamos precisar dos nomes de unidades do projeto bem definidos para o prximo passo.

Executando um Arquivo
O boto "Calculadora" vai executar o calculadora do Windows , cujo arquivo "Calc.exe". No procedimento de evento OnClick , faa o seguinte: begin WinExec('calc.exe', SW_SHOWNORMAL); end; A funo WinExec uma funo do Windows que executa um programa. Ela recebe como parmetros o nome do programa e um valor que indica como a janela do programa deve aparecer. Para isso existe um comando que converte a string em PChar. Execute o programa e verifique o resultado. Vamos retornar ao formulrio principal, para fazer isto clique no cone menu View/forms, ir aparecer a seguinte tela: ou [Shift+F12] ou

51

Escolha a opo "formPrincipal" e clique em "OK". Ele ir mostrar o formulrio principal, no evento OnClick do boto "Calendrio" iremos chamar o formulrio "formCalendrio". Para mostrar um outro formulrio basta usar o mtodo Show ou o mtodo ShowModal, da seguinte forma: nome_do_formulrio.Show; { ou } nome_do_formulrio.ShowModal; A diferena entre os dois que ShowModal mostra o formulrio de forma modal. Quando uma janela modal est na tela, o usurio no pode utilizar outras janelas do programa. Ele deve terminar de executar a tarefa atual e fechar a janela modal para poder retornar principal. Se uma janela no modal, o usurio pode alternar livremente entre ela e outras janelas no modais. Uma janela modal a interface recomendada para caixas de dilogo, por isso utilizaremos ShowModal. No cdigo do procedimento criado coloque: if FormCalendario.ShowModal = mrOk then editData.Text := DatetoStr(FormCalendario.MtCData.Date); Primeiro o mtodo ShowModal chamado e o valor retornado verificado. Se esse valor for 'mrOk', o boto "Ok" foi pressionado. Se ele for 'mrCancel', o boto "Cancelar" foi pressionado. Quando o valor 'mrOk', o componente 'editData' vai receber a data que foi escolhida , essa valor iremos obter pela propridade Date do componente MtCData no formulrio formCalendario. Repare que isso feito com a sintaxe: FormCalendario . MtCData . Date Mas para esse cdigo funcionar falta uma coisa. Se um formulrio precisa acessar outro que est em outra unidade, preciso adicionar uma referncia unidade, atravs de uma clusula uses. No arquivo da unidade EXECPRIN.PAS, procure a palavra implementation, e acrescente o seguinte logo depois do {$R *.DFM}: uses ExecCalen; "ExecCalen" o nome da outra unidade, que contm o formulrio "FormCalendario". Se no houvesse essa clusula, o cdigo no conseguiria acessar o outro formulrio. Como a propriedade Text do componente "Edit" do tipo String e a propriedade Date do componente MonthCalendar e do tipo TDate, temos que converte o contedo da propriedade Date para String, por isso foi necessrio usar a funo StrtoDate. Execute o programa e clique no boto "Calendrio". O segundo formulrio aparece como uma janela modal(se voc clicar no formulrio principal, no vai conseguir us-lo). Para retornar ao principal clique no boto "Ok". Salve novamente o projeto. Mantenha ele aberto no Delphi, pois vamos analisar algumas opes do Delphi utilizando esse mesmo projeto.

Gerenciando os Arquivos do Projeto


Um projeto grande, com vrios formulrios, pode ficar difcil de compreender e manter. Para facilitar o tratamento de projetos, o Delphi tem vrios recursos. Note que para utilizar esses recursos com eficincia, voc deve dar nomes descritivos a todos os formulrios e unidades.

52

Usando a Speedbar ou Menus


Para alternar entre os formulrios do projeto, clique no boto (Select form from list) da Speedbar. Ele vai mostrar uma janela com os nomes de todos os formulrios (no caso "FormPrincipal" e "FormCalendario"). Escolha um deles e clique Ok, ou clique duas vezes no nome dele. No teclado, voc pode usar [Shift+F12]. Para ver a lista de unidades disponveis, em vez de formulrios, use o boto (Select unit from list). Quando voc selecionar uma unidade, ela vai aparecer no editor de cdigo. Repare que aparece um nome a mais, que o nome do projeto ("CalcData"). Essa opo traz o arquivo de projeto (DPR), que analisaremos mais tarde. No teclado, voc pode usar [Ctrl+F12]. Nota: Se voc tentar executar o programa sem fazer essa alterao, o Delphi automaticamente se oferece para adicionar uma referncia unidade do outro formulrio, pedindo uma confirmao. Depois que as unidades foram abertas, voc pode alternar livremente entre elas clicando nas abas do editor de cdigo (ou usando [Ctrl+Tab]):

E voc tambm pode alternar para uma unidade e, a partir dela, abrir o formulrio associado. Para isso use a tecla [F12] ou o boto (Toggle Form/Unit) da SpeedBar. claro que se voc puder ver os dois (ou mais formulrios) ao mesmo tempo na tela, voc pode alternar entre eles com um clique de mouse. Voc tambm pode adicionar um arquivo ao projeto (como um formulrio que voc criou em outro projeto) usando o boto da SpeedBar ou o item de menu Project|Add to project....

ou o item Project|Remove from Para remover um arquivo do projeto, use o boto project... e selecione qual voc quer remover. Nota: Quando voc adiciona um arquivo ao projeto, o Delphi no faz uma cpia do arquivo. Se outros projetos estiverem utilizando o arquivo, ele ser compartilhado entre eles. Quando voc remove um arquivo do projeto, o arquivo no excludo do disco. Ele continua no diretrio do projeto e pode ser utilizado novamente no mesmo projeto ou em outros projetos.

Usando o Project Manager


O Delphi tambm inclui um pequeno utilitrio que permite ter uma viso geral do projeto. Para us-lo, clique no item View|Project Manager no menu do Delphi. O Project Manager [gerente de projeto] tem uma aparncia como a seguinte:

53

O Project Manager mostra uma tabela com os nomes de cada unidade do projeto e ao expandir essas unidades ele mostra o formulrio correspondente , a no ser no caso de uma unidade independente. Na coluna "Path", aparece o diretrio do arquivo, isto se no estiver no mesmo diretrio do projeto. Podemos trabalhar com mais de um projeto ao mesmo tempo . Isso muito til , se voc quer desenvolver um desenvolver um programa EXE e uma DLL que trabalham em conjunto. Os arquivos podem ser salvos nos "grupo de projetos", que serve para manter agrupados todos os itens adicionados. Podemos adicionar um novo projeto e tambm um projeto j existente, para isso clique com o boto direito do mouse na palavra ProjectGroup1(caso no tenha mudado o nome do grupo). Com isso iro aparecer as seguintes opes:

Estas opes so utilizadas para: Add New Project : Adicionar um novo projeto ao grupo. Add Existing Project : Caso o projeto j exista , podemos adicion-lo ao grupo atravs desta opo. Save Project Group : Salva todas as alteraes feitas neste grupo. Save Project Group As: Salva as configuraes deste grupo com outro nome. View Project Group source : Para cada grupo criado gerado um arquivo com a extenso bgp, e neste arquivo contm todos os projetos associados ao grupo.Esta opo mostra o contedo do arquivo cuja extenso bgp. ToolBar: Se est opo estiver marcada , mostrado uma barra de ferramento onde apareem as opes:

Status Bar: Mostra o nome e o caminho do arquivo de projeto. Dockable: Permite encaixar a janela atual em outra janela, como por exemplo, o editor de cdigo, o object inspector, etc..

54

55

Definindo o Formulrio Principal


Esse exemplo que criamos possui um formulrio principal e um formulrio Calendrio. O formulrio principal de um projeto o que aparece inicialmente para o usurio, e a partir do qual os outros so chamados. Inicialmente o formulrio principal o primeiro Formulrio criado no projeto, mas voc pode mudar isso a qualquer momento. Para mudar, acione o menu Project|Options.... Na pgina Forms , lista "Main Form", selecione o nome do formulrio que voc quer que seja o principal, por exemplo, "FormCalendario" e clique "Ok". Quando voc executar o programa, esse formulrio vai aparecer em vez do "FormPrincipal". Depois retorne para a opo anterior.

56

Captulo 8 Estrutura das Unidades


Estrutura Geral das Unidades O Cdigo Gerado pelo Delphi Unidades Associadas e Independentes Compilao de Unidades Usando uma Unidade Resolvendo Conflitos de Nomes Arquivo de Projeto

57

Quando voc cria um formulrio no Delphi, automaticamente criada uma unidade associada, que contm algum cdigo gerado automaticamente pelo Delphi, alm do cdigo que voc acrescenta nos procedimentos de evento. Voc tambm pode criar uma unidade independente, para usar como uma biblioteca de funes e procedimentos, por exemplo. Neste captulo veremos como a estrutura do cdigo gerado pelo Delphi, e qual a forma geral da estrutura de uma unidade.

Estrutura Geral das Unidades


Todo arquivo de unidade dividido basicamente em uma seo de interface e uma seo de implementao. Em geral, o que declarado na seo de interface (variveis, constantes, procedimentos etc.) visvel externamente, em outras unidades. O que for declarado apenas na seo de implementao visvel apenas para uso dentro da prpria unidade: unit Execprin; interface { itens visveis externamente } ... implementation { itens para uso interno } ... end.

O Cdigo Gerado pelo Delphi


Voc pode criar suas prprias unidades, mas para comear, vamos ver a estrutura do cdigo que o Delphi gera automaticamente num arquivo de unidade. No projeto anterior (CALCDATA.DPR) abra a unidade EXECPRIN.PAS, que est associada ao formulrio principal (FormPrincipal). Verifique que o cabealho da unidade contm uma linha: unit Execprin; A primeira linha contm a palavra unit seguida do nome da unidade (que corresponde ao nome do arquivo). Depois vem a palavra interface, que inicia a seo de interface da unidade.

Seo de Interface
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls; A seo de interface comea com uma clusula uses, que contm uma lista de nomes de outras unidades que so utilizadas por esta. Nesse caso esses nomes so de unidades do Delphi (Windows, SysUtils, ...) que compem a biblioteca do Delphi. Essa lista mantida automaticamente, mas voc pode acrescentar outros nomes lista. Aps a clusula uses, voc pode acrescentar declaraes de tipos de dados, variveis, procedimentos e funes. A primeira declarao, colocada automaticamente, a da classe de formulrio. A classe uma definio dos componentes que o formulrio contm, e dos procedimentos de evento definidos nele. Ns veremos a classe de formulrio mais em detalhes posteriormente. type TformPrincipal = class(TForm) btnCalendario: TButton; btnCalculadora: TButton; btnFechar: TButton; editData: TEdit; Label1: TLabel; procedure btnFecharClick(Sender: TObject); ... private

58

{ Private declarations } public { Public declarations } end; Com a palavra end, termina a definio da classe. Depois o Delphi acrescenta uma declarao de varivel para o formulrio. var FormPrincipal: TFormPrincipal; Depois dessas declaraes, vem a seo de implementao da unidade, que contm o seguinte: implementation {$R *.DFM} uses execcalen; procedure TformPrincipal.btnFecharClick(Sender: TObject); begin .... end; procedure TformPrincipal.FormCloseQuery(Sender: TObject;var CanClose: Boolean); begin .... end; ... end. A declarao {$R *.DFM} no um comentrio, apesar de parecer com um. Esse tipo de declarao chamada de diretiva do compilador e uma instruo para o compilador interno do Delphi. No caso, o que ela faz associar o arquivo de formulrio (EXECPRIN.DFM) com o arquivo de unidade. Essa diretiva necessria para o funcionamento do programa, portanto no a remova. Depois vem o corpo de cada um dos procedimentos de evento, Note que em cada um deles, o nome da classe de formulrio ("TFormPrincipal") includo como prefixo no cabealho do procedimento. Aps todos os procedimentos existe uma linha contendo apenas "end." (end seguido de ponto final). Essa linha sinaliza o final do arquivo da unidade. O compilador ignora tudo que for digitado depois dessa linha, mesmo sem especificar comentrios.

Unidades Associadas e Independentes


No Delphi, uma unidade associada a um formulrio sempre tratada e utilizada em conjunto com o formulrio, e o cdigo da unidade geralmente est ligado (atravs de eventos) com os componentes do formulrio. Mas voc pode tambm criar unidades independentes, que contm apenas rotinas de cdigo e nenhum componente. Vamos ver alguns exemplos mais tarde, mas o processo de criar uma unidade independente simples: selecione o item de menu File|New... no Delphi, clique no cone Unit e clique Ok. Com isso, criada uma unidade contendo apenas o esqueleto das sees, como a seguinte: unit Unit2; interface

59

implementation end. Quando voc salva o arquivo da unidade, fornecendo um outro nome, o Delphi vai alterar a declarao no cabealho para refletir esse nome.

Compilao de Unidades
O Delphi compila o seu projeto quando voc executa o programa, ou quando voc aciona Project|Compile (nome do projeto ativo). Caso queira compilar todos os projetos existente no grupo escolher Project|Compile All Projects. Para compilar o programa, o Delphi rene todas as unidades do projeto e cria um arquivo executvel, com o mesmo nome do projeto e extenso EXE. Essa compilao feita em vrias fases. Da primeira vez que o projeto compilado, para cada arquivo de unidade (.PAS), gerado um arquivo de unidade compilada (.DCU), e esses arquivos DCU so mantidos no disco. Depois todos os arquivos DCU, mais os arquivos (RES) e o arquivo DPR so combinados em um nico arquivo EXE independente. Da prxima vez que o projeto for compilado, apenas as unidades alteradas desde a ltima compilao so recompiladas (.PAS -> .DCU). O Delphi verifica isso comparando a data/hora do arquivo PAS com a data/hora do arquivo DCU correspondente. Se o arquivo fonte for mais recente, ele recompila. Voc pode tambm forar o Delphi a recompilar todas as unidades sem verificar a data. Para isso, use o comando Project|Build (nome do projeto ativo) , caso queira recompilar todos os projetos pertencentes ao grupo escolher Project|Build All Projects. O processo de compilao pode ser resumido com o diagrama:

Usando uma Unidade


Uma unidade sempre utilizada por outra unidade (ou pelo programa principal, como veremos). Na clusula uses, so especificadas quais as unidades utilizadas. Por exemplo: unidade FRMTESTE.PAS: unit FrmTeste; interface uses Forms, Controls, ... Rotinas; {nome da outra unidade} ... implementation procedure...

60

begin Contador := 30; AumentaCont; end; ... end. unidade ROTINAS.PAS: unit Rotinas; interface var Contador: integer; procedure AumentaCont; implementation ... end. Quando uma unidade (FrmTeste), utiliza outra (Rotinas), ela passa a ter acesso a todos os identificadores, como variveis e procedimentos, que esto declarados na seo de interface da outra (ela no tem acesso a identificadores declarados apenas na seo de implementao da outra). Existem dois lugares onde pode ser colocada a clusula uses: no incio da seo de interface, ou no incio da seo de implementao. Os identificadores da outra unidade s se tornam visveis a partir do ponto onde a outra unidade foi referenciada. Se voc colocar a referncia outra unidade na clusula uses da interface, ento os identificadores da outra podem ser usados j na parte de interface. Se voc referenciar a outra unidade na clusula uses da parte de implementao, os identificadores s podem ser usados a partir da parte de implementao. Se duas unidades dependem uma da outra atravs da seo de interface, ento o Delphi recompila a unidade dependente (gera o arquivo .DCU) sempre que a outra alterada. Nesse exemplo, toda vez que a unidade ROTINAS alterada, a unidade FRMTESTE, que depende dela, recompilada primeiro. Duas unidades podem se "utilizar" mutuamente, isto , pode haver tambm uma clusula uses em ROTINAS, que referencia FRMTESTE. Mas se ambas as referncias estiverem na parte interface das unidades, o Delphi no consegue determinar a ordem de compilao das duas, e gera uma mensagem de erro ("Circular unit not allowed"). Por isso, sempre melhor acrescentar a referncia para a outra unidade na seo implementation. S realmente necessrio colocar a referncia na interface quando voc precisa usar algo da outra unidade ainda dentro da parte interface (s acontece no caso de constantes e tipos de dados que sejam usados por outros tipos de dados ou constantes).

61

Resolvendo Conflitos de Nomes


Pode acontecer de voc ter um identificador que tem o mesmo nome na unidade atual e em outra que est sendo utilizada. Isso gera uma ambiguidade quando voc usa o nome. Por exemplo, suponhamos que FRMTESTE.PAS contenha uma varivel chamada 'Contador', e utiliza a unidade ROTINAS.PAS, que tambm contm uma varivel chamada 'Contador'. Se voc colocar na unidade FRMTESTE um comando: Contador := 34; o Delphi vai dar prioridade varivel da unidade atual ('Contador' em FRMTESTE). Mas para acessar a varivel da outra unidade (ROTINAS), voc pode usar um identificador qualificado, isto , prefixado com o nome da outra unidade, por exemplo: Rotinas.Contador := 34; Qualquer identificador pode ser usado dessa forma para resolver o conflito de nomes.

62

Captulo 9 Outros Tipos de Dados e Depurao


Tipos Enumerados Tipos Faixa Vetores Exemplo: Clculo de Mdia Conjuntos Depurao

63

Tipos Enumerados
Um tipo enumerado composto por uma lista seqencial de valores simblicos. Uma varivel desse tipo pode assumir qualquer um desses valores. Para criar um tipo enumerado, usa-se uma declarao type: type EstadoCivil = (Solteiro, Casado, Desquitado, Viuvo); Aps criar um tipo de dados, podem ser criadas variveis desse tipo, com uma declarao de variveis normal: var estCiv: EstadoCivil; A varivel 'estCiv' s vai poder assumir um dos valores do tipo: Solteiro, Casado, etc. Esses valores no so numricos e no so strings de texto. So apenas constantes simblicas que representam uma informao. Por exemplo: estCiv := Casado; ... if estCiv = Viuvo then begin ... end; Tipos enumerados melhoram a legibilidade do programa, evitando que voc precise codificar uma varivel com valores numricos (p.ex.: 0 para Solteiro, 1 para Casado, etc.). Mas eles so manipulados de forma eficiente pelo Object Pascal, pois internamente so tratados como constantes numricas.

Operaes com Ordinais


Um tipo enumerado tambm um tipo ordinal, como os tipos inteiros, o tipo Char e o tipo Boolean. Por isso, tambm se aplicam a ele todas as operaes que podem ser feitas com tipos ordinais, vistas no Captulo sobre Variveis e Tipos de Dados e outros: Para obter o prximo elemento da seqncia: usa-se a funo succ. Por exemplo: estInicial := Casado; estCiv := succ(estInicial); {o valor ser Desquitado} Para obter o elemento anterior: usa-se a funo pred. Por exemplo: pred(Casado) retorna o valor Solteiro. Para saber a posio do elemento na seqncia: usa-se a funo ord. Ela retorna um valor indicando a posio do elemento na lista, e pode ser usada para converter um valor enumerado em numrico. O primeiro elemento tem a posio zero. Por exemplo: ord(Solteiro) = 0, ord(Casado) = 1, ord(Desquitado) = 2 e ord(Viuvo) = 3 e ord(estCiv) retorna um valor dependendo do valor atual da varivel. Para percorrer uma faixa de elementos: pode ser usado o comando for (visto em Estutura de Controle) para fazer um lao: for estCiv := Solteiro to Viuvo do ... Alm disso, tipos ordinais podem ser usados para ndices de vetor (como veremos adiante) ou para criar conjuntos (como veremos adiante) e podem ser usados com o comando case que foi visto anteriormente.

Tipos Enumerados no Delphi


A prpria VCL do Delphi utiliza tipos enumerados em vrios lugares. A propriedade BorderStyle do formulrio, por exemplo, de um tipo enumerado (TFormBorderStyle) que contm quatro valores possveis. A declarao desse tipo, no cdigo fonte da VCL, : type TFormBorderStyle = (bsNone, bsSingle, bsSizeable, bsDialog); Cada valor possvel representa um estilo de borda do formulrio, como vimos antes. Se BorderStyle fosse uma propriedade numrica em vez de enumerada, os valores possveis teriam que ser codificados como nmeros (0,1,2,3) e isso tornaria difcil a escrita e manuteno

64

do programa. Se eles fossem codificados como strings de texto ('bsNone' etc.), seria muito ineficiente o armazenamento e manipulao dos valores.

Tipos Faixa
Se voc sabe que determinada varivel s pode pertencer a uma faixa de valores definida, pode utilizar um tipo faixa para que o prprio Delphi se encarregue de verificar isso automaticamente. Um tipo faixa uma restrio sobre os valores de um tipo ordinal qualquer. Por exemplo: type EstadoCivil = (Solteiro, Casado, Desquitado, Viuvo); DiaMes = 1..31; LetraMaiuscula = 'A'..'Z'; EstadoNaoViuvo = Solteiro..Desquitado; O tipo faixa declarado com o valor inicial e final da faixa, separados por '..' (um ponto seguido de outro). Os valores inicial e final devem pertencer a um tipo ordinal: inteiro, Char, ou enumerado. Depois de declarar o tipo, voc pode criar variveis baseadas no tipo: var dm: DiaMes; letra1, letra2: LetraMaiuscula; est1: EstadoNaoViuvo; x:integer; Qualquer atribuio a uma varivel do tipo faixa verificada, para saber se o valor est dentro dos limites. Por exemplo, os seguintes comandos geram erro de execuo, com uma mensagem "Range Check Error": x := 32; dm := x; {erro: 32 est fora da faixa} letra1 := Chr(32); {erro: ' '(espao) est fora de faixa} estCivil := Viuvo; est1 := estCivil; {erro: Viuvo est fora da faixa}

Opo "Range Checking"


Na verdade, nem sempre o Delphi verifica se um valor est dentro da faixa. Ele s faz isso quando a opo "Range Checking" [verificao de faixa] est ativa nas opes do projeto. Para alterar essa opo, voc deve acionar o menu Project|Options... e, na pgina "Compiler", marcar ou desmarcar o item "Range Checking". Quando essa opo est marcada, ao compilar o programa o Delphi gera cdigo para cada atribuio de varivel do tipo faixa, garantindo que ela no vai receber um valor fora da faixa. Mas esse cdigo gerado aumenta o tamanho do programa e pode tambm reduzir a velocidade de execuo. Geralmente voc deve compilar com "Range Checking" ativo apenas durante o desenvolvimento do programa. Depois que o programa j tenha sido testado, quando for gerar a verso final, desative essa opo para aumentar a eficincia da execuo.

Vetores
Um vetor (tambm chamado matriz) uma varivel que contm vrios elementos do mesmo tipo de dados. Cada elemento possui um ndice que identifica esse elemento no vetor. Podemos criar os vetores de duas formas : Esttica e Dinmica. Um vetor esttico tem um tamanho definido, enquanto que um vetor dinmico no tem tamanho declarado e seu tamanho pode ser mudado durante a execuo do programa.

Vetores Estticos
Para criar um tipo de dados que representa um vetor, usa-se uma declarao array, informando o tipo do ndice e o tipo dos elementos do vetor (ou tipo base). Por exemplo: type TVetor = array [1..30] of double;

65

Essa declarao cria um tipo de vetor, com ndices na faixa de 1 a 30 (um tipo faixa) e elementos do tipo Double. Esse tipo pode ser usado para declarar uma ou mais variveis: var vetA: TVetor; vetB, vetC: TVetor; ind, x: integer; Cada varivel declarada um vetor com 30 elementos do tipo Double, e seus elementos individuais podem ser acessados informando o ndice do elemento entre colchetes: begin vetA[3] := 1000; x := vetA[5]; ind := 10; vetB[ind] := x; end; Na verdade no necessrio definir um tipo, quando voc s precisa de uma varivel daquele tipo. Voc pode inserir a definio do tipo na prpria declarao de varivel: var vetA: array [1..30] of double;

Verificao de Faixa para Vetores


O ndice do elemento pode ser constante ou varivel. De qualquer forma, esse ndice deve estar na faixa definida pelo tipo do ndice. Se o ndice for uma varivel, o Delphi vai verificar em tempo de execuo se a varivel est na faixa, mas apenas se a opo "Range Checking" estiver ativa, a mesma opo que controla verificaes de tipos faixa. Se "Range Checking" estiver desativado, qualquer valor admitido como ndice, e com isso, possvel acessar posies de memria fora do limite do vetor, com resultados imprevisveis. Essa posio de memria pode estar num espao ocupado por outra varivel, e nesse caso essa varivel ser modificada para conter um valor invlido, causando erros em outras partes do programa. Ou a posio pode estar numa rea de memria controlada pelo Windows. Como o Windows restringe o acesso memria apenas s reas reservadas ao programa, ele vai interceptar essa tentativa de acesso e terminar o programa. Geralmente, antes de terminar, o Windows mostra uma mensagem ("Este aplicativo provocou um erro e ser finalizado"). s vezes o Windows permite ao usurio ignorar o erro e continuar, mas na maioria das vezes, a nica opo finalizar a execuo.

Usando Outros Tipos de ndice


O tipo do ndice do vetor um tipo faixa, e por isso usa a mesma sintaxe. O ndice no precisa comear em um ou zero, por exemplo: type TVetorInt = array [-3..3] of integer; TVetorBool = array [0..10] of boolean; O nome do tipo no precisa comear com "T", mas isso uma conveno bastante utilizada para tipos de dados. Voc pode tambm definir um tipo faixa antes e depois utiliz-lo em um vetor: type DiaMes = 1..31; TPresenca = (Presenca, Falta, Feriado); TVetPresenca = array [DiaMes] of TPresenca; Como o ndice pode ser qualquer tipo ordinal ou tipo faixa, ele pode ser do tipo Char, Boolean ou enumerado, por exemplo: type TFreqLetras = array ['A'..'Z'] of longint; var freq: TFreqLetras; letra: Char; maior: Longint; begin for letra := 'A' to 'Z' do freq[letra] := 0;

66

maior := freq['A']; ... end; Outros exemplos so: type TVetIndBool = array [False..True] of integer; TVetIndEnum = array [Solteiro..Viuvo] of string;

Vetores Dinmicos
Para criar um vetor dinmico tambm temos que utilizar a declarao array, informando o tipo dos elementos do vetor (ou tipo base). A diferena do vetor esttico que no informamos os tipo do ndice e o seu tamanho. Essa informao fornecida em tempo de execuo atravs do procedimento SetLength. O ndice inicial do vetor sempre zero. var Vetor : array of double; N:integer; begin N := 10; SetLength(Vetor, N); // muda o tamanho do vetor Vetor[5] := 5; // ele tem elemento de 0 a 9 end; Para redefinir o tamanho do vetor , usa-se a propriedade Setlength novamente com o novo tamanho que deseja . Por exemplo: continuando o exemplo anterior acrescente as seguinte linhas: SetLength(Vetor, 20); // Redefine o tamanho para 20 Vetor[20] := 5; O contedo do vetor na posio 20 5.

Vetores Multidimensionais
Um vetor tambm pode ter mais de uma dimenso, permitindo representar um vetor de vetores. Nesse caso, cada elemento possui dois ou mais ndices. Um vetor multidimensional pode ser criado definindo vrios tipos de ndices: type TMatriz = array [1..10, 1..30] of double; TMarcador = (marcaX, marcaO, marcaNada); TJogoDaVelha = array [0..2, 0..2] of TMarcador; TCubo = array [1..10, 1..10, 1..10] of integer; var m, n: TMatriz; i,j,k:integer; jogo: TJogoDaVelha; lin,col:integer; cubo: TCubo; begin { para acessar um elemento, usa-se dois ndices } m[i,j] := 100.0; for lin := 0 to 2 do for col := 0 to 2 do jogo[lin, col] := marcaNada; cubo[i,j,k] := 0; {trs ndices} end; Podemos tambm criar vetores multidimensionais dinmicos. A idia a mesma do anterior, mas no informamos o tamanho do vetor durante a definio, seu tamanho definido durante o tempo de execuo utilizando tambm o mtodo SetLength e alm disso permito criar para cada linha um nmero diferente de elementos, por Exemplo: var Matriz : array of array of double; begin setLength (Matriz, 2); // muda o tamanho do vetor multidimensional setLength (Matriz[0], 2);

67

setLength (Matriz[1], 5); Matriz[0,1] := 3; Matriz[1, 4] := 5 end;

Exemplo: Clculo de Mdia


Para ver na prtica como utilizamos vetores, vamos criar um novo projeto. O programa vai permitir que o usurio informe uma lista de valores, e depois calcule a mdia dos valores fornecidos. No formulrio altere a propriedade Caption para "Calcula Mdia" e crie componentes no formulrio conforme o seguinte:

Crie um rtulo (componente Label) com Caption "Nmero:" e ao lado dele um componente Edit com nome "editNumero" , coloque a propriedade Text vazia . Crie os botes como mostrado, e mude seus nomes, respectivamente para 'btnAdicionar', 'btnLimpar' e 'btnCalcular'. Ao lado do rtulo "Mdia:", coloque um componente Edit que vai apenas mostrar o resultado. Defina seu nome como 'editMedia'. Coloque sua propriedade Text vazia.Altere sua propriedade ReadOnly para True, o que vai proibir a edio do valor. Altere tambm a propriedade Color escolhendo o valor 'clBtnFace'. Com isso, ele vai ficar da mesma cor do formulrio e dos botes, o que fornece ao usurio uma indicao visual de que ele no pode ser editado. Para o 'btnAdicionar', faa a propriedade Default = True, para que ele possa ser "pressionado" usando a tecla [Enter].

Declarando o Vetor
Antes de fazer qualquer tratamento de eventos, vamos adicionar na unidade uma declarao para o tipo do vetor e uma declarao de varivel desse tipo. Pressione [F12] para abrir o arquivo da unidade. No incio da seo de implementao, aps a palavra implementation, digite o seguinte: type TVetorInt = array [1..3] of double; var Valores: TVetorInt; ContValores: integer; A varivel 'Valores' um vetor do tipo 'TVetorInt', ou seja, um vetor com elementos do tipo 'double' e ndices de 1 a 3. A varivel 'ContValores' ser um contador usado para especificar quantos elementos do vetor esto sendo usados no momento. A cada vez que for clicado o boto "Adicionar", essa varivel ser incrementada.

Adicionando um Elemento
No cdigo do boto 'btnAdicionar', vamos adicionar o nmero que foi digitado (em 'editNumero') ao vetor. A cada clique, vamos tambm incrementar o contador. Digite o seguinte: procedure TForm1.btnAdicionarClick(Sender: TObject); var numero: double; begin numero := StrToFloat(editNumero.Text);{conv. p/ inteiro} ContValores := ContValores + 1; {increm. contador}

68

Valores[ContValores] := numero; {guarda o elemento} { Facilita a digitao do prximo nmero } editNumero.Clear; editNumero.SetFocus; end; Repare que depois de adicionar o elemento, o programa limpa o controle 'editNumero', usando o mtodo Clear. Isso facilita que o usurio digite seqencialmente os nmeros. Tambm para facilitar, o programa devolve o foco de teclado para o controle, no caso de ele ter usado o mouse para clicar no boto. Isso feito com o mtodo SetFocus.

Limpando a Lista
O boto 'btnLimpa' vai "limpar" a lista de valores. Na verdade no precisamos percorrer todos os elementos do vetor, apenas zerar o contador, para indicar que no h nenhum elemento guardado. Faa o seguinte: procedure TForm1.btnLimparClick(Sender: TObject); begin ContValores := 0; end;

Calculando a Mdia dos Elementos


O boto 'btnCalcula' vai fazer a tarefa de calcular a mdia dos elementos do vetor. Para isso, temos que primeiro achar a soma dos elementos e depois dividir a soma pelo contador de elementos. Digite o seguinte, por enquanto: procedure TForm1.btnCalcularClick(Sender: TObject); var soma: double; i: integer; begin soma := 0.0; for i := 1 to ContValores do soma := soma + Valores[i]; Note que o lao for til para percorrer elementos de um vetor. No caso, o valor inicial sempre 1 e o valor final varivel, determinado por 'ContValores'. Aps fazer a soma, devemos fazer uma diviso dessa soma pelo contador. Mas antes, para evitar um erro de execuo, vamos verificar se o contador zero: if ContValores = 0 then editMedia.Text := 'Erro' else editMedia.Text := FloatToStr(soma/ContValores); end; Note que se 'ContValores' inicialmente for zero, o lao for no far nada (o valor final menor do que o inicial).

Testando o Programa
Execute o programa. Digite um nmero e clique no "Adicionar", ou tecle [Enter]. Repita o processo para adicionar alguns nmeros lista. (Repare que, como o programa no faz ainda verificao de erro, se voc digitar um valor no numrico e clicar em Adicionar, vai ver uma mensagem de erro do Delphi). Depois clique em "Calcular" para calcular o resultado. Se voc digitar, por exemplo, 13, 28 e 34, o resultado final ser: 25. No menu Project|Options na pasta Compiler se a opo RangeCheck estiver marcada , desmarque esta opo e pede para recompilar todo o projeto novamente (Project|Compile Mediap). Com isso se pedir para informar mais de 3 nmeros para ser adicionados a mdia , o Delphi no ir fazer a verificao se ultrapassou o tamanho do vetor, seu exemplo pode at continuar funcionando, vai depender da rea de memria que foi utilizada para acrescentar esses valores que foram colocados a mais, para que ocorre esta verificao a opo RangeCheck tem que estar marcada.

69

Salvando o Projeto
Vamos retornar a esse projeto mais tarde, portanto salve-o como MEDIA.PAS (unidade) e MEDIAP.DPR (projeto).

Conjuntos
O tipo de dados conjunto representa a noo matemtica de conjuntos, permitindo fazer todas as operaes padro de conjuntos. Um conjunto pode conter elementos de qualquer tipo ordinal (ou faixa). Para criar um tipo conjunto, usa-se a declarao set: type TConjCarac = set of char; TConjLetra = set of 'A'..'Z'; TConjDia = set of 1..31; TConjEstado = set of EstadoCivil; Para atribuir um valor (constante) a uma varivel conjunto, especifica-se os elementos do conjunto entre colchetes: var vogais: TConjLetra; diasUteis: TConjDia; begin vogais := ['A','E','I','O','U']; diasUteis := [1..10, 13, 15, 20..23]; Note que uma faixa de valores pode ser colocada, para evitar enumerar todos os valores.

Verificando Elementos
Voc pode verificar se um elemento pertence a um conjunto, com o operador in, que equivale em matemtica operao x c. Por exemplo: if caractere in vogais then texto := 'Vogal' else texto := 'Consoante'; if dia in diasUteis then ... if estCivil in [Desquitado, Viuvo] then ... Esse tipo de teste mais eficiente do que uma srie de ifs, alm de mais legvel. Vamos abrir o projeto CALCP para fazer uma alterao semelhante em um dos testes. No cdigo associado ao evento OnKeyPress, do 'editOperando1', existe um if que testa os valores possveis da varivel 'Key': if ((Key < '0') or (Key > '9')) and (Key<> #8) then Key := #0; { rejeita a tecla } Vamos alterar esse if para utilizar um conjunto. Substitua pelo seguinte: if not (Key in ['0'..'9', #8]) then Key := #0; ou seja, se a tecla no estiver no conjunto formado por '0'..'9', mais o backspace (#8), ela ser rejeitada. Esse teste bem mais simples e mais eficiente do que o teste anterior.

Operaes com Conjuntos


Suponhamos duas variveis do tipo set of integer (conjunto de inteiros), recebendo os seguintes valores: A := [1, 2, 3, 5, 7, 11]; B := [1, 3, 5, 7, 9]; Voc pode fazer vrios tipos de operaes com variveis conjunto, que so as seguintes: B. O resultado da unio um conjunto que contm todos os elementos de Unio: C = A ambos os conjuntos. A unio feita com o operador +. Por exemplo: C := A + B; { o resultado ser [1, 2, 3, 5, 7, 9, 11] }

70

Interseo: C = A B. O resultado da interseo um conjunto que contm um elemento em comum entre os dois conjuntos. A interseo feita com o operador "*", por exemplo: C := A * B; { O resultado ser [1, 3, 5, 7] } Diferena: C = A - B. O resultado de A menos B o conjunto com os elementos de A que no existem em B. A diferena feita com o operador "-": C := A - B; { O resultado ser [2, 11] } C := B - A; { O resultado ser [9] } Contido: A B (A est contido em B) ou B A (B contm A). Verifica se todos os elementos de um conjunto pertencem tambm ao outro conjunto. No Object Pascal, o operador (est (contm) por >= Por exemplo: contido) representado por <= e {verifica se os elementos 1 e 3 pertencem ao conjunto A} if [1,3] <= A then ... {verifica se B contm A} if B >= A then ...

Propriedades de Conjunto
Algumas propriedades de componentes do Delphi utilizam tipos de conjunto. Por exemplo, a propriedade BorderIcons de um formulrio contm um conjunto de valores, onde cada um determina se o formulrio ter ou no um determinado item da borda. Essas propriedades aparecem no Object Inspector com um sinal de "+" e o seu valor aparece com a sintaxe de conjunto. Quando voc clica duas vezes no nome da propriedade, aparecem subitens, que permitem adicionar ou remover elementos do conjunto. Para atribuir um valor para este tipo de propriedade no programa, voc deve usar a sintaxe de conjunto, por exemplo: BorderIcons := [biSystemMenu, biMinimize, biMaximize]; Para alterar o valor, por exemplo, adicionando um elemento, voc deve usar os operadores de conjuntos: BorderIcons := BorderIcons + [biMinimize]; Para verificar se um elemento est presente, voc deve usar o operador in: if biMaximize in BorderIcons then ...

71

Depurao
Para encontrar as causas de uma exceo, ou para detectar erros de lgica no programa (erros que s voc pode saber que esto acontecendo), voc pode usar os mecanismos de depurao do Delphi. O processo de depurao [debugging] consiste em analisar o funcionamento do programa durante e execuo, vendo os valores de variveis, o fluxo da execuo, e assim por diante.

Colocando um Ponto de Parada


Para comear a depurao do programa, voc deve escolher um ponto inicial onde voc vai entrar em modo de depurao. Para isso coloque um ponto de parada [breakpoint] na linha onde voc quer comear. No nosso caso, coloque o cursor na primeira linha aps o begin, a que contm soma := 0. Para colocar ou retirar um ponto de parada voc pode usar a tecla [F5], ou clique na margem esquerda do editor, esquerda da linha. Em qualquer caso, o editor de cdigo mostra a linha destacada em vermelho e um marcador vermelho esquerda indicando um ponto de parada. Execute o programa, adicione uns dois ou trs nmeros e depois clique em "Calcular". Quando o Delphi encontra o ponto de parada, ele pra a execuo e destaca a linha atual. A janela principal do Delphi agora deve mostrar no ttulo "Delphi - Mediap [Stopped]". A palavra stopped [parado] significa que voc est em modo de depurao, com a execuo parada na linha atual. Para fazer os prximos testes, voc pode precisar executar vrias vezes o mesmo procedimento de evento. Depois da primeira vez, basta clicar no boto Calcular novamente. Nota: voc tambm pode colocar um ponto de parada com o menu Run|Add Breakpoint|Source Breakpoint. Nesse caso, voc pode especificar uma condio de parada (Condition) e quantas vezes a linha deve ser executada antes de fazer uma parada (Pass count). Nota: as linhas que podem ter breakpoints esto marcadas com pontos azuis. As outras no esto relacionadas a cdigo executvel.

Executando Passo a Passo


Quando voc est em modo de depurao, voc tem vrias opes. Se quiser continuar a execuo normal, tecle [F9]. A janela do Delphi vai mudar para "Delphi - Mediap [Running]" indicando modo de execuo normal. Voc pode, ao invs disso, acompanhar passo a passo a execuo do programa. Execute novamente at chegar ao ponto de parada. Depois tecle [F7] ou [F8] (nesse caso tanto faz) para executar essa linha e passar para a prxima. A cada vez que voc teclar [F7] ou [F8], voc vai executar uma linha e o tringulo que aparece esquerda se move indicando a prxima linha que ser executada. Com isso voc pode acompanhar o lao for, por exemplo. O comando dentro do for vai ser executado quantas vezes forem os nmeros que voc adicionou com o boto Adicionar. Essas teclas tambm equivalem a itens de menu do Delphi ou botes da SpeedBar: Tecla Boto Item de Menu [F7] Run|Trace Into [F8] Run|Step Over

A diferena entre "Trace Into/F7" e "Step Over/F8" s importante quando voc passa por uma chamada de procedimento. "Trace Into" entra no procedimento e executa cada linha dele passo a passo tambm. Isso pode ser o que voc quer, mas em alguns casos um procedimento j foi totalmente testado e voc no precisa acompanhar sua execuo de novo. Nesse caso, use "Step Over", que executa o procedimento inteiro em modo de execuo normal e depois volta ao modo depurao, depois da chamada do procedimento.

Executando At o Cursor
s vezes, durante a depurao voc quer "pular" para uma determinada linha diretamente, executando todo um trecho em velocidade normal de execuo. Por exemplo, durante a

72

execuo, voc pode querer ir diretamente ao fim do lao for, em vez de acompanhar cada passagem. Para isso coloque o cursor na linha onde quer parar (por exemplo, no if depois do for) e use o item de menu Run|Run To Cursor ou sua tecla de atalho, [F4]. Nota: se a execuo nunca chegar linha do cursor, o programa entrar em modo de execuo normal ("Running") e no voltar automaticamente ao modo de depurao.

Vendo Valores de Variveis


Em modo de depurao, voc pode ver qual o valor atual de uma varivel ou, at mesmo, alterar o valor da varivel, afetando o funcionamento do programa da forma que voc quiser. Para isso, basta passear o cursor por cima do texto do programa. Quando o cursor estiver em cima do nome de uma varivel, o valor desta ser mostrado. Esse recurso chamado de avaliao instantnea. Nota: a avaliao instantnea, como outros recursos de depurao, funciona apenas em modo depurao [Stopped] e no em modo de execuo normal [Running]. Para ver outras variveis ou alterar seus valores, use o comando Run |Evaluate/Modify... ou sua tecla de atalho, [Ctrl+F7]. Se voc clicar no nome de uma varivel e teclar [Ctrl+F7], a janela "Evaluate/Modify" aparece, mostrando o valor atual da varivel e permitindo voc digitar um novo valor em "New value:":

Voc tambm pode digitar o nome de outra varivel ou uma expresso qualquer em "Expression", por exemplo, "soma * 10 / 7", usando a janela como uma calculadora. Ou voc pode digitar o nome de uma constante (para saber o valor de uma constante predefinida do Delphi por exemplo), ou uma propriedade de um componente. Ao clicar em "Evaluate", voc ver o valor da expresso, varivel ou constante. Se for uma varivel, voc ter a opo de modificar o valor.

Monitorando o Valor de uma Varivel Dinamicamente


Se voc quer acompanhar o valor de uma varivel a cada momento da execuo, voc pode adicionar um "watch" [sentinela], que um mostrador permanentemente atualizado com o contedo da varivel. Para adicionar um "watch" para a varivel 'soma', por exemplo, clique no nome da varivel e use Run |Add Watch... ou a tecla [Ctrl+F5]. Existem vrias opes nesta janela, mas mantenha as opes padro e clique Ok. O Delphi vai mostrar a janela "Watch List", que contm todos os "watches" adicionados. Voc pode mov-la para uma posio qualquer da tela onde no cubra outras janelas. Agora medida que voc usar Trace Into/F7 ou Step Over/F8, o "watch" vai mostrar o valor da varivel sendo alterado.

73

Para editar um "watch", clique duas vezes em cima dele na janela "Watch List" e altere suas opes. Para remov-lo, clique na lista e pressione [Delete]. Para adicionar um novo, com a janela "Watch List" aberta, clique duas vezes na linha vazia depois do fim da lista.

Forando a Finalizao do Programa


Quando, durante a depurao, voc quiser terminar a execuo do programa, o melhor a fazer continuar sua execuo normal e depois fechar a janela do programa. No entanto, s vezes necessrio forar a terminao do programa. Para fazer isso, use o item de menu Run |Program Reset ou tecle [Ctrl+F2] (essa tecla de atalho s funciona se voc estiver com o foco em uma janela do Delphi).

Outras Ferramentas de Depurao


Enquanto voc est em modo de depurao, voc pode chegar a executar um procedimento que foi chamado por outro, que por sua vez foi chamado por outro e assim por diante. Para esse tipo de programa mais complexo, voc pode visualizar a pilha de chamadas [call stack], que mostra toda a seqncia de chamadas de procedimento feitas at o ponto atual, desde o primeiro procedimento de evento executado. Para isso, use o menu View|Debug Windows|Call Stack[Ctrl+Alt+S]. As outras opes que aparecem em View|Debug Windows|Call so: Threads opo para verificar multiplas linhas de execuo (threads). Modules visualizar DLLS , que o programa utiliza. CPU mostra o cdigo assembler de dlls e programas, indenpendente se possui o cdigo fonte. Se voc se perder durante a depurao e quiser encontrar a linha que est sendo executada agora, use o menu Run|Show Execution Point.

74

10 - Procedimentos e Funes
Procedimentos Gerais Unidades Independentes Funes Passagem de Parmetros

75

Procedimentos Gerais
Um procedimento um trecho de programa que tem um nome e pode ser utilizado (chamado) por outras partes do programa. Um procedimento de evento um procedimento que est diretamente ligado a um evento e chamado diretamente por um componente quando acontece aquele evento. Como j vimos, procedimentos de evento geralmente so criados pelo Delphi de forma automtica. Mas voc pode criar tambm procedimentos gerais, que no so associados a nenhum componente, e s so chamados quando voc determinar. Procedimentos gerais tornam o programa mais legvel e evitam repetio desnecessria de cdigo, facilitando a manuteno do programa. Em muitos casos, eles tambm contribuem para a reduo do tamanho do programa. Eles tambm podem ser reutilizados em vrios projetos, evitando "reinventar a roda" a cada novo programa que voc desenvolve.

Criando um Procedimento Geral


Abra novamente o projeto da calculadora, CALC.DPR. Nesse projeto temos uma validao de tecla, feita pelo procedimento de evento 'tratartecla'. Mas vamos transform-la em um procedimento geral, para poder reutilizar essa validao em outros programas. Quando voc cria um procedimento de evento, o Delphi gera automaticamente o esqueleto do procedimento, ou seja, um cabealho, mais o begin e end, inicialmente vazios. Mas um procedimento geral deve ser criado manualmente, ou seja, voc deve digitar todo o esqueleto. Na unidade CALC.PAS, coloque o cursor depois da palavra implementation e do comentrio {$R *.DFM}. Digite todas as linhas a seguir: procedure ValidarTecla(var tecla: char); begin end; O cabealho do procedimento contm a palavra procedure, o nome do procedimento (vamos cham-lo de 'ValidarTecla') e, entre parnteses, os parmetros do procedimento. Parmetros so variveis que recebem informaes externas, passadas por quem chamar o procedimento. Agora, dentro do procedimento 'TForm1.TratarTecla', selecione todo o texto entre o begin e o end e tecle [Ctrl+X] para retir-lo e guardar na rea de transferncia do Windows. Substitua o texto anterior por: ValidarTecla(Key); Isso vai chamar o procedimento, substituindo o parmetro 'tecla' pelo argumento 'Key'. Argumentos so informaes passadas para o procedimento para substituir os parmetros. Volte ao procedimento 'ValidarTecla' e, dentro dele, use [Ctrl+V] para inserir o cdigo que foi copiado antes. Faa a seguinte alterao no cdigo: substitua as referncias a 'Key' por 'tecla'. O procedimento dever ficar como o seguinte: procedure ValidarTecla(var tecla: char); begin if not (tecla in ['0'..'9', #8]) then tecla := #0; end; O argumento (Key) e o parmetro (tecla) na verdade poderiam ter o mesmo nome. Ns colocamos nomes diferentes apenas para que o procedimento tenha uma forma mais geral. Execute o programa e ele deve continuar funcionando como antes.

Unidades Independentes
Da forma que o procedimento est, ele s pode ser usado na unidade CALC.PAS, associada ao formulrio da calculadora. Se quisermos que o procedimento seja usado por outras unidades do projeto, devemos colocar uma declarao do procedimento na interface da unidade. Mas essa ainda no a soluo ideal, pois para utilizar uma unidade associada em outro projeto, necessrio tambm utilizar o seu formulrio, mesmo que ele no seja necessrio. O melhor colocar o procedimento em uma unidade independente, ou seja, uma unidade no

76

associada a nenhum formulrio. Unidades independentes facilitam a reutilizao, especialmente entre vrios projetos.

Criando uma Unidade Independente


Para criar uma unidade independente, use o item de menu File|New... do Delphi, escolha ) e clique Ok. O Delphi vai abrir a nova unidade no editor de cdigo, o cone "Unit" ( contendo apenas um esqueleto do mnimo que uma unidade deve ter (como vimos no captulo 9): unit Unit2; interface implementation end. Salve o projeto para dar um nome nova unidade. Chame-a de GERAL.PAS (porque ela vai conter procedimentos gerais). O cabealho da unidade automaticamente vai mudar para 'unit Geral;'.

Transferindo o Procedimento
Voltando unidade Calc (use as abas do editor de cdigo para mudar entre as duas), selecione todo o procedimento 'ValidarTecla', inclusive o cabealho. Tecle [Ctrl+X] para recort-lo da unidade. Agora alterne para a unidade Geral, coloque o cursor depois da palavra implementation e "cole" o texto, usando [Ctrl+V]. O corpo do procedimento deve ficar na seo de implementao, mas se ele precisar ser usado externamente, o cabealho do procedimento deve ser copiado para a seo de interface. Coloque o cursor na seo de interface e tecle [Ctrl+V]. Apague do begin ao end, porque s necessrio (e s permitido) o cabealho. A unidade ficar assim: unit Geral; interface procedure ValidarTecla(var tecla: char); implementation procedure ValidarTecla(var tecla: char); begin if not (tecla in ['0'..'9', #8]) then tecla := #0; end; end.

Usando a Unidade no Mesmo Projeto


Para utilizar os procedimentos da unidade 'Geral' em outra unidade, voc deve acrescentar 'Geral' clusula uses da unidade. Voltando unidade Calc, ela ainda no tem uma clusula uses na seo de implementao, ento acrescente uma, logo aps o {$R *.DFM}, contendo o seguinte: uses Geral; Execute o programa e ele dever funcionar como antes. Salve o projeto novamente.

Usando a Unidade em Outros Projetos


Abra o projeto MEDIAP.DPR. A unidade Geral, que criamos no outro projeto, um nico arquivo fonte (GERAL.PAS), que pode ser reutilizado quando necessrio em qualquer outro

77

projeto. Primeiro acrescente a unidade ao projeto atual, usando File|Add to project... ou o da SpeedBar e escolhendo GERAL.PAS. Esse passo no estritamente boto necessrio(caso a unit GERAL esteja no mesmo diretrio que o projeto MEDIAP), mas importante para facilitar o gerenciamento do projeto, como veremos. Depois, voc deve acrescentar o nome da unidade clusula uses da unidade MEDIA.PAS, associada ao formulrio. A forma mais fcil de fazer isso a seguinte: selecione a unidade "Media" no editor de cdigo, e use o item de menu File|Use unit.... Na lista, clique em "Geral" e depois em Ok. O Delphi ir adicionar o seguinte seo de implementao da unidade: uses Geral; Agora crie um procedimento de evento para o controle 'editNumero', evento OnKeyPress. Dentro do procedimento, coloque uma chamada a 'ValidarTecla'. Inicialmente digite apenas o seguinte e deixe o cursor posicionado aps o parntese: ValidarTecla( Repare que o Delphi mostra uma descrio dos parmetros do procedimento (no caso apenas var tecla: char). Essa uma caracterstica do Code Insight que permite saber facilmente quais so os parmetros que um determinado procedimento exige e o CodeExplorer mostra o procedimento na lista. Complete a linha como abaixo: ValidarTecla(Key); Ou seja, vamos passar como argumento a varivel 'Key'. Execute o programa. Note que agora o controle 'editNumero' agora tem a mesma validao de tecla, no permitindo valores no numricos.

Gerenciando um Projeto com Unidades Independentes


Ns vimos anteriormente que o Project Manager usado para facilitar o gerenciamento de projetos com vrios arquivos. Abra o Project Manager novamente e repare que a unidade independente 'Geral' aparece na lista de arquivos do projeto. Ele no permite expandir o arquivo GERAL.PAS, obviamente, pois essa unidade no est associada a um formulrio. Alm do Project Manager, voc pode usar o boto (View Unit) para ver as unidades do projeto, incluindo unidades independentes. Se voc no adicionar uma unidade ao projeto, mas apenas adicionar uma clusula uses para ela, voc ainda pode acess-la,desde que esteja no mesmo diretrio do projeto ou no diretrio LIB do Delphi), mas ela no estar disponvel nas facilidades de gerenciamento de projeto.

Criando uma Biblioteca de Rotinas


Uma unidade independente pode funcionar como uma biblioteca de rotinas mais utilizadas, compartilhada por vrios projetos. Mas nesse caso preciso tomar certos cuidados. Por exemplo, se voc modificar um procedimento, isso pode afetar o funcionamento de outros projetos que o utilizam. Tambm, para que um procedimento seja reutilizvel, preciso que ele no dependa de nada especfico de um determinado projeto, como um formulrio ou uma varivel global, ou outra unidade. Uma unidade pode conter tambm, alm de procedimentos, constantes, tipos de dados definidos e variveis. Se estes forem declarados na parte interface, podem ser usados tambm por outras unidades. No caso de uma constante ou tipo de dados, pode ser necessrio us-la(o) ainda na seo de interface. Nesse caso (e apenas nesse caso) necessrio acrescentar o nome a unidade clusula uses da seo de interface. Em todos os demais casos, melhor acrescent-la na seo de implementao.

78

Funes
Funes so semelhantes a procedimentos, mas so chamadas geralmente dentro de uma expresso. Uma funo retorna um valor para quem chamou, e esse valor inserido na expresso onde a funo foi chamada, por exemplo: x := 3 * Soma(a,b); Durante a execuo, a funo 'Soma' chamada, com os seus parmetros preenchidos de acordo com os argumentos fornecidos (a e b). A funo ento devolve um resultado, que inserido na expresso. Depois continua o clculo do restante da expresso.

Criando uma Funo


Vamos abrir novamente o projeto CALCP. Agora dentro da unidade Geral, vamos criar uma funo. Essa funo no vai fazer nada realmente til, pois apenas soma dois nmeros e devolve o resultado, mas ela ilustra os detalhes mais importantes que envolvem a criao e uso funes. Na seo de interface, digite o cabealho da funo: function Soma(x,y: double): double; No cabealho da funo, alm do nome e parmetros, preciso declarar o tipo de retorno da funo, ou seja, o tipo de dados do valor que a funo devolve. No caso, o tipo double, declarado depois do fecha parnteses. Agora na seo de implementao, repita o cabealho da funo e acrescente o corpo da funo, contendo o seguinte: function Soma(x,y: double): double; begin Result := x + y; end;

Retornando um Valor
O nome 'Result' uma varivel automaticamente criada (no precisa ser declarada) dentro de uma funo. O valor colocado nessa varivel ser o valor retornado pela funo, que ser inserido no ponto de chamada. No caso, o valor calculado como a soma dos valores dos dois parmetros (x e y). O tipo dessa varivel o tipo de retorno da funo, no caso double. Para determinar o valor de retorno, tambm pode ser usada a sintaxe de antigas verses do Pascal, com o nome da funo do lado esquerdo: Soma := x + y; A desvantagem dessa sintaxe que no possvel usar o nome 'Soma' do lado direito de uma atribuio, como possvel fazer com 'Result'. Ex: Soma := Soma + y;

Chamando a Funo
No formulrio principal, clique duas vezes no boto com o sinal de "=" (btnCalcula) para abrir o procedimento de evento associado. Neste procedimento substitua a linha: res := op1 + op2; por uma chamada funo. Inicialmente digite apenas o seguinte e deixe o cursor aps o abre parnteses: res := Soma( Note que o recurso de Code Insight do Delphi automaticamente mostra a descrio dos parmetros (x: double; y: double). Caso voc no se lembre mais dos parmetros exigidos, esse recurso facilita bastante. Complete o restante da linha, com os argumentos: res := Soma(op1, op2); Note que os argumentos so separados por "," (vrgula) na chamada. Execute o programa e verifique que ele continua funcionando como antes. Notas: Se deseja ver o contedo de um procedimento ou funo ,clique com Ctrl+Clique . Notas: Se colocou o cabealho de um procedimento ou funo na seo interface, e deseja cri-los pressione Ctrl+Shift+C.

79

Notas: Para alternar da seo implementation , para seo interface pressione Ctrl + Shift + ( ) , o contrrio utilize Ctrl+Shift + ( ).

Passagem de Parmetros
Quando um procedimento ou funo possui parmetros, ele deve ser chamado com argumentos correspondentes, na mesma ordem. Nenhum argumento deve ser omitido. (A documentao do Delphi chama os parmetros de formal parameters e argumentos de actual parameters). Por exemplo: begin ValidarTecla(Key); end; ... procedure ValidarTecla(var tecla: char);

Declarao de Parmetros e Argumentos


Quando h mais de um parmetro, esses so separados por ";" (ponto-e-vrgula) na declarao do procedimento, se tm tipos diferentes: function Soma(x: double; y: integer): double; ou podem ser separados com ",", se tm o mesmo tipo: function Soma(x, y: double): double; e as duas formas podem ser combinadas, exatamente como em declaraes de variveis: procedure TextOut(x,y:integer; text:string); Na chamada ao procedimento ou funo, os argumentos so sempre separados por "," (vrgulas): x := Soma(12, TAMANHO); TextOut(x, 13, 'Testando'); O nome do procedimento pode ser repetido no projeto ou na unit, o que diferencia um procedimento do outro o nmero e tipo de parmetros passados. Por Exemplo: A funo soma pode realizar a soma entre dois , trs e quatro nmeros , sendo que quando a soma for realizada entre quatro nmeros os dois ltimos so do tipo string. Como na Unit GERAL j existe uma funo que realiza a soma de dois nmeros , vamos criar as outras com o mesmo nome: function Soma( op1, op2, op3 : double): double; begin result := op1 + op2 + op3; end; function Soma( op1, op2 : double, op3, op4 : string): double; begin result := op1 + op2 + strtofloat(op3) + strtofloat(op4); end; Mas alm de criar as funes ou procedimentos com o mesmo nome necessrio que durante a declarao do procedimento especficique que eles sero sobrecarreagados, para isso temos que informar no final da declarao a diretiva overload. function Soma(x,y: double): double;overload; function Soma( op1, op2, op3 : double): double;overload; function Soma( op1, op2 : double; op3, op4 : string): double;overload;

Tipos de Passagem
Existem vrias opes disponveis para passagem de parmetros de procedimentos ou funes. (Os nomes entre colchetes esto como aparecem na documentao do Delphi): Passagem por Valor [value parameter]: o valor do argumento (que pode ser uma varivel, constante ou uma expresso) simplesmente copiado para o parmetro. Isso significa tambm que qualquer alterao no parmetro no afeta o argumento original, mas apenas uma cpia

80

local. Esse o mtodo padro de passagem, ou seja, um parmetro passado por valor se no for especificado em contrrio. A funo 'Soma' usa esse mtodo para os dois parmetros. Se o parmetro Tecla da funo Validar tecla for do tipo passagem por valor , o programa que chamar este procedimento no vai funcionar, porque o programa ir escrever os caracteres invlidos, portanto , necessrio alterar o argumento original. Passagem por Referncia [variable parameter]: o argumento deve ser uma varivel do mesmo tipo de dados do argumento. Qualquer alterao no parmetro afeta imediatamente o argumento original. Para indicar passagem por referncia, usa-se a palavra var antes do nome do parmetro. O procedimento 'ValidarTecla', por exemplo, usa passagem por referncia, porque precisa alterar o argumento original. Passagem Constante [constant parameter]: um parmetro constante (declarado com const antes do nome) no pode ser modificado dentro do procedimento. Essa caracterstica pode ser usada para impedir alteraes acidentais que violariam a lgica do programa. O argumento pode ser uma expresso qualquer. No caso de parmetros grandes, como vetores e registros, a passagem constante evita que seja feita uma cpia do argumento, como na passagem por valor, portanto bem mais eficiente. No mesmo procedimento ou funo, um parmetro pode ser passado por valor e outros por referncia ou constantes, independentemente um do outro. Funes especificamente no precisam ter parmetros por referncia, pois elas j retornam um valor atravs da prpria chamada de funo, mas em alguns casos a passagem por referncia pode ser til.

81

Captulo 11 Objetos
O que Contm um Objeto Classes e Objetos Herana Formulrios como Objetos Variveis de Objetos Listas de strings Objetos Predefinidos Code Explorer Programao Orientada a Objeto

82

O Que Contm um Objeto


Um objeto, numa definio prtica, uma rea de memria separada do computador, contendo dados e o cdigo que manipula esses dados, e que manipulada como uma nica unidade. Por exemplo, qualquer componente, um formulrio, uma lista de strings, ou o objeto Clipboard. Nos programas, os dados de um objeto aparecem como campos do objeto, ou geralmente, como propriedades. Um objeto pode ter campos de dados que no so visveis externamente, com isso mantendo todo o controle sobre sua implementao interna. O cdigo de programa que manipula os dados feito atravs de mtodos. Um mtodo tem acesso a todos os campos de dados do objeto, mesmo aqueles que no so visveis externamente. Um mtodo pode ser um procedimento, que executa alguma ao quando chamado, ou uma funo, que alm de executar uma ao, retorna um valor para quem chamou, que pode ser usado em uma expresso.Os procedimentos de eventos criados so mtodos do objeto do formulrio criado. Por exemplo, com alguns mtodos que j vimos: editNumero.SetFocus; {mtodo procedimento: SetFocus} Lines.SaveToFile(nome); {mtodo procedimento: SaveToFile} if Clipboard.HasFormat(cf_text) then {mtodo funo: HasFormat} Um componente, que um tipo de objeto, pode ter tambm eventos, que so propriedades cujo valor um procedimento de evento. O procedimento que est associado a um evento chamado quando ele acionado.

Classes e Objetos
Todo objeto pertence a uma classe. Uma classe um esquema que deve como sero os objetos, quais suas caractersticas, e quais os mtodos que podem ser usados para manipular o objeto. Cada objeto especfico uma instncia da classe, criada de acordo com o modelo definido pela definio da classe. Por exemplo, cada cone da paleta de componentes corresponde a uma classe. O nome dessa (Edit) corresponde classe tem a letra 'T' antes do nome que aparece. Por exemplo, o cone classe TEdit. Quando voc seleciona esse cone e clica no formulrio, voc est criando um objeto da classe TEdit, que chamado (inicialmente) de "Edit1". Voc pode criar quantos objetos quiser da mesma classe, limitado apenas pela memria do computador. Se voc criar outros, eles sero chamados de "Edit2", "Edit3". O Object Inspector sempre mostra o nome do componente e o nome de sua classe, por exemplo:

Todos os objetos de uma mesma classe tm as mesmas caractersticas (propriedades), mas cada um tem seus prprios valores para essas caractersticas. Quando voc cria um objeto, ele comea como uma cpia idntica do modelo definido pela classe, e suas propriedades (exceto Name, que deve ser nico) comeam com os mesmos valores padro que a classe define. Depois voc pode alterar essas propriedades, diferenciando um objeto do outro. Voc pode tambm criar um objeto dinamicamente, durante a execuo do programa, conforme veremos.

83

Herana
Classes geralmente no so criadas a partir do zero. Quando voc cria uma nova classe, ela pode ser baseada em uma classe que j existe. Com isso, a classe herda todos os dados e mtodos da outra classe, mas pode acrescentar ou redefinir alguns de acordo com o que necessrio. O mecanismo de herana [inheritance] permite que voc programe apenas o que diferente entre a sua classe e a outra (programao por exceo). A classe da qual so herdadas as caractersticas chamada de classe base ou ancestral [ancestor] e a classe criada chamada de classe derivada ou descendente [descendent]. Herana no apenas uma cpia esttica de caractersticas. Qualquer alterao feita em uma classe ancestral automaticamente repercute nas classes descendentes. Quando a herana usada sucessivamente, com uma classe derivada tambm tendo classes derivadas, criada uma hierarquia [hierarchy] de classes, que pode ser representada com uma estrutura em rvore.

Hierarquia de Classes do Delphi


Ns j vimos que "todo controle um componente". Da mesma forma, "todo componente um objeto". Essas frases dizem respeito exatamente a relaes entre classes ancestrais e classes derivadas no Delphi. A classe 'TComponent' a ancestral, direta ou indireta de todas as outras classes de componentes. Ela contm as propriedades Name e Tag (alm de outras pouco usadas), que so herdadas por todas as outras classes descendentes. A classe 'TControl' uma das descendentes de TComponent. Ela contm propriedades, como Enabled, Visible, Left, Top, Width e Height e mtodos, como Refresh, que so herdados por todas as classes de controles, por exemplo, TEdit, TButton, TLabel. Todo formulrio tambm um controle. A classe 'TForm', que define as caractersticas de qualquer formulrio, descendente indireta de TControl. Quando voc cria um novo formulrio, o Delphi cria automaticamente uma classe de formulrio descendente de TForm, ou seja, seu formulrio tem todas as caractersticas de um formulrio padro, alm das que voc acrescentar (novos campos de dados, novos mtodos etc.). O nome da sua classe de formulrio criado com 'T' seguido do nome do formulrio, por exemplo, 'TMeuForm'. Uma viso simplificada de uma hierarquia de classes (omitindo algumas intermedirias) a seguinte: TComponent (ancestral de todos componentes) TOpenDialog (um componente que no controle) TControl (ancestral de todos controles) TForm (ancestral de todos formulrios) TFormPrincipal (suas classes... TFormCalen ...de formulrio) TButton (classes de... TEdit ...controles) TTimer (um componente que no controle) Todas as classes no Delphi, inclusive TComponent, so descendentes diretas ou indiretas da classe TObject, que contm apenas mtodos bsicos de manipulao de objetos. Voc pode tambm criar uma nova classe de componente, derivando uma classe de TComponent ou de alguma descendente desta. Mas este um processo mais complexo, que envolve vrios detalhes de programao, e por isso no cobriremos no curso.

O Object Browser
Para visualizar a hierarquia de classes do Delphi e da sua aplicao, existe uma ferramenta que pode ser usada para isso. o Object Browser, que pode ser aberto no Delphi com o menu View|Browser (s est disponvel depois que voc compilou o projeto ao menos uma vez). Alm de classes, o Object Browser permite ver quais as constantes, tipos de dados e variveis das unidades utilizadas no projeto.

Simplificando o Acesso aos Campos

84

Campos, propriedades e mtodos de um objeto so acessados, geralmente, usando-se a sintaxe que j vimos, com o nome do objeto, seguido de um ponto e o nome do campo, propriedade ou mtodo: editTamanho.Clear; editTamanho.Enabled := True; editTamanho.SetFocus; Mas quando se acessa vrios campos do mesmo objeto, preciso repetir o nome do objeto em cada comando. Para evitar isso, existe o comando with. Dentro do bloco do comando with, o nome do objeto fica implcito: with editTamanho do begin Clear; Enabled := True; SetFocus; end;

85

Formulrios como Objetos


Formulrios tambm so objetos. Quando voc cria um novo formulrio, o Delphi cria uma classe de formulrio e um objeto de formulrio dessa classe. O nome da classe de formulrio sempre inicia com um T, seguido do nome do objeto de formulrio (que voc define na propriedade Name do formulrio). A vantagem de ter uma classe de formulrio que isso torna possvel criar dinamicamente outros objetos de formulrio, alm do inicial, e alterar suas propriedades.

A Classe de Formulrio
Abra o projeto CalcData.DPR(Captulo 8). Voc ver inicialmente o formulrio principal. Tecle [F12] para ver a unidade do formulrio. Na seo de interface da unidade, logo aps a clusula uses, voc ver a declarao da classe de formulrio: type TFormPrincipal = class(TForm) btnCalendario: TButton; btnCalculadora: TButton; btnFechar: TButton; editData: TEdit; Label1: TLabel; procedure btnFecharClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure btnCalculadoraClick(Sender: TObject); procedure btnCalendarioClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var formPrincipal: TFormPrincipal; A primeira linha: TFormPrincipal = class(TForm) quer dizer que a classe do formulrio baseada na classe 'TForm', que define um formulrio genrico. Veremos mais sobre isso mais tarde. Dentro da definio da classe (que vai at a palavra end), existe uma declarao para cada componente do formulrio (no caso Button ,Edit e Label). Se voc adicionar, remover, ou renomear qualquer componente, o Delphi altera automaticamente essa seo. Para testar, alterne para o formulrio com [F12] e acrescente um componente Button. Quando voc volta unidade, pode verificar que o Delphi acrescentou uma declarao para esse componente: Button1: TButton; onde 'Button1' o nome do componente e 'TButton' o nome da classe do componente, como veremos adiante. Volte ao formulrio, remova o boto e o Delphi vai tambm remover essa declarao. Depois das declaraes de componentes, comeam as declaraes para os procedimentos de evento. Para cada procedimento de evento, o Delphi adiciona uma declarao dentro da classe, como: procedure btnFecharClick(Sender: TObject); O corpo do procedimento, que fica na seo de implementao, contm os comandos que implementam realmente o procedimento. O cdigo at a palavra private mantido automaticamente pelo Delphi e voc no deve alterlo. Geralmente no existe motivo para fazer alteraes manuais. As sees private e public dentro da definio da classe so onde voc pode adicionar mais elementos. O Delphi no troca o que voc colocar em uma dessas sees. O que fica na seo private acessvel apenas na unidade atual, mas o que for declarado na seo public visvel externamente em outras unidades.

86

Com a palavra end, termina a definio da classe. Depois o Delphi acrescenta uma declarao de varivel para o formulrio. Essa declarao cria um formulrio baseado na classe definida antes:

Procedimentos na classe de formulrio


Vamos criar um mtodo para a classe desse formulrio, como um mtodo um procedimento criado dentro de um classe, podemos criar um procedimento na unit e declara-lo em uma das sees private ou public, por exemplo: procedure AbrirFormulario; E o corpo do procedimento, com os seus comandos, seria colocado na parte implementation, por exemplo: procedure TFormPrincipal.AbrirFormulario; begin Show; end; Quando definimos que um procedimento faz parte de uma determinada classe na criao do procedimento temos que especficar o nome da classe , como foi feito no exemplo anterior. No exemplo citado o procedimento no faz muita coisa til. Mas a vantagem principal de criar um procedimento como parte da classe de formulrio que ele pode acessar diretamente qualquer componente que faz parte do formulrio, sem indicar o nome do formulrio. Isso torna mais fcil manipular os componentes. Vamos abrir o projeto EVENTOS.DPR (Captulo 6), podemos verificar que no procedimento abaixo que utiliza a propriedade Cursor do formulrio, no foi necessrio especificar o nome do objeto que referencia a classe do formulrio criado, isso no foi necessrio porque o procedimento faz parte da classe do formulrio especifico. procedure TForm1.FormClick(Sender: TObject); begin if Cursor = crDefault then Cursor := crHourglass else Cursor := crDefault; end;

Variveis de Objeto
Uma varivel de objeto declarada utilizando o nome da classe como um tipo de dados, como j vimos: var btnCalendario: TButton; Edit1:TEdit; formPrincipal: TFormPrincipal; O contedo de uma varivel de objeto uma referncia a um objeto, internamente armazenada como o endereo de memria onde o objeto fica armazenado. Inicialmente o contedo da varivel lixo ou, no caso de uma varivel global, ela inicializada com o valor nil. Esse um valor especial que significa no caso "nenhum objeto". Se voc tentar usar uma varivel que contm nil, isso vai causar um erro de execuo. Voc pode inicializar a varivel, criando um objeto. Para isso, use o mtodo Create (o construtor da classe), com o nome da classe, por exemplo: lista := TStringList.Create; O construtor aloca um espao de memria para conter os dados do objeto e retorna o endereo dessa memria. Dependendo da classe, o construtor pode ter parmetros usados para inicializar o objeto. Algumas classes tm construtores com outros nomes ao invs de Create. Para liberar a memria usada pelo objeto, use o mtodo Free (definido na classe TObject e herdado por todas as classes). Se voc no liberar, o espao de memria do objeto continua alocado, mesmo que no existam mais variveis para acess-lo. Por exemplo, depois de terminar de usar uma string list, voc deve liberar a memria ocupada por ela: lista.Free;

87

Quando voc atribui uma varivel de objeto a outra, no feita uma cpia fsica do objeto. A nica coisa copiada a referncia ao objeto. Depois da atribuio, ambas as variveis referenciam o mesmo objeto, por exemplo: var btn: TButton; begin btn := btnDuplicar; btn.Caption := 'Duplicar de novo'; {afeta btnDuplicar indiretamente} ... end; Vamos criar um exemplo, que quando for clicado o mouse no formulrio, vamos criar componente TButton na posio do cursor. No formulrio, altere o nome para formCriaComp e o ttulo para "Criao de Componentes". Coloque dois componente Button , faa as seguintes alteraes: Button1 btnCriar Name Caption Criar Button2 btnDestruir Name Caption Destruir Vamos criar uma propriedade na classe de formulrio 'TformCriaComp', para isto basta criar uma varivel nesta classe, como iremos armazenar nesta varivel a quantidade de botes criados,esta varivel ser publica. Na classe de formulrio 'TformCriaComp' na parte public , acrescente: TForm1 = class(TForm) ....... private { Private declarations } public { Public declarations } QuantBotao:integer; end; No evento OnClick do boto "btnCriar", faa o seguinte: var botao : TButton; begin quantBotao := quantBotao + 1; botao := TButton.create(self); with botao do begin parent := self; caption := 'Boto' + inttostr(quantBotao); left : = 0; top := 0; visible := true; end; end; Antes de criar o Boto iremos adicionar o valor 1 a propriedade quantBotao. Quando voc cria um componente,usa o construtor Create da classe TComponent. Esse construtor exige como parmetro o formulrio onde o componente ser criado. No caso, passamos 'Self'(o formulrio atual), que o mesmo que 'FormCriaComp' nesse caso. O formulrio 'Self' ser o dono[owner] do componente.Mas no caso de um controle(componente visual) preciso dizer tambm quem ser o pai[parent] desse controle. Se for o prprio formulrio, o controle fica sobre o formulrio. Mas se houver outro controle que capaz de conter controles, o pai pode ser esse outro controle. Por Exemplo: O controle Panel, se colocar esse controle sendo o pai do Boto, este ser criado em cima do Panel. Quem determina o pai do componente a propriedade Parent. Depois a propriedade caption alterada para 'Boto' mais o contedo da propriedade quantBotao, e a posio do

88

componente(propriedades Top e Left) definida com o valor Zero.A propriedade Visible faz com que o componente aparea no formulrio. No evento OnClick do boto "btnDestruir", vamos destruir o boto criado, o mtodo utilizado para liberar a memria o Free. Ento acrescente: var botao :TButton; begin botao.free end; Execute o programa. Para testar clique no boto 'Criar'. A cada clique no boto ser criado um componente da classe TButton, mas quando for destruir o componente no ir funcionar , pois, a referencia que existia para os botes que foram criados anteriormente foram perdidas. Um dos problemas ocorre porque a varivel que contm a referncia do objeto da classe TButton local, existindo somente no procedimento que foi criada. Para solucionar este problema vamos criar a varivel botao sendo global, ento vamos retirar a declarao desta varivel nos procedimentos de eventos TCriaComp.btnCriarClick e TCriaComp.btnDestruirClick. E na seo implementation acrescente a declarao desta varivel. Implementation {$R *.DFM} var botao:TButton; Mesmo colocando esta varivel sendo global o problema ainda no foi resolvido , pois, o boto 'Criar' continua permitindo a criao de mais de um boto, com isso a varivel botao sempre ir conter a referncia para o ltimo boto criado. Vamos considerar que queremos criar somente um boto de cada vez, inicialmente o boto 'Destruir' vai aparecer desabilitado, porque no temos nenhum boto criado, ao criar iremos habilitar o boto 'Destruir' e desabilitar o boto 'Criar' e quando destruir o boto vamos desabitilitar o boto 'Destruir' e habilitar o boto 'Criar'. Na propriedade Enabled do boto 'Destruir' altere seu valor para false. No envento OnClick do boto 'Criar' acrescente o cdigo a seguir: btnDestruir.enabled := true; btnCriar.enabled = false; E no evento OnClick do boto 'Destruir' acrescente: btnDestruir.enabled := true; btnCriar.enabled = false; Vamos salvar o projeto como CRIACOMP.PAS e CRIACOMPP. Execute e teste o projeto.

89

Listas de Strings
O Delphi possui um tipo de objeto que til quando se trabalha com vetores de strings. So as chamadas listas de strings [string lists]. importante saber trabalhar com esse tipo de objeto, pois vrias propriedades de componentes so do tipo lista de strings, como a propriedade Items dos controles ListBox e ComboBox, a propriedade Lines de um controle Memo, entre outras. Vamos abrir o primeiro projeto criado, AULA1P. Nesse projeto, existe um componente ListBox chamado 'ListBox1' (o nome default). No cdigo do boto Adicionar, o programa faz o seguinte: ListBox1.Items.Add(Edit1.Text); Nesse cdigo, 'ListBox1.Items' uma string list, e nesse caso, est sendo utilizado o mtodo Add da string list, que adiciona um elemento. Como essa string list est associada a 'ListBox1', o item adicionado tambm aparece na lista.

Propriedades da String List


Voc pode usar a propriedade Strings, que um vetor, para acessar os elementos da lista (o ndice do vetor comea de zero), por exemplo: nome := ListBox1.Items.Strings[i]; ou simplesmente, omitindo o nome da propriedade, pode-se acessar a lista como um vetor: nome := ListBox1.Items[i]; A propriedade Count informa quantos elementos existem na lista, por exemplo: for i := 0 to ListBox1.Items.Count - 1 do Writeln(arquivo, ListBox1.Items[i]); A propriedade Sorted, quando True (verdadeiro), faz com que os elementos da lista sejam classificados automaticamente.

Mtodos da String List


O mtodo Add adiciona um elemento no final da lista ou na posio em ordem alfabtica, dependendo do valor de Sorted. Voc pode adicionar um elemento no meio da lista, usando Insert. Para remover um elemento, usa-se o mtodo Delete, informando a posio numrica. Para remover todos os elementos, basta usar o mtodo Clear. Alm disso, Move move um elemento para outra posio e Exchange troca dois elementos de lugar. Resumindo, os mtodos so usados da forma: Add(novoElemento); {adiciona} Insert(posio, novoElemento); {insere} Delete(posio); {exclui um elemento} {exclui todos} Clear; Move(posio-ant, posio{move} nova); Exchange(pos1, pos2); {troca os elementos} Para procurar um elemento na lista, usa-se IndexOf. Se o elemento no for encontrado, retorna -1. Por exemplo: pos := ListBox1.Items.IndexOf(Edit1.Text); if pos <> -1 then {achou...} No programa EDITORP, ns utilizamos dois mtodos que permitem salvar ou ler uma string list para um arquivo, que so LoadFromFile e SaveToFile. Por exemplo: memoEditor.Lines.LoadFromFile(dlgArquivo.FileName); Isso pode ser feito porque 'memoEditor.Lines' uma string list. De forma geral, esse mtodos so usados como: LoadFromFile(nomeArquivo); {carrega do arquivo} SaveToFile(nomeArquivo); {salva para o arquivo}

Criando String Lists Independentes

90

Voc tambm pode criar string lists independentemente de qualquer componente, declarando uma varivel do tipo TStringList, e usando o mtodo Create. Aps terminar de usar a string list, voc deve liberar a memria ocupada por ela com o mtodo Free: var lista: TStringList; begin lista := TStringList.Create; lista.Sorted := True; lista.Add('Curso'); lista.Add('Delphi'); lista.Delete(0); lista.Free; {libera memria} end;

Objetos Predefinidos
A biblioteca do Delphi contm vrios objetos predefinidos, que voc pode usar no programa sem precisar de declarar variveis para eles. Com esses objetos, voc pode utilizar funcionalidade adicional no seu programa.

O Objeto Application
O objeto Application representa a sua aplicao como um todo. Ele tem vrias propriedades e mtodos usadas internamente pelo Delphi, mas algumas delas so teis no seu prprio cdigo. A propriedade Title determina qual o ttulo que aparece no cone quando o programa minimizado. A propriedade ExeName (somente de leitura) permite voc consultar qual o nome do arquivo executvel do seu programa. Voc pode terminar a execuo do programa, em qualquer ponto, usando o mtodo Terminate. Quando voc passa muito tempo em um lao de processamento, o Delphi no tem uma oportunidade para verificar os eventos do usurio. Isso pode fazer o seu programa aparecer como se estivesse "travado" para o usurio. Para evitar isso, voc pode chamar o mtodo ProcessMessages do objeto Application, de tempos em tempos dentro do lao, o que d a oportunidade ao seu programa de processar os eventos: while not fim do begin ... Application.ProcessMessages; ... end;

O Objeto Clipboard
O objeto Clipboard representa a rea de transferncia [clipboard] do Windows, uma rea de memria usada para passar informaes entre programas. O clipboard pode ser usado para guardar texto ou imagens. Para ler ou colocar um texto no Clipboard, use a propriedade AsText, por exemplo: Clipboard.AsText := edit1.text; ... s := Clipboard.AsText; {se houver texto no clipboard, pega o valor desse texto} O mtodo Assign pode ser usado para copiar uma imagem para o Clipboard, a partir de um componente Image, por exemplo: Clipboard.Assign(image1.Picture); Para fazer o contrrio, voc pode trazer a imagem que est no Clipboard dentro de um componente Image, por exemplo: image1.Picture.Assign(Clipboard); Para saber se um determinado formato est disponvel, use o mtodo HasFormat, que retorna um valor do tipo boolean:

91

if Clipboard.HasFormat(CF_TEXT) then ... O parmetro de HasFormat pode ser: CF_TEXT para verificar se existe um texto, ou CF_BITMAP, CF_DIB, CF_IMAGE para verificar se existe uma imagem. Para usar o objeto Clipboard no programa, voc precisa acrescentar a unidade Clipbrd sua clusula uses.

O Objeto Screen
O objeto Screen representa a tela do computador e tem propriedades que permitem consultar a resoluo da tela, e saber qual o controle ou formulrio que tem o foco atualmente. As propriedades Width e Height contm, respectivamente, a largura e altura da tela em pixels. A propriedade PixelsPerInch um fator de converso, que diz quantos pixels existem em uma polegada. Com isso voc pode converter pixels em unidades fsicas e vice-versa. A propriedade Fonts um objeto TStringList que contm todos os nomes de fontes disponveis no Windows. Voc pode acessar o formulrio ativo (o que tem o foco de teclado) atravs da propriedade ActiveForm e o controle que tem o foco com a propriedade ActiveControl (do tipo TControl). A propriedade Cursor, se alterada, vai mudar o cursor do mouse de forma global para todos os formulrios. Voc pode tambm alterar o cursor para um formulrio individual, com a propriedade Cursor do formulrio.

Code Explorer
O code explorer aparece quando estamos editando uma Unit. Vamos abrir o projeto CRIACOMPP.DPR, e vamos no editor de codigo da Unit 'CriaComp', ir aparecer a seguinte janela:

O code Explorer o que parece do lado esquerdo desta janela, nele conseguimos visualizar quais so as constantes, variveis , uses e as classes utilizados na unidade que aparece no editor de cdigo. Vamos expandir cada item que aparece no code explorer e teremos o seguinte resultado:

92

Como a nica classe que foi definida dentro desta Unit 'TFormCriaComp', apareceu somento o nome dela. Nesta classe mostrado o que foi definido nas partes Public e Private. Na opo 'Variables/Constant' conseguimos obter todas as variveis globais que foram declaradas e em 'Uses' identificamos as units utilizadas.

Programao Orientada a Objetos


A programao orientada a objeto (POO) uma forma de programao que tenta construir os programas como colees de classes e objetos, relacionados entre si. Uma classe uma estrutura de dados, definida em tempo de projeto, que contm tambm os procedimentos que manipulam esses dados. Um objeto uma instncia de uma classe, criada em tempo de execuo, de acordo com a estrutura da classe e que pode ser manipulada com os mtodos da classe. A idia da POO criar o mnimo possvel de dependncias de uma parte do programa em relao outra. (As "partes" do programa so as classes e seus objetos). Com isso, uma parte pode ser alterada sem afetar as outras. Num programa orientado a objeto bem construdo, o efeito de uma alterao no cdigo menor e mais previsvel. Em outros tipos de programao, uma alterao no cdigo pode causar problemas, bugs, inconsistncias etc. em vrias partes do programa. Alm disso, a programao orientada a objeto facilita bastante a reutilizao de cdigo. Sem POO, possvel reutilizar cdigo, por exemplo, procedimentos e funes isolados, mas isso tem suas limitaes. Na POO, vrios conceitos so importantes: encapsulamento, herana e polimorfismo. Encapsulamento permite esconder membros de uma classe para evitar que outras classes alterem a estrutura interna do objeto. Por exemplo, um "cliente" da classe TConta no precisa saber como ela guarda as movimentaes da conta e no tem acesso para modificar essas informaes (e falsificar um extrato, por exemplo). Com o encapsulamento, voc garante que o objeto pode alterar sua representao interna sem afetar nenhuma outra classe. Ele s no pode alterar a sua interface, isto , o conjunto de mtodos e dados pblicos (por exemplo, Depositar(valor:double) e Retirar(valor:double)). O encapsulamento ento fora uma separao entre interface e implementao, onde a interface geralmente fixa ou muda pouco enquanto a implementao de uma classe tem total liberdade para mudar.

93

Herana permite criar uma classe derivada a partir de uma classe base. A classe derivada herda a implementao da base, reutilizando o cdigo que j existe, que j foi testado e aprovado. A classe derivada pode modificar ou estender o funcionamento de mtodos j existentes. Uma classe derivada herda tambm a mesma interface da classe base. Isso quer dizer que em qualquer lugar que possa ser usado um objeto da classe TBase, ele pode ser substitudo por um objeto da classe TDerivada (porque ele suporta os mesmos mtodos). Essa possibilidade, de substituir um objeto por um de outra classe derivada, chamado polimorfismo. Com o polimorfismo, um "cliente" de uma classe (procedimento que usa objetos da classe) pode ser escrito sem se preocupar com a subclasse especfica que ele vai manipular. Futuramente, se novas subclasses so criadas, com capacidades adicionais, o cliente no precisa nem mesmo saber que elas existem, mas pode us-las como objetos da classe TBase.Claro que ainda possvel criar programas mal-estruturados, confusos, e instveis com POO. Mas se voc entender corretamente os conceitos e aplicar da forma correta os recursos da linguagem, corre um risco menor de acontecer isso.

94

Captulo 12 Aplicaes de Banco de Dados


Termos Usados Desktop x Cliente / Servidor Formatos de Bancos de Dados Criando Tabelas Exemplo: Criando um Formulrio "Manualmente" Exemplo: Usando o Database Form Wizard Resumo dos Componentes de Dados Apelidos de Bancos de Dados

95

Termos Usados
Os sistemas de programao necessrios ao funcionamento de uma empresa precisam manter dados de forma permanente, e fornecer recursos para atualizar e pesquisar nesses dados. Os recursos de linguagem que permitem isso so chamados de acesso a bancos de dados. Um registro [record] um grupo de variveis com tipos de dados diferentes, que armazenam dados relacionados. Por exemplo, um registro pode conter os dados relativos a um produto vendido pela empresa, como descrio, cdigo de identificao, quantidade em estoque. Um campo [field] um dos itens de informao dentro do registro, como a descrio do produto. Uma tabela [table] no Delphi um conjunto de registros com a mesma estrutura, armazenados de forma permanente em disco. Uma tabela pode ser um arquivo fsico, mas no necessariamente, como veremos. Algumas documentaes se referem aos registros de uma tabela como linhas [rows] e aos campos como colunas [columns]. Um banco de dados [database] um conjunto de tabelas que contm dados relacionados. Por exemplo, um sistema de contas a pagar poderia ter um banco de dados de contas a pagar, com uma tabela para duplicatas, uma tabela para bancos etc. Geralmente sistemas pequenos ou mdios usam apenas um banco de dados contendo todos os dados. Um apelido [alias] no Delphi um nome que representa um banco de dados, independente de sua localizao. Isso permite mover os dados para outro local, sem alterar o programa. Existem vrios formatos de bancos de dados que podem ser acessados pelo Delphi. Dependendo do formato, um banco de dados pode ser fisicamente um subdiretrio do disco, ou um nico arquivo. Um ndice [index, plural 'indexes' ou 'indices'] um mecanismo que permite pesquisar rapidamente um registro em uma tabela, dado o valor de um determinado campo (ou alguns campos) da tabela. Durante a execuo, cada tabela possui um registro atual ou corrente [current record], cujos dados esto disponveis para o programa. Voc pode alterar a posio de registro atual, movimentando-se seqencialmente pelos registros, ou ento usando um ndice para procurar um registro. Um recurso extremamente poderoso do acesso a bancos de dados do Delphi a consulta [query], que permite obter todo um subconjunto da tabela ou de vrias tabelas, especificando as condies de seleo. Nota: Voc pode criar um registro no Object Pascal com uma estrutura do tipo record, e manipular um arquivo de registros. Mas esse tipo de acesso no tem muitos recursos, como a possiblidade de alterar a estrutura de um arquivo, ou excluir um registro, ou pesquisar um valor.

96

Desktop x Cliente/Servidor
Uma aplicao que utiliza bancos de dados composta de trs partes: Interface com o usurio: responsvel por validar as entradas do usurio, e iniciar pesquisas de acordo com um pedido do usurio. Mecanismo de acesso a banco de dados: [database engine]: responsvel pela manuteno das estruturas de dados necessrias em arquivos, pelos detalhes internos do acesso aos dados, e pela manuteno da integridade dos dados. Armazenamento de dados: arquivos que contm os dados em si. Num computador isolado, todos os trs componentes ficam no mesmo computador. J numa rede, que envolve no mnimo uma estao e um servidor, a configurao pode ser diferente. Um banco de dados "desktop" (ou baseado em arquivos) aquele no qual a interface com o usurio e o mecanismo de acesso ficam no mesmo computador (a estao) e apenas os arquivos dados ficam num servidor de rede. Operaes de consulta ou pesquisa devem passar atravs da rede. Por exemplo, quando um usurio quer ver uma relao de contas a pagar, mas apenas em determinado perodo, o sistema deve selecionar alguns registros baseado na data informada. No ambiente desktop, a estao traz todos os registros atravs da rede, mesmo os que no so utilizados. O trfego gerado na rede grande, principalmente quando vrias estaes acessam simultaneamente o servidor. J num banco de dados cliente/servidor, a interface com o usurio fica na estao e se comunica remotamente com o mecanismo de acesso, que um sistema gerenciador de banco de dados (SGBD) rodando no servidor. Quando o SGBD recebe um pedido para selecionar alguns dados, ele acessa localmente os dados no servidor e retorna apenas o resultado pedido. No caso de uma atualizao, no necessrio nem mesmo retornar um resultado, apenas informar que a atualizao foi feita. O diagrama abaixo resume as diferenas entre os ambientes: Desktop Cliente/Servidor

Bancos de dados desktop funcionam relativamente bem quando so poucos os dados a serem acessados, ou poucas consultas feitas simultaneamente, de forma que o trfego na rede seja pequeno. Em redes maiores, recomendvel utilizar o mecanismo cliente/servidor. No Delphi voc pode comear a desenvolver sua aplicao usando um banco de dados desktop e depois migrar para cliente/servidor, com poucas modificaes no programa, pois a forma de acesso atravs do programa praticamente a mesma. Nota: De acordo com a Borland, com menos que 12 usurios simultneos, um ambiente desktop pode fornecer um timo desempenho. Mas para mais usurios, recomenda-se um sistema cliente/servidor, como o InterBase ou SQL Server por exemplo. Ambientes c/s tambm so mais confiveis.

Formatos de Bancos de Dados


Todo o acesso a dados feito atravs do Borland Database Engine (BDE), (anteriormente chamado IDAPI), que embutido no prprio Delphi. O BDE permite acesso a alguns formatos

97

de dados "nativos", mas atravs de interfaces adicionais, permite acessar praticamente qualquer banco de dados padro de mercado. Em resumo, os formatos disponveis so os seguintes: Formatos Desktop: o BDE acessa "nativamente" vrios formatos de dados no padro desktop, como Paradox, dBase, Microsoft Access e FoxPro: Paradox: correspondem ao formato utilizado pelo Paradox, um banco de dados da Borland. Cada tabela tem um arquivo separado, com a extenso DB. dBASE/FoxPro: formatos semelhantes, com pequenas diferenas. Cada tabela um arquivo separado, com a extenso DBF. Access: usado pelo Access, da Microsoft. Cada banco de dados um nico arquivo .MDB, que contm vrias tabelas. InterBase: o InterBase um banco de dados da Borland que pode ser usado para desenvolver e testar aplicaes cliente/servidor. As edies Professional e Client/Server vm com uma verso reduzida do InterBase, chamado "InterBase Local", e com drivers que podem ser usados para acessar essa verso. A edio Client/Server vem com o InterBase para Windows NT, para ambientes cliente/servidor com at 4 usurios. O InterBase armazena o banco de dados inteiro, com todas suas tabelas, num nico arquivo de extenso GDB. SQL Links: na edio Client/Server, o Delphi inclui os drivers "SQL Link", para acesso nativo a vrios formatos de bancos de dados cliente/servidor, como: Oracle, Sybase SQL Server, Microsoft SQL Server, Informix, IBM DB/2 e InterBase. ODBC: permite utilizar drivers ODBC, que um padro definido pela Microsoft, mas utilizado por vrios fabricantes de bancos de dados. Atravs do ODBC voc pode utilizar outros bancos de dados que no so suportados das outras formas. ODBC pode ser usado a partir da edio Professional. O formato que voc vai utilizar depende de se voc est acessando um banco de dados j existente, que exige um determinado formato, ou se voc est criando o banco de dados a partir do incio. Neste ltimo caso, voc pode optar por um formato desktop ou cliente/servidor, dependendo do custo necessrio e do tamanho e quantidade de acessos previsto para os seus dados.

Criando Tabelas
Aps definir qual a estrutura que devem ter suas tabelas, voc deve criar fisicamente o seu banco de dados. Dependendo do formato de dados, voc pode utilizar um programa especfico do banco de dados ou usar um utilitrio fornecido juntamente com o Delphi o Database Desktop (DBD). Chame esse utilitrio a partir do Delphi, atravs de seu cone em: |Programas|Borland Delphi 4|Database Desktop.

Definindo um Diretrio de Trabalho


Antes de comear a criar tabelas, melhor definir um diretrio de trabalho, que o diretrio padro usado pelo DBD para criar os arquivos de dados. Voc pode salvar tabelas em qualquer diretrio, mas esta opo facilita o trabalho. Abra o menu File|Working Directory... e digite o diretrio onde sero colocados os arquivos do curso ("C:\CURSODF\TABELAS"). Clique Ok.

Definindo a Estrutura dos Campos


Para criar uma tabela, use File|New|Table.... Voc deve escolher qual o formato de dados a ser utilizado para a tabela (o padro "Paradox 7"). Clique Ok para aceitar o default. Agora dever aparecer a lista de campos a ser preenchida. No nosso caso, a tabela ter a seguinte estrutura: Campo Tipo Tamanho Chave CodCliente S (automtico) * Nome A 40 Telefone A 10 DataNasc D (automtico)

98

Digite o nome do campo "CodCliente" na coluna "Field Name" e tecle [Tab] ou a seta [ ] para mudar para a coluna "Type". Em tabelas Paradox, nomes de campos podem ter at 25 caracteres, e podem incluir letras, dgitos e espaos. (outros formatos de dados tm regras diferentes). Os tipos de dados em tabelas Paradox so representados por letras. Clique com o boto direito na coluna "Type" para escolher um tipo de dados ou digite diretamente a letra correspondente. Para esse campo, escolha o tipo "S" (short), que corresponde a um nmero inteiro binrio, com a mesma faixa de valores do tipo smallint do Object Pascal. O tamanho do campo determinado automaticamente, ento pule a coluna "Type". Em qualquer tipo de tabela, ndices pode ser usados para pesquisa ou ordenao de valores. Mas em tabelas Paradox, existem dois tipos de ndices. O ndice primrio [primary index] ou chave primria [primary key] determina um valor que deve ser nico para todos os registros da tabela, e tambm determina a ordem default em que os registros sero percorridos. Um ndice secundrio [secondary index] usado apenas para pesquisa e ordenao. A coluna "Key", se estiver marcada, diz que o campo parte da chave primria da tabela. (S os primeiros campos da tabela podem fazer parte da chave primria). No nosso caso, marque a coluna "Key" apenas para o campo "CodCliente". Faa isso com um duplo clique do mouse ou pressionando qualquer tecla. Tecle [ ] (seta para baixo) para definir os outros campos. Digite as caractersticas dos campos nas colunas apropriadas. Os campos "Nome" e "Telefone" so alfanumricos, isto , do tipo "Alpha". Note que eles exigem a definio do tamanho do campo, enquanto outros tipos como "Short" e "Date" no permitem uma determinao de tamanho, porque utilizam um tamanho automtico. O campo "DataNasc" do tipo "Date", que armazena datas. Note que o ano sempre armazenado com quatro dgitos, embora normalmente ele esteja configurado para mostrar apenas dois dgitos.

Salvando a Tabela
Para salvar a tabela, clique no boto "Save As...". Note que o DBD vai mostrar o diretrio de trabalho (definido anteriormente), mas tambm permite salvar em qualquer outro diretrio. Digite o nome "CLIENTE" e clique Ok. Como uma tabela Paradox, a extenso de arquivo ".DB" ser adicionada automaticamente, criando um arquivo CLIENTE.DB.

Entrando com Dados


Aps criar a tabela, voc pode entrar com alguns dados para teste no prprio Database Desktop. Para isso abra a tabela que voc criou com File|Open|Table..., selecionando CLIENTE.DB no diretrio. Voc vai ver a estrutura da tabela, mas ainda sem nenhum registro. Quando voc abre uma tabela, ela est em modo de visualizao, e no permite edio. Para editar os dados, , que vai colocar a tabela em modo de edio. O mesmo tecle [F9] ou clique no boto processo volta ao modo de visualizao. Digite alguns dados de teste para preencher a tabela. Use as setas, ou [Tab] e [Shift+Tab] para mudar de campos e a seta [ ] para incluir um novo registro. Como o campo "CodCliente" a chave primria, voc no pode incluir dois registros que tenham o mesmo valor desse campo. Os registros sempre sero mantidos na ordem desse campo. Para acrescentar um registro no meio, use a tecla [Ins]. Para excluir um registro, use [Ctrl+Del]. Tecle [F2] ou clique no boto quando quiser editar um campo seno, quando voc comear a digitar, o contedo anterior perdido. Note como o campo DataNasc automaticamente validado, e no permite datas invlidas como "32/04/97", "29/02/97" (1997 no bissexto). Ele lido e mostrado no formato "dia/ms/ano", se a configurao do Windows estiver com esse formato. Nota: o Windows armazena uma configurao padro para formato de datas, horas, nmeros etc., que usada por todos os programas. Ela pode ser alterada atravs do Painel de Controle, cone "Configuraes Regionais".

99

100

Exemplo: Usando o Database Form Wizard


A forma mais rpida de criar um programa que acessa bancos de dados em Delphi utilizando o Database Form Wizard [assistente de formulrio de banco de dados]. Com essa ferramenta, no preciso programao nem mesmo criao de componentes, basta especificar qual a tabela a ser acessada e ele cria um formulrio contendo tudo que preciso. O que feito pelo Database Form Wizard (DFW) o que fizemos manualmente no "Cadastro de Cliente", e voc pode personalizar o formulrio criado da forma que voc quiser. Mas na maioria das vezes, ele facilita o trabalho inicial.

Criando um campo autoincremento


Quando definimos um campo sendo autoincremento, a coluna que foi definida com este tipo tem um nico valor que gerado automaticamente pelo sistema. O contedo desta coluna ,conseguimos obter somente quando o registro for gravado. Outro detalhe que no podemos informar seu contedo durante uma alterao ou incluso de dados. Como exemplo vamos criar a tabela de produto. Para criar uma nova tabela no Database Desktop , no menu File|New|Table... e digite os campos como abaixo: Campo Tipo Tamanho Chave CodProduto + * Nome A 40 QtdEstoque S PrecoVenda N CodForncedor S No Paradox o que identifica um campo sendo autoincremento o tipo sendo + (AutoIncrement) . Podemos ter somente um coluna com esse tipo na tabela. Note que o campo PrecoVenda vai usar o tipo N (Number). Esse tipo equivale ao tipo double do Object Pascal, isto , permite armazenar nmeros inteiros bem como nmeros com parte fracionria.

Criando um Formulrio para Acessar a Tabela com Form Wizard


Crie um novo projeto no Delphi e depois acione o item de menu Database| Form Wizard.... O DFW dividido em vrias telas de informaes. A primeira tela oferece dois grupos de opes:

Mantenha as opes padro: "Create a simple form" em "Form Options" indica que vamos criar um formulrio "simples", que acessa uma nica tabela e "Create a form using TTable objects" em "DataSet Options" indica o tipo de componente de acesso a dados utilizado. Veremos as outras alternativas mais tarde. Clique em "Next". Agora voc deve selecionar a tabela a ser utilizada. Selecione PRODUTO.DB, que foi criada anteriormente e clique em Next. Na prxima tela, voc pode

101

escolher apenas alguns campos ou todos os campos da tabela para utilizar no formulrio. Para selecionar todos os campos, clique no boto [>>] e depois em Next. Voc pode escolher um lay-out para o formulrio. Escolha o padro "Horizontally" (Horizontal) e clique em Next. A ltima tela tem uma opo "Generate a main form" [gerar um formulrio principal]. Se ela estiver marcada, o novo formulrio ser o principal do projeto. Deixe essa opo marcada, e clique no boto "Finish".

Testando o Programa
Note que o formulrio gerado tem vrios componentes j posicionados, incluindo controles de dados para cada campo da tabela. Cada controle de dados responsvel por ler e gravar os dados de um campo. Voc pode alterar a posio e o tamanho do formulrio como quiser. Altere o Caption do formulrio para "Cadastro de Produto" e a propriedade Name para formCadProduto. Note que para alterar uma propriedade do formulrio voc deve selecionar o formulrio. Se um componente estiver selecionado, tecle [Esc] at no aparecer nenhuma indicao de seleo. O que o DFW faz quando cria um novo formulrio o mesmo processo que fizemos para criar o formulrio manualmente. Vamos alterar a propriedade Name do componente table para 'tblProduto', os componentes que tiverem alguma propriedade associada com o componente Table o Delphi automaticamente muda o nome tambm , o nome s no mudado em linhas de cdigo . No componente DataSource colocar o nome sendo 'dsProduto', como o nome do componente Table foi mudado precisamos tambm alterar um trecho de cdigo no formulrio que abre a tabela (no exemplo anterior usamos a propriedade Active). Selecione o formulrio (tecle [Esc] algumas vezes se houver algum componente selecionado) e, no Object Inspector, clique na pgina de eventos. Clique duas vezes no valor do evento OnCreate, e ir aparecer um procedimento de evento contendo: Table1.Open; Altere esse comando para: tblProduto.Open;

Salvando o Projeto
Antes de salvar o projeto, devemos remover o formulrio inicial, que no tem funo nenhuma. Isso preciso porque o Database Form Wizard cria um novo formulrio, mas no altera os anteriores. Clique em Project|Remove from project..., selecione Form1 e clique OK. Agora salve o projeto, dando os nomes de CADPRODUTO e CADPRODUTOP. Execute o projeto e cadastre alguns produtos.

Resumo dos Componentes de Dados


Neste captulo fizemos alguns projetos que utilizam os componentes de acesso a dados e os controles de dados do Delphi. De forma geral, o fluxo dos dados nesse tipo de programa :

Os componentes de acesso a dados, como o componente Table, lem e gravam no banco de dados. O componente DataSource faz a ligao entre estes componentes e os controles de dados, como o DBEdit.

102

Apelidos de Bancos de Dados


Quando voc desenvolve uma aplicao de banco de dados, voc deve especificar o diretrio onde estaro os seus dados (se for um banco de dados local) atravs da propriedade DatabaseName de um componente Table. Mas com isso o programa fica dependente do local onde esto armazenados os dados. Se voc mover as tabelas para outro diretrio, o programa no vai mais funcionar como antes. Para resolver esse problema, existem os alias do BDE. Um alias, ou apelido, um nome que pode ser usado nos programas em lugar de especificar o diretrio. Num banco de dados cliente/servidor, um alias tambm a forma mais usada para acesso aos dados, porque ele guarda tambm outros parmetros de configurao. Os apelidos so armazenados em um arquivo de configurao do BDE e so globais a todas as aplicaes em Delphi. Voc pode criar ou alterar apelidos usando o utilitrio Database Desktop (DBD), atravs do comando Tools|Alias Manager, mas mais fcil usar um utilitrio que faz parte do prprio Delphi, o Database Explorer. Para isso clique em Database|Explore no menu do Delphi. Voc ver uma tela como a seguinte:

O Database Explorer mostra do lado esquerdo, na pgina "Databases", uma rvore contendo os apelidos que j foram definidos. Ele permite tambm visualizar e alterar os dados de qualquer tabela, atravs de um apelido. Para criar um novo alias, clique em Object|New... Voc deve escolher o tipo de banco de dados que ser usado. Os tipos disponveis dependem de quais drivers esto instalados no computador. No nosso caso, deixe selecionado o tipo STANDARD (acesso a Paradox e dBase), que o padro. Clique Ok e o novo alias aparece na lista, com o nome provisrio de "STANDARD1". Digite "CursoDelphi" para o alias. Note que um tringulo aparece esquerda do nome, que indica que esse nome ainda no foi salvo na configurao:

103

Do lado direito, esto os parmetros de configurao do alias. O nico parmetro que importa no caso o PATH. Clique neste e digite "C:\CURSODF\TABELAS" (o diretrio onde esto os arquivos do curso). Agora clique no boto (Apply) para salvar as alteraes. Se voc quiser ver as tabelas que esto neste alias, clique no sinal de [+] ao lado do nome para abrir o alias, depois abra o cone "Tables" e voc ver as tabelas definidas. Ao clicar em uma delas, por exemplo, CLIENTE.DB, voc pode visualizar informaes gerais sobre a tabela, ou visualizar e alterar os dados, clicando na pgina "Data":

Note que aparecem botes de controle na parte superior, semelhantes ao DBNavigator. Para fechar a conexo com o alias, clique em CursoDelphi e no boto (Open Close). Agora feche o Database Explorer (ou SQL Explorer) e retorne ao Delphi. Abra um dos projetos anteriores, como o projeto CADCLIENTeP. No componente Table, primeiro altere a propriedade Active para False. Depois selecione a propriedade DatabaseName, abra a lista de valores e selecione "CursoDelphi" e altere novamente a propriedade Active para True. Faa a mesma alterao para o projeto CADPRODUTOP. A lista de valores na propriedade DatabaseName, sempre mostra quais so os aliases cadastrados. O programa vai mostrar os mesmos dados que antes, mas agora ele no mais dependente do diretrio "C:\CURSODF\TABELAS". Se voc quiser mover os dados para outro lugar, basta alterar o alias novamente, usando o Database Explorer ou o Database Desktop.

104

Captulo 13 Recursos Adicionais


Definindo Tabelas Criando o Menu Principal Alterando o Formulrio Principal Usando o Controle DBGrid

105

Definindo Tabelas
Durante o curso, iremos desenvolver um mini-sistema de controle de vendas, no qual teremos um cadastro de clientes, um controle das vendas efetuadas para cada cliente e de itens vendidos para cada venda. Isso vai envolver vrias tabelas adicionais no nosso banco de dados. O modelo abaixo mostra como esto relacionadas as tabelas que sero utilizadas no nosso exemplo:

Volte ao Database Desktop para definir tabelas adicionais e alterar a estrutura da tabela de cliente, criada anteriormente.

Reestruturando a Tabela "Cliente"


Aps criar uma tabela, voc sempre pode alterar a estrutura desta, acrescentando novos campos, removendo campos existentes ou alterando o tipo de um campo. Os dados anteriores so preservados, sempre que possvel, mas obviamente, se voc reduzir o tamanho de um campo, ou mudar seu tipo para uma faixa de valores menor, voc pode perder parte dos dados. Para reestruturar a tabela, use Table|Restructure Table.... A mesma janela com a estrutura dos campos aparece. Vamos adicionar um campo no meio da estrutura, entre Nome e Telefone. Para isso, clique no campo Telefone e pressione [Insert]. Digite "CPF" no nome do campo, "A" para o tipo e 11 para o tamanho. Agora adicione dois campos no final: clique no campo DataNasc, pressione a seta para baixo e digite os novos campos: "Cidade", "A", 25 e "Estado", "A", 2. A estrutura da tabela agora a seguinte: Nome do Campo Tipo Tamanho Chave CodCliente S (automtico) * Nome A 40 CPF A 11 Telefone A 10 DataNasc D (automtico) Cidade A 20 Estado A 2

106

Criando um ndice Secundrio


Antes de salvar a tabela modificada, para facilitar as pesquisas e ordenaes por nome, vamos criar um ndice secundrio para o campo Nome. Clique na lista direita, abaixo de "Table Properties", e escolha a opo "Secondary Indexes". Agora o boto "Define..." estar ativo. Clique nesse boto para ver a janela de definio de ndices. Na lista da esquerda esto todos os campos da tabela. Para definir que o campo "Nome" far parte do ndice, selecione-o e clique na seta para a direita. No quadro "Index Options", abaixo da lista de campos, existem opes que voc pode alterar. A opo "Maintained" faz com que o ndice seja mantido automaticamente a cada alterao, que o mais usado. Se estiver desabilitada, o ndice s atualizado quando voc tentar fazer uma pesquisa, o que toma certo tempo. A opo "Case sensitive" s tem efeito em campos alfanumricos. Se habilitada, as pesquisas no ndice fazem diferena entre maisculas e minsculas. Agora clique em OK para salvar o ndice. O Database Desktop vai pedir um nome para o ndice. O nome segue as mesmas regras de nomes de campos. Nesse caso, coloque o nome de "IndNome". Mais tarde veremos como utilizar um ndice secundrio no programa. Para salvar a tabela modificada, clique no boto "Save". Se quiser, entre com dados para o campo CPF nos registros. Nota: voc tambm pode criar um ndice que utiliza vrios campos da tabela. Basta adicionar todos os campos utilizados lista da direita.

Criando a Tabela "Venda"


Vamos criar agora a tabela de vendas. Para criar uma nova tabela no DBD, faa como antes, usando File|New|Table... e digite os campos como abaixo: Campo Tipo Tamanho Chave CodVenda S * CodCliente S DataVenda O campo "CodVenda" a chave primria da tabela, que identifica um registro de venda. O campo "CodCliente" est relacionado com um registro da tabela "Cliente", indicando que esta venda se refere quele cliente. Clique em "Save As..." para salvar a tabela e digite o nome "VENDA".

Criando Integridade Referencial


Vamos alterar a estrutura da tabela "Venda". Como o campo "CodCliente" nesta tabela est relacionado com um registro da tabela "Cliente" , no podemos deixar que neste campo seja colocado cdigo do cliente que no exista na tabela "Cliente" e at mesmo ao excluir um cliente no pode ser permitido excluir um cliente que tenha venda , a no ser que exclua as vendas ,para depois excluir o cliente desejado (chamamos este processo de excluso por cascata). Ento na tabela "Venda" vamos alterar sua estrutura criando "Integridade Referencial" na coluna 'CodCliente' com a tabela "Cliente" , para isto clique na lista "Table Properties", escolha a opo "Referential Integrity" e clique no boto "Define...". Selecione o campo "CodCliente" na lista da esquerda, e clique na seta para mov-lo para a direita. Clique em OK para salvar o ndice e d o nome de "IntCliente". Iremos criar integridade referencial somente nesta tabela, a ttulo de demonstrao. Notas: Utilizar integridade referencial no Paradox, no muito seguro, pois, ao colocar o programa para funcionar principalmente em rede ocorre problemas do tipo "Arquivo Corrompido" ou "ndice Fora de Data". Com banco de dados Client/Server utilizar a integridade referencial bem mais seguro. No caso do Paradox uma sada seria tratar a integridade pelo Delphi. Clique em "Save ..." para salvar a tabela "VENDA".

Criando a Tabela de Itens


No DBD, use File|New|Table... como antes e defina a seguinte estrutura para a tabela:

107

Campo CodVenda CodProduto Quantidade

Tipo S S S

Chave * *

Defina tambm um ndice secundrio no campo CodVenda. Isso necessrio para que o Delphi possa tratar o relacionamento mais tarde. Para definir um ndice secundrio, faa como antes: selecione "Secondary Indexes", clique no boto "Define...", selecione o campo CodVenda e clique Ok. D o nome de "IndVenda" para o ndice e clique Ok. Salve a tabela com o boto "Save as...", dando o nome de ITEM.db (lembre-se que a extenso no precisa ser digitada). Depois feche o DBD e retorne ao Delphi. Nota: nomes de tabelas podem ter at 253 caracteres (fora extenso), mas melhor usar um nome com oito ou menos caracteres para manter compatiblidade com programas mais antigos.

Criando a tabela Fornecedores


No DBD, use File|New|Table... como antes e defina a seguinte estrutura para a tabela: Campo Tipo Tamanho Chave CodFornecedor S * Nome A 60 Defina tambm um ndice secundrio no campo 'Nome' . Para definir um ndice secundrio, faa como antes: selecione "Secondary Indexes", clique no boto "Define...", selecione o campo 'Nome' e clique Ok. D o nome de "IndNome" para o ndice e clique Ok. Salve a tabela com o boto "Save as...", dando o nome de "FORNECEDOR.DB".

108

Criando o Menu Principal


Vamos criar um programa onde utilizaremos os formulrios criados anteriormente, alm de alguns novos. Crie um novo projeto no Delphi. O formulrio criado durante a criao do projeto ser o formulrio principal , este formulrio ser a janela a partir da qual o usurio acessa as outras janelas do programa.

O MenuDesigner: criando menus


Para utilizar um menu em um programa, precisamos inserir um componente MainMenu no formulrio. Ele o primeiro da pgina Standard: . Aps coloc-lo no formulrio, clique duas vezes nele para abrir o Menu Designer, que tem uma aparncia como a seguinte:

O Menu Designer mostra uma simulao do menu e permite voc criar os itens de menu que voc vai utilizar. medida que voc criar itens de menu, o Object Inspector vai mostrar as propriedades do item selecionado. Para criar o primeiro item, simplesmente digite "Cadastro" (sem as aspas) e tecle [Enter]. O Menu Designer vai mudar para a seguinte aparncia:

direita e abaixo do item, sempre ficam disponveis retngulos vazios que voc pode preencher para criar novos itens. Se voc no os preencher, eles no vo aparecer no menu final. Agora digite o texto do prximo item: "Cliente" e tecle [Enter]. O marcador vai passar para a prxima linha. Crie mais um item "Produto". Agora crie o item "Fornecedor". Em seguida crie uma barra separadora no prximo item. Para criar uma barra separadora, digite "-" (um sinal de menos). Depois da barra, crie um item "Venda", crie novamente uma barra separadora e finalmente crie mais um item "Sair". A aparncia final vai ficar como na figura:

109

Quando voc digita o texto do menu, voc est alterando a propriedade Caption de cada item de menu. O Object Inspector automaticamente altera a propriedade Name de cada item para ser igual ao valor do Caption, com um nmero acrescentado ao final (por exemplo, Cadastro1). Ns vamos mudar esses nomes para definir um padro mais descritivo. Clique no item "Cadastro" e na propriedade Name, troque "Cadastro1" (o nome que o Delphi colocou automaticamente), por "menuCadastro". Faa de forma semelhante para os outros itens, de acordo com a tabela: Cliente menuCadClientes Produto menuCadProdutos Fornecedor menuCadFornecedores N!(separador) Venda menuCadVendas N2(separador) Sair menuCadSair Agora clique no item vazio direita do item Arquivo e digite "Editar". Abaixo desse item, crie subitens de acordo com a figura:

A propriedade name altere de acordo com a tabela abaixo: Consultas menuConsultas Cliente por Estado menuconCliEstado Vendas por Cliente menuConVendasTotais

110

Nota: O Menu Designer tem outras facilidades tambm. Para inserir um item de menu no meio, pressione a tecla [Ins]. Para excluir um item de menu, use o [Ctrl+Del]. Para definir um nvel adicional de submenu, use [Ctrl+seta para direita].

Tratando Eventos de Menus


Feche a janela do Menu Designer e retorne ao formulrio "real". O menu vai estar inserido no formulrio, exatamente com a aparncia que foi definida que ele ir aparecer para o usurio, mas no permite modificao. Voc pode clicar nos menus "Arquivo" ou "Editar" para ver os seus subitens. Se voc executar o programa, tambm pode clicar os subitens no vo fazer nada, pois ainda no fizemos nenhum tratamento de eventos. Para tratar eventos em um sub-item de um menu, basta abrir o menu e clicar no sub-item (no formulrio, mas no no Menu Designer). Clique no menu "Cadastro" e depois no item "Sair". O Delphi vai abrir um procedimento de evento para esse item: procedure TForm1.menuCadSairClick(Sender:TObject); begin end; Esse item deve terminar o programa quando clicado. Para isso, basta fechar o formulrio, utilizando um comando (na verdade, um mtodo) chamado Close: Close; O mtodo Close fecha o formulrio e, como o nico formulrio do programa, ele finaliza a execuo. Execute o programa e clique em Arquivo|Sair. O programa dever finalizar e retornar ao modo de projeto. Acrescente no Menu Designer o item de menu abaixo Crie a seguinte estrutura de menus: Relatrio menuRelatorios Clientes menuRelClientes Vendas por Produto menuRelVendasProduto

Teclas de Acesso e Teclas de Atalho


Apesar do Windows geralmente ser mais fcil de usar com o mouse, bom ter em mente que um programa Windows tambm deve ser fcil de usar apenas com o teclado, sem utilizar o mouse. Isso entre outras coisas, envolve uma forma de selecionar menus atravs do teclado. O Windows j fornece automaticamente uma interface padronizada de teclado para os menus. Para verificar isso durante a execuo do programa, pressione a tecla [F10]. Agora voc pode usar as teclas [ ] e [ ] para mudar entre os itens na barra de menu e [Enter] para abrir um menu. Quando o menu est aberto, as teclas [ ] e [ ] so usadas para movimentao entre os itens do menu, [Enter] para acionar o item selecionado, ou [Esc] para fechar o menu aberto. Alm dessa facilidade, voc pode definir uma tecla de acesso para cada menu e cada item dentro de um menu. Uma tecla de acesso aparece como uma letra sublinhada no texto do menu. Para um menu da barra principal, o usurio pode abrir o menu pressionando [Alt+letra], onde letra a tecla de acesso. Quando o menu est aberto, um item do menu pode ser acionado pressionando-se sua tecla de acesso (sem usar [Alt]). Clique duas vezes no componente (MainMenu) no formulrio para chamar o Menu Designer. Clique no menu "Cadastro" e na propriedade Caption. Para inserir uma tecla de acesso no 'C', digite &Cadastro. Faa de forma semelhante para todos os outros itens (no altere as barras separadoras): Item &Clientes &Vendas &Produtos Tecla de Acesso &C &V &P

111

&Fornecedores &Sair C&onsultas Clientes por &Estado &Vendas por Cliente &Relatrio &Clientes &Vendas por Produto

&F &S &O &E &V &R &C &V

Agora, o item Cadastro|Cliente, por exemplo, pode ser acionado com as teclas [Alt+C,C]. Outra forma de acionar itens de menu atravs de teclas de atalho [shortcut keys]. A diferena que teclas de atalho podem ser usadas mesmo quando o menu no est aberto, esteja onde estiver o foco de teclado, e no precisam ser letras. Se voc abrir um menu do Delphi, ver que teclas de atalho aparecem direita do item, como [Ctrl+S], [F5], [Ctrl+F7] etc. S itens de menu podem ter teclas de atalho (no os menus da barra principal). Ainda no Menu Designer, clique no item "Clientes" e na propriedade Shortcut [atalho]. Selecione da lista a opo "Ctrl+K". Para "Vendas...", coloque "Ctrl+E".Para "Produtos" , coloque "Ctrl+P". Note tambm que o item Sair no tem uma tecla de atalho. Isso porque j existe um atalho definido pelo Windows para sair de um programa qualquer: [Alt+F4]. De forma geral, bom tentar economizar teclas de atalho, e s colocar essas teclas nos itens mais utilizados do programa. Se voc tem muitas teclas de atalho, o usurio no conseguir memoriz-las, e isso desvia do propsito original desse tipo de acesso. Nota:Voc no deve repetir a mesma tecla em um grupo de itens do mesmo nvel. O Delphi permite fazer isso, mas a tecla no vai funcionar da forma esperada. J itens em menus diferentes podem usar a mesma tecla sem problemas. Nota: Teclas de atalho devem ser nicas entre todos os itens de menu. Execute o programa e teste as teclas. Voc no precisa abrir um menu para acionar a tecla correspondente a um item. Note que nos itens separadores, o Delphi coloca momes padro(N1 e N2), que voc no precisa alterar. A propriedade ShortCut fornece um acesso rpido pelo teclado em alguns itens.

Alterando o Menu Principal


Alterando Propriedades
Reduza o tamanho do formulrio na vertical, ou a propriedade Height, de forma que ele no ocupe espao na tela, deixando apenas a barra de menu visvel. Crie um procedimento para o evento OnCreate , e coloque os cdigos abaixo: left := 0; top := 0; A barra de menu ir ficar posicionada no topo do DeskTop. Altere o Name do formulrio para 'FormPrincipal'. Num projeto grande, importante dar nomes distintos aos vrios formulrios. Altere sua propriedade Caption para "Controle de Estoque". Salve o projeto e chame a unidade do formulrio principal de VENDPRIN.PAS e o projeto de VENDAS.DPR.

Acrescentando os formulrios anteriores


Neste projeto iremos acrescentar os formulrios criados anteriormente. Para cada um dos fomulrios, voc deve clicar no cone (Add File to Project). Adicione as unidades CADCLIENTE.PAS e CADPRODUTO.PAS.

Associando os formulrios aos itens de menu

112

O formulrio principal, que contm os itens de menu, ir chamar cada um dos formulrios criados. Para que ele possa fazer isso, a unidade principal deve ter uma clusula uses, com os nomes de todas as unidades. Fique posicionado na unit "VendPrin" . nessa unidade logo aps a palavra implementation, acrescente: uses CadCliente, CadProduto; Agora tecle [F12] para voltar ao formulrio. Clique no item de menu Cadastro|Clientes e, no procedimento de evento, coloque o seguinte comando: formCadCliente.Show; Iremos fazer a mesma coisa para o Produto. Clique no item de menu Cadastro|Produto e , no procedimento de evento, coloque : formCadProduto.Show; Salve o projeto e depois execute o programa.Note que no incio da execuo, aparece apenas o formulrio principal. Ao clicar em um item de menu, por exemplo Cadastro|Clientes, aparece o formulrio correspondente. Voc pode clicar novamente no formulrio principal e abrir outro formulrio. Como os formulrios no so modais, vrios formulrios podem estar na tela ativos simultaneamente.

Usando o Controle DBGrid


Alm de usar os controles de dados, para mostrar um formulrio da forma "tradicional", usando um controle para cada campo, voc pode usar um controle DBGrid, que permite visualizar vrios registros ao mesmo tempo.

Criando os Componentes de Dados


Vamos criar um novo formulrio e utilizar a mesma tabela de clientes, mas com um componente DBGrid. Para criar um formulrio ir no menu File|New Form . Selecione a pgina Data Access e coloque no formulrio um componente Table e um componente DataSource. Defina suas propriedades como antes: Table Name: tblCliente DatabaseName: CursoDelphi TableName: CLIENTE.DB DataSource Name: dsCliente DataSet: tblCliente Note que em DatabaseName estamos usando o alias definido anteriormente, "CursoDelphi", que pode ser escolhido na lista de valores. De agora em diante, usaremos esse nome para fazer referncia ao diretrio. Agora abra a pgina Data Controls e selecione o cone (DBGrid). Coloque o componente no formulrio e altere sua propriedade DataSource para "dsCliente". Agora volte ao componente Table e altere sua propriedade Active para True. A grade de dados j vai mostrar os dados da tabela e voc pode usar as barras de rolagem para ver mais registros. Altere a propriedade Align do DBGrid para "alClient", desta forma o DBGrid ir preencher todo o formulrio. Altere tambm a propriedade Name do formulrio para "formConsClienteEstado".

Manipulando dados no DBGrid


Para verificar o funcionamente do DBGrid , temos que no menu principal chamar o formulrio. Posicione no formulrio da Unit VendPrin , no clique no menu Consultas|Clientes por Estado e coloque o comando a seguir: procedure TformPrincipal.menuConCliEstadoClick(Sender: TObject);

113

begin formConsClienteEstado.show; end; Salvar esta unit como CONSCLIENTEESTADO. Acrescente na unit VendPrin na seo implementation, uma uses para a unit ConsClienteEstado. Ficando desta forma: uses CadCliente, CadProduto, ConsClienteEstado; Execute o programa, clique no menu Consultas|Clientes por Estado e verifique o funcionamento do DBGrid, que bem semelhante a uma grade de dados do Database Desktop. Voc pode usar as setas para mover entre campos (linhas) e registros (colunas). Quando voc tenta sair de um campo, se voc digitou um dado invlido, imediatamente ver uma mensagem de erro (por exemplo, no campo DataNasc). Quando voc sai de uma linha, os dados do registro so imediatamente gravados. Para alterar um campo, editando o valor existente, pressione [F2]. Para inserir um registro, voc pode descer abaixo do ltimo registro, ou teclar [Insert]. Para excluir um registro, tecle [Ctrl+Del]. Nota: voc tambm pode alterar caractersticas das colunas se voc clicar duas vezes no prprio DBGrid. Essas alteraes tm prioridade sobre as propriedades dos campos da tabela e voc tem outras opes como, por exemplo, mudar a cor do campo. Mas geralmente no necessrio alterar opes no prprio DBGrid.

Usando o Editor de Campos


Vamos posicionar na unit "CadCliente.pas", caso esteja na unit pressione a tecla [F12] para mostrar o fomulrio.At agora utilizamos os objetos de campos para criar os controles de dados, mas ele tem outras finalidades tambm colocar mscara para a edio de determinados campos. Quando voc utiliza o componente Table, ele cria internamente, para cada campo da tabela, um objeto TField correspondente, que tem propriedades para definir a formatao do campo, tamanho com o qual ele aparece na tela etc. Se voc quiser alterar as propriedades dos campos em tempo de projeto, voc precisa criar uma lista persistente de objetos, e isto feito no editor de campos. A estrutura da tabela "Cliente" foi alterada , foi acrescentado alguns campos que ainda no foram adicionados ao editor de campos. Clique duas vezes no componente 'tblCliente' no formulrio para abrir o editor de campos. Quando a lista de campos est vazia, significa que todos os campos tero as propriedades default. Para adicionar os objetos de campo que esto faltando, clique com o boto direito no fundo e clique em "Add fields...", ser mostrado somente os campos que foram acrescentados a tabela , como todos os campos esto selecionados clique em Ok para adicion-los. Agora quando voc clicar em um dos campos na lista, as propriedades do campo (do objeto TField) aparecem no Object Inspector. No editoe de campos clique em "DataNasc" vamos mudar o formato de data que usado para mostrar as datas. Altere a propriedade DisplayFormat, colocando o valor "dd/mm/yyyy".

Alterando a Mscara de Edio


Cada campo pode ter tambm uma mscara de edio, que define alguns caracteres que aparecem no campo, mas que o usurio no precisa digitar. No nosso caso, vamos colocar uma mscara no campo CPF. No editor de campos, clique no campo CPF. No Object Inspector, clique na propriedade EditMask. Para alterar a mscara de edio, voc pode digitar um valor diretamente para essa propriedade, mas mais fcil usar o editor especializado. Clique duas vezes no valor ou uma vez no boto de reticncias. Na mscara de edio, digite: 999.999.999-99. Cada nove na mscara corresponde a uma posio digitada pelo usurio, que s permite nmeros, mas os outros caracteres sempre aparecero na mscara, e o usurio no precisa digitar. importante tambm desmarcar o quadro "Save literal characters". Se esse quadro estiver marcado, os pontos e traos da mscara sero includos no campo, quando ele for gravado. Se ele ficar desmarcado, s os caracteres digitados sero includos no campo. Note que quando voc altera essa opo, um 0 ou 1 adicionado ao final da mscara.

114

A opo "Character for blanks" define qual o caractere que ser usado nos espaos vazios durante a digitao. Geralmente melhor manter o padro, '_' (sublinhado). Quando voc altera essa opo, o caractere adicionado ao final da mscara. Para testar a mscara, na mesma janela voc pode digitar alguma coisa em Test Input. Se voc digitar e no conseguir sair do campo (o Delphi vai mostrar uma mensagem), tecle [Esc] e tente novamente. Vamos definir uma mscara para edio no campo "DataNasc". Ento no editor de campos, clique no campo "DataNasc". No Object Inspector, clique na propriedade EditMask , em "Sample Masks" clique na opo "date" , esta opo contm uma mscara para data. O contedo de "Input Mask" ser '!99/99/00;1;_', substitua o '0' por '9', a diferena de utilizar 0 ou 9 que quando colocamos '0' fazendo parte da mscara, quer dizer que naquele local o usurio obrigado a informar algum nmero, se utilizar '9' aceita somente nmeros, mas no obirgatrio. importante que a opo "Save literal characters" esteja marcada , pois, as barras so gravadas no campo.

115

Captulo 14 Validao e Pesquisas


Exemplo: Cliente por Estado Exemplo: Clientes - Alterando Validao de Campos e Registros Tratamento de Excees Pesquisas na Tabela Blocos Protegidos Usando Outros Controles de Dados

116

Exemplo: Cliente por Estado


Iremos realizar algumas alteraes no formulrio "formConsClienteEstado", portanto , abra este formulrio.Atualmente este formulrio mostra todos os clientes cadastrados, vamos realizar uma procura onde iremos mostrar os Clientes por um determinado Estado escolhido pelo usurio. Altere a propriedade Caption para 'Cliente por Estado' e modifique tambm a propriedade Align do DBGrid para 'alBottom' e aumente o tamanho do fomulrio para acrescentar um Componente GroupBox( "Parmetros", como na figura abaixo: ) . Altere sua propriedade Caption para

Altere o nome do controle de edio para 'editEstado'e sua propriedade CharCase para 'ecUpperCase', deixe a propriedade Text vazia. Isso faz com que todas as letras digitadas sejam convertidas em maisculas. Chame o boto de 'btnProcurar' e mude sua propriedade Default para True. No evento OnClick do boto 'btnProcurar', vamos alterar a propriedade Filter do componente Table dinamicamente,com esta propriedade iremos definir um filtro que ir procurar os clientes que pertencem ao estado indicado.Digite o seguinte: tblCliente.Filter := 'Estado = ''' + editEstado.text + ''''; tblCliente.Filtered := true; tblCliente.Open; Note que para modificar a propriedade Filter, usamos vrios apstrofos na sintaxe. Cada dois apstrofos na string representam um apstrofo na string resultante. Por exemplo, se editEstado = 'GO' a string do Filter vai conter : Estado = 'GO' Mas a propriedade Filter funciona somente se a propriedade Filtered for True.Aps a alterao da propriedade necessrio abrir o componente Table novamente para ver o resultado. Salve o formulrio e execute. Para testar informe alguns estados e clique no boto 'Procurar'. Notas: O paradox "case sensitive", portanto ele faz diferenciao entre letras maisculas e minsculas. Exceo somente quando cria um ndice secundrio para o campo e a opo "case sensitive" deve estar desmarcada.

Exemplo: Clientes - Alterando


Neste captulo, faremos vrias alteraes no formulrio "formCadCliente". Portanto, abra esse projeto.

117

Note que ainda faltam no formulrio controles de dados para os novos campos que foram acrescentados por ltimo: CPF, Cidade e Estado. Os objetos foram criados , falta criar os controles de dados. Clique duas vezes em 'tblCliente' (o nico componente Table do formulrio) para abrir o editor de campos. Agora arraste, um de cada vez, os campos CPF, Cidade e Estado para o formulrio. Deixe o formulrio com a aparncia semelhante a figura abaixo:

Mantenha o editor de campos aberto.

Validao de Campos e Registros


Uma mscara de edio proporciona uma forma automtica de validao de campos, mas voc pode tambm adicionar seu prprio cdigo de validao, executado pelo Delphi quando for necessrio. Existem duas formas de validao: Validao de Campo: feita logo quando o usurio alterna para outro campo, no mesmo registro ou em outro. Se a validao falha, o usurio no consegue mudar de campo. Validao de Registro: feita apenas quando o usurio muda de registro, e se a validao falha, o usurio no pode mudar de registro. Pode ser usada para fazer uma verificao que envolva mais de um campo.

Validando Campos
Para fazer a validao de campo, voc deve tratar o evento OnValidate. Esse um evento do componente TField associado ao campo. Vamos adicionar uma validao ao campo CPF. Para este projeto foi criado uma unit independente chamada GeralVenda que contm uma funo para fazer a verificao do CPF, a idia no explicar como funciona a verificao de CPF , mas de como fazer esse tipo de verificao no Delphi, segue tambm nesta unit uma rotina para verificao de CGC.Ento iremos utiliz-la para verificar se um determinado CPF foi informado corretamente.O nome da funo ValidaCPF ela retorna true se o CPF estiver correto, temos que passar como parmetro um valor do tipo 'String'. Notas:Para verificar se um cpf vlido ou no, primeiro certifique que ele tenha 11 dgitos. Os dois ltimos dgitos so utilizados para verificao. Declare algumas variveis: var soma, somaDig, pos, resto : smallint; A constante ordZero contm a posio do nmero 0 na tabela Ascii. A verificao do penltimo dgito feita atravs da soma dos dgitos at a posio , cada dgito necessrio multiplicar por 11 e subtrair pela sua posio, necessrio tambm ter a soma de todos os dgitos at a posio 9..

118

for pos := 1 to 9 do begin soma := soma + (ord(textoCPF[pos]) - ordZero) * (11 pos); somaDig := SomaDig + (ord(textoCPF[pos]) - ordZero); end; Verificao do Penltimo Dgito: Divida o contedo da varivel soma por 11,faa a subtrao do resto pelo nmero 11 e atribua a uma varivel, se o contedo desta varivel for maior que 9, altere o contedo da variavel para 0, em seguida verifique se o contedo desta varivel diferente do penltimo digito do CPF, se for CPF invlido, caso contrrio necessrio verificar o ltimo dgito. resto := 11 - soma mod 11; if resto > 9 then resto := 0; if resto <> ord(textoCPF[10] - ordZero then exit; {DV errado} Para verificar o ltimo dgito nessrio somar os resultados encontrados nos calculos anteriores. Ento Soma + SomaDig + 2 * resto , dividir este resultado por 11, o resto subtrair por 11 , se o resultado obtido for maior que 9 , atribuir 0 a esse resultado, em seguida verificar se o resultado encontrado igual ao ltimo dgito verificador , se for igual CPF Vlido. soma := soma + somaDig + 2 * resto; resto := 11 - soma mod 11; if resto > 9 then resto := 0; if resto <> ord(textoCPF[11]) - ordZero then exit; { segundo DV errado } Result := True; { tudo certo } No formulrio "formCadCliente" abra o editor de campos para tblCliente e clique no campo CPF na lista. No Object Inspector, abra a pgina de eventos e crie um procedimento de evento para OnValidate. Neste procedimento de eventos, adicione o seguinte: begin if not ValidaCPF(tblClienteCpf.value) then begin ShowMessage('CPF Invlido!'); Abort; end; end; A funo ValidaCPF verifica se o CPF esta correto.Caso esteja errado, o procedimento mostra uma mensagem, com ShowMessage e gera uma exceo com o procedimento Abort. Qualquer exceo gerada faz com que o Delphi cancele a movimentao de campo ou de registro, mas melhor usar Abort porque ele gera uma exceo silenciosa, da classe EAbort, que no mostra nenhuma mensagem de erro alm das mensagens do seu programa. Antes de executar o programa na seo Implementation da Unit CADCLIENTE acrescente uma clausula uses para a unit independente: uses GeralVenda; Para adicionar a Unit ao projeto , no menu Project|Add to Project ( ), escolha a unit "GERALVENDAS.PAS" em seguida clique no boto "Abrir". Execute o programa e veja o que acontece. Altere um registro existente, digitando um valor para o CPF, Invlido e tecle [Tab] para tentar mudar de campo. Voc deve digitar um valor vlido ou teclar [Esc] para retornar ao valor anterior do campo. importante notar que a validao de campo s acontece quando o usurio edita o campo. Um registro j existente, que tenha um valor invlido, no passar pela validao a no ser que o usurio altere o valor do campo CPF. Nota: Quando vrios controles esto associados ao mesmo campo, as alteraes de propriedade afetam todos eles.

119

Validando Registros
Para fazer uma validao de registro, voc pode utilizar o evento BeforePost do componente Table. Esse evento executado logo antes do registro ser gravado, seja um novo registro ou do um registro j existente. Essa gravao pode ocorrer quando o usurio clica no boto DBNavigator ou quando ele muda de registro, se o registro foi alterado. Selecione o componente 'tblCliente', e na pgina de eventos, clique duas vezes no valor de BeforePost. Neste evento vamos fazer o seguinte: begin if tblClienteNome.IsNull then begin ShowMessage('O nome obrigatrio'); tblClienteNome.FocusControl; Abort; end; if tblClienteCidade.IsNull then begin ShowMessage('A cidade obrigatrio'); tblClienteCidade.FocusControl; Abort; end; end; A propriedade IsNull de um componente TField retorna True se ele tem um valor nulo, isto , vazio, no informado. Se o campo estiver vazio, o procedimento mostra uma mensagem e chama o mtodo FocusControl do componente. Esse mtodo coloca o foco no controle de dados associado (com isso no preciso saber o nome do controle DBEdit ligado ao campo). Depois de fazer isso, o procedimento chama Abort para cancelar a gravao do registro. Com a validao de registro, o usurio s tem duas opes: ou digitar valores vlidos, ou do DBNavigator. Execute o programa e note que cancelar a edio do campo, com o boto agora essa validao tambm feita se voc incluir um registro e tentar grav-lo. Salve e execute o programa. Para testar crie um novo cliente , no informe seu nome , mas coloque o nome da cidade onde ele mora, ao salvar o cliente , o cliente no ser salvo enquanto no informar o seu nome. Notas: A verificao se um campo ou no obrigatrio pode ser no banco de dados e no Delphi podemos fazer a verificao atravs de erros.Veremos nos prximos captulos.

120

Tratamento de Excees
Desmarque a opo " Stop on Delphi Exceptions" no menu Tools | Debugger Options | Language Exceptions. Mas tarde iremos entender o motivo. Observe que ao digitar uma data invlida , ocorre a seguinte mensagem:

Esta mensagem que aparece um erro de execuo, ou seja, uma mensagem do Delphi avisando de uma condio de erro.O termo usado no Delphi para essas situaes exceo.Uma exceo[exception] uma condio anormal que ocorre durante a execuo do programa, que interrompe o seu funcionamento. Quando ocorre uma exceo, o Delphi mostra uma mensagem padro e termina a execuo do procedimento de evento atual, mas continua a responder a eventos e executar o programa.Para qualquer exceo, voc pode fazer seu prprio tratamento, interceptando o tratamento do Delphi. Para tratar essa exceo voc tem que utilizar um evento que ocorra antes da mensagem de erro. Como o componente est associado a um objeto de campo , podemos fazer este tratamento nos eventos do objeto de campo. Clique duas vezes no componente tblCliente ) para abrir o editor de campos. Clique no campo "DataNasc" e crie um procedimento ( para o evento OnSetText . Esse evento executado todas as vezes que alterado o contedo do objeto de campo. Neste procedimento o parmetro "Text" contm o valor da data informada. Coloque o cdigo a abaixo: var Data : TDateTime; begin try data := strtodate(text); tblClienteDataNasc.asDatetime := data; except on EConvertError do begin showmessage('Data Invlida!'); abort; end; end; end; O comando try (tentar) um comando de tratamento de excees. Os comandos entre o try e o except so executados, mas se ocorre alguma exceo nesse bloco, o Delphi sai do bloco e entra na parte except[exceto]. Ento o Delphi procura uma clusula on correspondente classe da exceo gerada. Se ele encontra um on correspondente, ele executa o comando de tratamento associado. Depois de executar o tratador, o Delphi no termina a execuo do procedimento de evento, mas continua a execuo com o prximo comando depois do end do try. A funo strtodate converte uma varivel do tipo string para data, caso ocorra algum erro gera uma exceo da classe 'EConvertError', se ocorrer a exceo mostramos a mensagem 'Data Invlida' , em seguida o comando abort executado ,es este comando cancela o procedimento, se ele no for colocado a mensagem do Delphi ir continuar aparecendo. Quando colocamos algum procedimento para este evento , ao sair do procedimento a data

121

informada no ser colocada no objeto de campo, por isso que atribuimos o valor da data ao objeto 'tblClienteDataNasc'.

Visualizando Informaes sobre Excees


Se a opo " Stop on Delphi Exceptions" estiver marcada , o Delphi mostra uma mensagem mais detalhada sobre cada exceo e mostra exatamente qual a linha que causou a exceo. Para verificar esta opo no menu Tools | Debugger Options | Language Exceptions e marque a opo " Stop on Delphi Exceptions". Agora execute o programa e provoque uma exceo, cadastrando um data invlida para a data de nascimento'. Nesse caso a mensagem ser:

ou seja , o projeto causou uma exceo da classe 'EConvertError'. O nome da classe de exceo uma informao importante quando voc fizer o tratamento da exceo no programa. Para continuar a execuo, tecle[F9] ou clique no boto (Run). Depois ir aparecer a mensagem que colocamos ( caso no tenha tratado a exceo aparece a mensagem do Delphi).

Classes de Excees
Quando voc faz o tratamento de excees, pode trat-las a nvel especfico de cada exceo ou voc pode tratar uma classe de exceo mais geral. As classes fazem parte de uma hierarquia de excees, como a seguinte: Exception (qualquer exceo) EIntError (erros de nmeros inteiros) EDivByZero (diviso por zero de inteiro) EIntOverflow (transbordo inteiro) ERangeError (valor ou ind. vetor fora de faixa) EMathError (erros de matemtica real) EOverflow (transbordo de real) EUnderflow (valor muito peq. de real) EZeroDivide (diviso por zero de real) Se voc criar uma clusula de tratamento para uma exceo mais geral, como 'EMathError', ela ser acionada para qualquer uma das classes abaixo na hierarquia, seja diviso por zero (EZeroDivide), transbordo de valor (EOverflow) ou qualquer outra. A classe Exception o nvel mais geral de tratamento e intercepta qualquer exceo. Se num conjunto de tratadores, voc colocar um tratador primeiro para uma exceo mais geral e depois para uma exceo especfica, o tratador mais especfico nem vai chegar a ser executado. Notas: O tratamento de exceo pode ser feito em qualquer procedimento que julgar necessrio.

Pesquisas na Tabela
Uma caracterstica fundamental de um programa permitir que o usurio faa uma pesquisa em uma tabela, fornecendo o valor a ser pesquisado. Na tabela de clientes, vamos facilitar a pesquisa pelo nome do cliente.

Adicionando um DBGrid
Para isso vamos adicionar ao formulrio um controle DBGrid, que vai mostrar toda a lista de clientes, permitindo selecionar qualquer um deles. Abra um espao adicional direita do

122

formulrio e acrescente um componente Label, com o texto "Procura:" e um componente Edit (no use um DBEdit), com o nome de "editProcura". Abaixo deles acrescente um componente DBGrid (cone da pgina Data Controls). O formulrio deve ficar como o seguinte:

Agora associe a grade (DBGrid) com a tabela, alterando sua propriedade DataSource para 'dsCliente'. Com isso, se a tabela estiver ativa, ele vai automaticamente mostrar todos os campos e todos os registros da tabela. No vamos permitir que o usurio altere os dados usando o grid. Para isso basta mudar a sua propriedade ReadOnly para True. Vamos restringir os campos mostrados apenas ao campo "Nome". Para isso, clique duas vezes em 'tblCliente' para abrir o editor de campos, selecione todos os campos menos Nome e altere a propriedade Visible para False. Se preciso, reduza o DisplayWidth para que o valor do campo aparea todo no Grid. Algumas caractersticas de visualizao do DBGrid no so necessrias aqui, como as linhas divisrias de registros e campos, ou os ttulos da parte de cima. Vamos desativar essas caractersticas, alterando a propriedade Options. Expanda essa propriedade no Object Inspector e altere as seguintes opes: Opo Valor Finalidade dgEditing False no permite incluir ou excluir dgTitles False desativa os ttulos dgIndicator False desativa o indicador de registro dgColLines False desativa as linhas verticais dgRowLines False desativa as linhas horizontais dgTabs False no usa [Tab] para mudar de campo dgAlwaysShowSelection True sempre mostra a linha selecionada Se a opo 'dgAlwaysShowSelection' estiver desativada, o grid s mostra qual a linha selecionada (a do registro atual) quando ele tem o foco de teclado. Ns devemos ativ-la para que o usurio saiba qual o nome selecionado na lista a qualquer momento. Execute o programa e verifique. Voc pode clicar na grade a qualquer momento para selecionar um dos registros, ou usar o DBNavigator para percorrer os registros. Nota: existem duas opes parecidas: dgAlwaysShowEditor e dgAlwaysShowSelection. Para visualizar melhor as opes, aumente a largura do Object Inspector.

Utilizando um ndice Secundrio


Mas h um problema: a grade mostra os dados ordenados pelo ndice principal da tabela, que no caso o ndice no campo CodCliente. Para facilitar a pesquisa, eles deveriam estar ordenados por nome.

123

Para mudar a ordem dos registros, podemos usar um ndice diferente. Para ordenar por nome, que o necessrio, precisamos usar o ndice criado para o campo Nome. Para isso, basta alterar a propriedade IndexName do componente Table. Se ela estiver vazia, a ordem dos registros ser determinada pelo ndice primrio da tabela. Se voc colocar o nome de um ndice secundrio, a ordem ser de acordo com esse ndice. Essa propriedade afeta tanto a ordem virtual dos registros, quanto as pesquisas que voc fizer, como veremos. Clique na propriedade IndexName e selecione o nome "IndNome" da lista. Esse o nome do ndice secundrio criado. Note como a ordem dos registros alterada no controle DBGrid. Se voc apagar o valor de IndexName, a ordem volta a ser a do campo CodCliente. Alm da propriedade IndexName, existe outra chamada IndexFieldNames, que tem a mesma funo. O valor desta propriedade a lista dos campos que compem o ndice. Por exemplo, voc poderia colocar "Nome" em IndexFieldNames e teria o mesmo efeito. Isto til se voc no souber o nome do ndice, mas se souber quais os campos que fazem parte dele. As duas propriedades so mutuamente exclusivas: se voc altera uma, a outra ter seu valor eliminado.

Pesquisando pelo Nome


Os controles acima do DBGrid sero usados para permitir pesquisa na tabela pelo nome do cliente. A cada digitao do usurio, vamos posicionar a tabela no nome mais prximo. Para isso, vamos usar o mtodo FindNearest do componente Table. Esse mtodo procura um valor na tabela utilizando o ndice atual. Se o valor no for encontrado exatamente, ele posiciona no registro mais prximo. Selecione o controle 'editProcura' e crie um procedimento para o evento OnChange. Esse evento executado toda vez que o usurio altera o valor do controle, digitando ou apagando caracteres. No procedimento basta colocar o seguinte: begin tblCliente.FindNearest([editProcura.Text]); end; Execute e verifique o resultado. Quando voc digita um nome em 'editProcura', o valor mais prximo selecionado. Isso chamado de busca incremental. Nota: se o ndice tiver mais de um campo, coloque em IndexFieldNames os nomes de campos separados por ponto-e-vrgula ";", sem espaos. Nota: quando voc clica num cone da paleta de componentes e depois em cima de um componente, aquele que voc criou fica contido no primeiro, isto , restrito rea do componente e os dois so movimentados em conjunto.

Pesquisando pelo Cdigo


Agora vamos dar ao usurio a opo de procurar um registro pelo valor do campo cdigo, que tambm tem um ndice definido (o ndice primrio da tabela). Para isso, abra um espao na parte inferior do formulrio. Vamos colocar nesse espao um componente GroupBox, que usado para agrupar visualmente outros componentes. do GroupBox na pgina standard e coloque-o no formulrio. Coloque na Selecione o cone sua propriedade Caption o texto "Procura por cdigo". Dentro do componente GroupBox, crie um label, um quadro de edio e um boto, como na figura abaixo:

Mude o Caption do label para "Cdigo:". Mude o Name do componente Edit para 'editProcCodigo' , a propriedade Text deixe vazia e o nome do boto para 'btnProcCodigo' e altere a propriedade caption para "Procurar". Agora clique duas vezes no boto Procurar. Neste procedimento, vamos usar o valor digitado para pesquisar na tabela, usando o mtodo FindKey. Como vamos pesquisar por um campo diferente, devemos alterar a propriedade IndexName do componente dinamicamente, e depois retorn-la ao original. Isso gera um pequeno problema ao alterar essa propriedade, os controles do formulrio vo mudar para refletir o novo ndice. Isso pode ser evitado com o

124

mtodo DisableControls do componente Table. Quando ele chamado, os controles de dados no atualizam mais seus valores at que o mtodo EnableControls seja chamado. Com isso, coloque o seguinte no cdigo do procedimento: var codigo: integer; begin codigo := StrToInt(editProcCodigo.Text); with tblCliente do try DisableControls; IndexName := ''; {usando ndice primrio} if not FindKey([codigo]) then ShowMessage('Codigo no encontrado'); finally IndexName := 'IndNome'; {usando ndice por Nome} EnableControls; end; end; O mtodo FindKey uma funo que retorna True se encontrou o registro. Caso ele encontre, ele posiciona no registro, seno mantm posicionado no registro atual.

Blocos Protegidos
Os tratamentos de erros no Delphi podem ser feitos para uma exceo especfica. As vezes , no necessrio tratar um exceo especfica , mas preciso realizar uma ao de finalizao, O finally utilizado quando uma determinada exceo ocorre , e necessitamos executar de qualquer forma um determinado comando ou vrios comandos antes de interromper o procedimento. Esses comandos devem ser colocados no trecho finally..end. Em geral , blocos protegidos podem ser usados em qualquer situao que envolva uma alocao e liberao de recursos(como um arquivo , por exemplo). No procedimento de evento do OnClick observe que a alterao de IndexName e a chamada de EnableControls so feitas no bloco finally. Isso significa que mesmo que acontea uma exceo, esses comandos so executados. Isso importante, pois se esse tipo de tratamento no for feito, os controles de dados podem ficar num estado desabilitado, e o usurio no conseguiria mais utilizar o programa. Execute e verifique o resultado. Se voc digitar um cdigo e clicar no boto Procurar, o programa vai tentar procurar o registro.

125

Captulo 15 Acesso s/ Controle de Dados


Estados de uma Tabela Mtodos para Percorrer Dados Mtodos para Modificar Dados Eventos dos Componentes de Dados Manipulao de Datas Exemplo: Criando Formulrio sem Utilizar o dbNavigator Tratamento do Erro "Key Violation" Usando um Controle DBLookupComboBox

126

Estados de uma Tabela


Dependendo da situao, um componente Table pode estar em vrios estados diferentes. preciso entender estes diferentes estados para poder utiliz-lo. A propriedade State (acessvel somente em tempo de execuo) tem valores diferentes dependendo do estado. Os principais so: Inativo (dsInactive): a tabela est fechada. A propriedade Active True. Visualizao (dsBrowse): a tabela est aberta, e o usurio est visualizando ou percorrendo registros. Inserindo (dsInsert): foi iniciada a incluso de um novo registro, mas esse registro ainda no foi salvo no banco de dados. O componente entra nesse estado quando o usurio clica no do DBNavigator. boto Editando (dsEdit): foi iniciada a edio de um registro existente, mas o registro ainda no foi salvo. O componente entra nesse estado quando o usurio comea a alterar um campo. Quando a propriedade AutoEdit do componente DataSource False (o padro True), o do DBNavigator. usurio deve iniciar a edio explicitamente, clicando no boto Quando a tabela est no estado inativo, voc no pode acessar os dados. Quando ela est no estado de visualizao (dsBrowse), voc pode percorrer os registros da tabela e ler os valores de campos, utilizando os componentes TField, mas voc no pode alterar os valores de campos. Para alterar os valores dos campos de um registro, voc deve colocar a tabela em estado de edio (dsEdit) e depois alterar o valor dos componentes TField. Depois voc deve salvar os dados, retornando ao estado de visualizao. Quando voc inicia a incluso de um registro, todos os componentes TField ficam com o valor em branco (nulo), e voc pode atribuir valores para eles. Depois que voc salva o registro, a tabela retorna ao estado de visualizao.

127

Mtodos para Percorrer Dados


O componente Table tem vrios mtodos que permitem voc acessar a tabela utilizada, independemente dos controles de dados. Se o componente Table estiver ligado a um componente DataSource, que utiliza controles de dados, o resultado dos mtodos vai aparecer na tela.

Mtodos de Abertura e Fechamento


Para abrir a tabela e poder acessar os seus dados, primeiro defina as propriedades DatabaseName e TableName do componente Table, seja em tempo de projeto ou no cdigo do programa. Depois utilize o mtodo Open, por exemplo: tblCliente.Open; Aps terminar de utilizar a tabela, voc pode usar o mtodo Close para liberar a tabela e o componente Table para outros usos. tblCliente.Close; O mtodo Open equivale a alterar a propriedade Active para True. O mtodo Close equivale a alterar a propriedade Active para False.

Mtodos para Percorrer Registros


Os seguintes mtodos podem ser usados para percorrer registros: Boto Mtodo Descrio Posiciona no primeiro registro. First Prior Next Last N/A MoveBy ( n ) Volta para o registro anterior. Avana para o prximo registro. Posiciona no ltimo registro.

Avana 'n' registros. Se 'n' for positivo, move para frente. Se 'n' for negativo, move para trs. Repare que cada um deles, exceto MoveBy, equivalente a um boto correspondente do controle DBNavigator. Na verdade, o DBNavigator apenas chama os mtodos correspondentes do componente Table, em resposta ao clique do usurio. Lembre-se que a ordem em que os registros aparecem quando voc percorre seqencialmente a ordem determinada pelo ndice que estiver sendo utilizado no momento. Quando a tabela aberta, o ndice utilizado o ndice primrio, mas isso pode ser alterado. Para ler os campos do registro atual, existem duas formas. Se voc usou o editor de campos para criar uma lista de componentes TField, cada um deles tem um nome, que formado pelo nome do componente Table, mais o nome do campo. Com isso, basta acessar a propriedade Value do componente TField: preco := tblItemPrecoVenda.Value; quant := tblItemQuantidade.Value; Mas se voc no criou uma lista de campos, os componentes TField so criados internamente e no tm nome, mas ainda podem ser acessados com o mtodo FieldByName: preco := tblItem.FieldByName('PrecoVenda').AsFloat; quant := tblItem.FieldByName('Quantidade').AsInteger; As propriedades AsFloat e AsInteger so necessrias nesse caso, para especificar qual o tipo de dados que voc est acessando. No caso de um componente criado explicitamente, o Delphi j sabe o tipo de campo pela declarao, ento voc pode usar Value, que tem o mesmo tipo de dados do campo. Da mesma forma, existem outras propriedades "As*", como AsString, AsDate, que retornam o valor do campo convertido para um determinado tipo de dados. Voc no pode atribuir valores para a propriedade Value ou As* do componente se voc estiver em modo de percorrer registros. Quando voc est percorrendo a tabela, existem duas propriedades teis, ambas do tipo boolean. A propriedade EOF verdadeira quando voc estiver posicionado no fim da tabela,

128

depois do ltimo registro. J BOF verdadeira quando voc estiver posicionado no incio da tabela. Por exemplo, para percorrer a tabela do incio ao fim. with tblItem do begin First; { vai para o primeiro registro } while not EOF do begin preco := tblItemPrecoVenda.Value; quant := tblItemQuantidade.Value; ... Next; { vai para o prximo registro } end; end; Se ambas forem verdadeiras, a tabela est vazia, no tem nenhum registro: if tblItem.BOF and tblItem.EOF then ShowMessage('A tabela est vazia');

Exemplo: Percorrendo a Tabela de Itens


Crie um novo projeto no Delphi, no qual vamos percorrer a tabela de itens (ITEM.DB) atravs de comandos de programa, usando os mtodos do componente Table. Esse programa vai percorrer toda a tabela e totalizar a quantidade de itens vendiddos. Altere a propriedade Caption do formulrio para 'Totalizar Itens'. Coloque no formulrio um componente Table ( ) e defina as seguintes propriedades: Name ser 'tblItem', DatabaseName ser 'CursoDelphi', o alias que diz onde esto os dados e TableName ser 'ITEM.DB'. Crie controles no formulrio como na figura:

Coloque um label, com o texto "Total:" e um controle de edio, com o nome 'editTotal', que ir mostrar o resultado final. Finalmente coloque um boto, com o texto 'Totalizar' e nome 'btnTotalizar'. Clique duas vezes no 'tblItem' para abrir o editor de campos. Acrescente todos os campos lista. Repare que se voc clicar em um nome de campo, por exemplo 'Quantidade', voc ver que a propriedade Name do objeto de campo tblItemQuantidade. Esse o nome que voc deve utilizar no programa para acessar o valor do campo. Clique duas vezes no boto Totalizar e digite o seguinte: var total: double; begin total := 0; with tblItem do begin Open; First; while not EOF do begin total := total + tblItemQuantidade.Value ; Next; end; Close; end; editTotal.Text := FloatToStr(total); end; Dentro do with, a primeira linha chama o mtodo Open para abrir a tabela. Isso no seria necessrio se a propriedade Active j tivesse o valor True no incio da execuo. Depois First posiciona no primeiro registro. Essa chamada no realmente necessria, porque logo depois de abrir a tabela, o registro atual j o primeiro.

129

O lao while verifica o valor da propriedade EOF. Enquanto ela for falsa (not EOF), o lao percorre os registros. Para cada registro, o campo Quantidade somado com varivel 'total'. Note a forma de acesso aos campos: com os nomes dos objetos TField, usando sua propriedade Value. Depois de somar o valor, o mtodo Next muda para o prximo registro. Depois do lao, o mtodo Close fecha a tabela (faz Active = False), e finalmente o resultado final, acumulado em 'total', mostrado no controle 'editTotal'. Execute o programa e clique no boto Totalizar para ver o resultado. Salve o projeto como TOTALITEM.PAS E TOTALITEMP.DPR.

130

Mtodos para Modificar Dados


Editando Registros
Para alterar os campos do registro atual, voc deve colocar a tabela em modo de edio. Para isso voc deve chamar o mtodo Edit do componente Table. Aps chamar o mtodo Edit, altere os valores dos campos, usando os objetos TField. As alteraes no sero gravadas at que voc chame o mtodo Post. Por exemplo: tblItem.Edit; tblItem.FieldByName('Quantidade').AsString := quantidade; ... {outras alteraes} tblItem.Post; Ou, de forma mais abreviada, usando o with: with tblItem do begin Edit; FieldByName('Quantidade').AsString := quantidade; ... {outras alteraes} Post; end; Voc pode usar tambm os componentes TField, se voc tiver usado o editor de campos para cri-los explicitamente. Nesse caso, melhor atribuir um valor para a propriedade Value, que j tem o tipo de dados correto. Quando mltiplos usurios acessam a mesma tabela, Edit tem uma funo mais importante: ele trava [lock] o registro, de forma que nenhum usurio consegue edit-lo (mais ainda pode fazer a leitura). Quando voc tentar travar o registro, e outro usurio j est editando, seja no mesmo computador ou em outro computador na rede, Edit vai gerar uma exceo EDBEngineError. Essa exceo pode ser tratada usando um comando try..except, coma j vimos. Depois que voc chama o mtodo Post, o registro gravado e liberado. Se depois de chamar Edit, voc resolver cancelar as alteraes no registro (devido a uma exceo, por exemplo), voc pode chamar o mtodo Cancel em vez de Post. Esse mtodo libera o registro e cancela todas as alteraes feitas nos componentes TField. Se voc mudar de registro aps o Edit, usando o mtodo Next por exemplo, o componente vai verificar se voc alterou algum campo. Se voc tiver alterado, ele automaticamente salva o registro antes da movimentao. Se no foi feita alterao, ele cancela a edio para no gravar um registro desnecessariamente. Quando voc usa o controle DBNavigator, alguns botes dele chamam automaticamente esses =Edit, = Post, = Cancel. mtodos: O boto Edit geralmente no necessrio, porque geralmente o usurio pode iniciar a edio simplesmente alterando um controle de dados, o que automaticamente chama o mtodo Edit. Mas isso depende da propriedade AutoEdit do componente DataSource, que normalmente True. Quando AutoEdit False, o usurio no pode editar os controles de dados e para poder modificar o registro, ele deve primeiro clicar no boto do DBNavigator.

Acrescentando Registros
Para incluir um novo registro na tabela, voc deve chamar o mtodo Insert ou Append. Se a tabela no tem ndice primrio, Insert insere um novo registro no meio da tabela e Append acrescenta o novo registro ao final. Para uma tabela que tem chave primria, os dois mtodos fazem exatamente a mesma coisa: o registro ser inserido na posio determinada pela chave. Assim, o que discutiremos sobre Insert se aplica igualmente a Append. Quando voc chama Insert, ele no grava dados na tabela. Ele apenas cria um novo registro vazio em memria. Depois voc deve preencher os campos desse registro com os seus valores, usando os objetos TField. Para gravar os dados, chame o mtodo Post. O novo registro ser o registro atual da tabela, e vai se tornar o registro atual. A posio do registro na tabela ser determinada pelo valor da sua chave primria. Por exemplo: codigo := 20;

131

with tblItem do begin Insert; tblItemCodItem.Value := codigo; tblItemQuantidade.Value := quant; tblItemPrecoVenda.Value := preco; Post; end; Se voc quiser cancelar a insero do novo registro, use o mtodo Cancel. Quando voc cancela, a posio de registro volta ao registro onde voc estava posicionado antes de chamar Insert. Se voc mudar de registro aps chamar Insert, o componente vai verificar se voc alterou algum campo, e vai gravar o novo registro, caso tenha havido alterao, ou cancelar a incluso, caso voc tenha deixado o registro inteiro em branco. , que chama Quando voc usa o controle DBNavigator, o usurio pode clicar no boto automaticamente o mtodo Insert da tabela. Depois ele preenche os campos e clica no boto , que chama o mtodo Post, ou no boto , que chama o mtodo Cancel. Quando voc usa o controle DBGrid, o usurio pode pressionar a tecla [Insert] para chamar o mtodo Insert, preencher os campos, e mudar de registro.

Excluindo Registros
Para excluir o registro atual, use o mtodo Delete: tblItem.Delete; A operao de excluso executada imediatamente e no pode ser desfeita. Registros excludos no podem ser recuperados. Usando o controle DBNavigator, o usurio pode clicar no boto , que chama esse mtodo automaticamente. Usando o controle DBGrid, o usurio pode pressionar [Ctrl+Delete] para excluir o registro atual. Esses dois controles tm uma propriedade ConfirmDelete. Se ela estiver verdadeira (valor True), o controle mostra uma mensagem de confirmao predefinida, seno exclui o registro imediatamente.

Outros Mtodos
Quando voc trabalha com os mtodos do componente Table, o efeito dos mtodos (edio, incluso, ou movimentao) aparece imediatamente nos controles de dados (se houver). Essa atualizao dos controles geralmente desnecessrio, e toma um certo tempo, tornando muito demorada uma operao com vrios registros, por exemplo. Voc pode desabilitar temporariamente a atualizao dos controles, com o mtodo DisableControls e depois habilitar novamente a atualizao com o mtodo EnableControls. Quando voc chama EnableControls, todos os controles de dados ficam "congelados" com seus valores atuais. Por exemplo: with tblItem do begin DisableControls; while not EOF do ... EnableControls; end; Se voc no lembrar de habilitar os controles de dados, eles ficam inutilizveis pelo usurio. Note tambm que se acontecer uma exceo depois de desabilitar os controles, o Delphi vai sair do procedimento e eles no sero habilitados novamente. Para evitar essa ltima situao, use um comando try..finally: try DisableControls; while not EOF do ... finally EnableControls; end;

132

Um comando try..finally garante que a parte do finally sempre executada, seja numa execuo normal, ou quando ocorre uma exceo no bloco do try. Nesse caso, isso garante que os controles de dados so habilitados novamente. Numa rede, os registros que esto sendo visualizados podem ficar desatualizados medida que outros usurios adicionam novos registros. Para obter os registros mais atualizados da tabela, voc pode usar o mtodo Refresh: tblCliente.Refresh; Esse mtodo chamado automaticamente pelo boto do DBNavigator.

133

Eventos dos Componentes de Dados


Os componentes de dados tm vrios eventos que so acionados em momentos especficos.

Eventos do Componente Table


Para cada mtodo do componente Table (Edit, Insert, Post, etc.), existem eventos "Before" e "After", que acontecem respectivamente antes e depois da execuo do mtodo. No evento "Before", voc pode cancelar a execuo do mtodo atual, gerando uma exceo. Esses eventos so acionados nas seguintes situaes: BeforeScroll, AfterScroll: antes e depois, respectivamente, de qualquer movimentao de registro na tabela, provocada por um dos mtodos de movimentao First, Next, Prior, Last, MoveBy, FindKey, FindNearest, etc. BeforeCancel, AfterCancel: antes e depois do cancelamento de uma edio ou incluso (mtodo Cancel). BeforeClose, AfterClose: antes e depois da tabela ser fechada (mtodo Close). BeforeDelete, AfterDelete: antes e depois de um registro ser excludo. No evento BeforeDelete, voc pode mostrar sua prpria mensagem de confirmao de excluso, evitando uma mensagem do Delphi. BeforeEdit, AfterEdit: antes e depois do incio da edio de um registro. BeforeInsert, AfterInsert: antes e depois do incio da incluso de um registro. BeforeOpen, AfterOpen : antes e depois da tabela ser aberta (ativada). BeforePost, AfterPost: antes e depois do registro ser gravado. O evento BeforePost, como j vimos, o melhor lugar para se fazer uma validao de registro, evitando a gravao se necessrio. OnNewRecord: acontece depois da incluso de um novo registro, antes do evento AfterInsert. Nesse evento voc pode, por exemplo, preencher o campo chave da tabela com um valor gerado pelo programa. Se voc fizer alguma alterao de campos em AfterInsert, ou qualquer outro evento, o registro ser considerado modificado, por isso melhor usar OnNewRecord. Cada um desses eventos tem um cabealho como o seguinte: procedure TForm1.Table1BeforePost(DataSet: TDataset); Ou seja, um parmetro do tipo 'TDataset'. TDataset uma classe que ancestral da classe TTable e de outros objetos de acesso a dados. Usando o parmetro 'DataSet', voc pode manipular a tabela de forma genrica, sem especificar o nome exato do componente. Alm desses, o evento OnCalcFields, como j vimos, acontece quando voc tem campos calculados, no momento em que necessrio obter o valor desses campos.

134

Manipulao de Datas
O Delphi permite armazenar datas e horas no banco de dados, em campos do tipo Date (apenas datas), ou do tipo Time (apenas horas), ou campos Date/Time ou Timestamp (guarda data e hora), em alguns bancos de dados. importante tambm saber nesse caso as funes disponveis para manipulao de datas. O Delphi codifica datas e horas internamente como nmeros, que representam uma contagem de dias desde 1/1/0001. Ele usa o tipo de dados TDateTime para esse formato codificado. Voc pode usar a funo EncodeDate para gerar esse valor codificado, e o procedimento DecodeDate para obter os componentes da data separados (dia, ms e ano). Por exemplo: var data: TDateTime; ... begin ... data := EncodeDate( ano, mes, dia ); .... DecodeDate( data, ano, mes, dia ); ... end; Para tratamento de horas, voc tem semelhantemente as rotinas EncodeTime e DecodeTime, que de forma genrica, so usadas assim: varHora := EncodeTime( horas, minutos, segundos, milisegs ); DecodeTime( varHora, horas, minutos, segundos, milisegs ); Voc pode fazer operaes com as datas codificadas, como por exemplo, somar um nmero a uma data, ou subtrair duas datas para saber a quantidade de dias entre elas. Voc tambm pode converter uma data/hora para sua representao textual, para trat-la como uma string, usando DateToStr, TimeToStr, ou DateTimeToStr: editData.Text := DateToStr(tblClienteDataNasc.Value); labelRelogio.Caption := TimeToStr(Now); Essas funes convertem a data usando o formato padro, que depende da configurao do Windows. Mas voc pode tambm usar outros formatos, usando FormatDateTime, por exemplo: texto := FormatDateTime(data, 'dd/mm/yyyy'); No segundo argumento de FormatDateTime, voc pode usar os marcadores de posio (entre outros): Marcador Insere d, dd O dia do ms. Se o dia de 1 a 9, "dd" acrescenta um zero esquerda. ddd O dia da semana abreviado. dddd O nome do dia da semana, completo. m, mm O ms como um nmero. Se o ms de 1 a 9, "mm" acrescenta um zero esquerda. mmm O nome do ms abreviado. mmmm O nome do ms completo. yy O ano com dois dgitos. yyyy O ano com quatro dgitos. h, hh As horas. Se de 0 a 9, "hh" acrescenta um zero esquerda. m, mm Os minutos. Se de 0 a 9, "mm" acrescenta um zero esquerda. s, ss Os segundos. Se de 0 a 9, "mm" acrescenta um zero esquerda. / O separador de datas (pode no ser uma barra). : O separador de horas (pode no ser o dois-pontos). Esses mesmos marcadores podem ser usados com a propriedade DisplayFormat de um campo do tipo data ou hora. Voc pode converter uma string em data/hora, usando as funes de converso StrToDate, StrToTime e StrToDateTime. Para saber o dia da semana, voc pode usar a funo DayOfWeek: diaSemana := DayOfWeek(data); {1=domingo,...7=sbado}

135

Finalmente, voc tem funes para consultar a data/hora atuais do computador: Now retorna a data e hora atuais codificadas, Date retorna apenas a data e Time retorna apenas a hora. Por exemplo, para mostrar a data de hoje em um controle de edio, faa: editData.Text := DateToStr(Date);

136

Exemplo: Criando formulrio sem utilizar o dbNavigator


Neste exemplo iremos criar o cadastro de fornecedores, sem utilizar o componente dbNavigator , iremos utilizar Botes e tratar o evento de cada um , fazendo uma simulao do dbNavigator. Crie um novo formulrio, altere seu nome para 'formCadFornecedor', na propriedade ), Caption coloque 'Cadastro de Fornecedores'. Acrescente 9 componentes SpeedButton ( e altere as propriedades a seguir, as figuras so encontradas no direito do Delphi 'BORLAND SHARED\IMAGES\BUTTONS' : SpeedButton1 spbIncluir Name FILENEW.BMP Glyph Inclui Hint SpeedButton2 spbAlterar Name FILEOPEN.BMP Glyph Alterar Hint SpeedButton3 spbSalvar Name FLOPPY.BMP Glyph Salvar Hint SpeedButton4 spbCancelar Name IGNORE.BMP Glyph Cancelar Hint SpeedButton5 spbPrimeiro Name VCRREWND.BMP Glyph Primeiro Hint SpeedButton6 spbAnterior Name ARROW3L.BMP Glyph Anterior Hint SpeedButton7 spbProximo Name ARROW3R.BMP Glyph Prximo Hint SpeedButton8 spbUltimo Name VCRFSFOR.BMP Glyph ltimo Hint SpeedButton9 spbExcluir Name TRASH.BMP Glyph Excluir Hint Coloque seu formulrio como a figura abaixo:

137

Coloque um componente Table e um DataSource no formulrio, defina suas propriedades como: Table Name: tblFornecedor DatabaseName: CursoDelphi TableName: Fornecedor DataSource Name: dsFornecedor DataSet: tblFornecedor Clique duas vezes no componente tblFornecedor, para abrir o editor de campos, em seguida adicione os objetos de campos e arraste-os para o formulrio. Organize seu formulrio de acordo com a figura abaixo:

Salve a unit como 'CADFORNCEDOR.PAS'. No evento OnShow do formulario, vamos abrir o componente tblFornecedor , crie um procedimento para este evento e coloque: tblFornecedor.Open Para que o formulrio funcione necessrio acrescentar em cada Boto , um procedimento para o evento OnClick. No procedimento do evento OnClick do boto spbIncluir colocar: procedure TformCadFornecedor.spbIncluirClick(Sender: TObject); begin tblFornecedor.insert end; O mtodo Insert do componente Table, inclui um registro em branco. No procedimento do evento OnClick do boto spbAlterar colocar: procedure TformCadFornecedor.spbAlterarClick(Sender: TObject); begin tblFornecedor.edit

138

end; O mtodo Edit que permite fazer alteraes, mas essas alteraes podem ser confirmadas ou no. No procedimento do evento OnClick do boto spbSalvar colocar: procedure TformCadFornecedor.spbSalvarClick(Sender: TObject); begin tblFornecedor.post end; O mtodo Post, confirma as alteraes feitas nos campos da tabela. No procedimento do evento OnClick do boto spbCancelar colocar: procedure TformCadFornecedor.spbCancelarClick(Sender: TObject); begin tblFornecedor.cancel end; O mtodo Cancel, cancela as alteraes feitas nos campos da tabela. No procedimento do evento OnClick do boto spbPrimeiro colocar: procedure TformCadFornecedor.spbprimeiroClick(Sender: TObject); begin tblFornecedor.first end; O mtodo First movimenta para o primeiro registro. No procedimento do evento OnClick do boto spbAnterior colocar: procedure TformCadFornecedor.spbAnteriorClick(Sender: TObject); begin tblFornecedor.prior end; O mtodo Previous movimenta para o registro anterior. No procedimento do evento OnClick do boto spbIncluir colocar: procedure TformCadFornecedor.spbProximoClick(Sender: TObject); begin tblFornecedor.next end; O mtodo Next movimenta para o prximo registro. No procedimento do evento OnClick do boto spbUltimo colocar: procedure TformCadFornecedor.spbUltimoClick(Sender: TObject); begin tblFornecedor.last end; O mtodo Last movimenta para o ltimo registro. No procedimento do evento OnClick do boto spbExcluir colocar: procedure TformCadFornecedor.spbExcluirClick(Sender: TObject); begin if application.messagebox('Deseja excluir o fornecedor?', 'Confirmao', MB_ICONQUESTION + MB_YESNO) = idyes then tblFornecedor.delete end; O mtodo Delete exclui o registro atual. Antes de excluir o registro ser mostrado uma mensagem perguntando se deseja excluir o fornecedor. Notas: Se foi feita alguma alterao no registro atual , em seguida foi aplicado algum modo de movimentao na tabela ,as alteraes sero confirmadas, antes da movimentao. Neste exemplo mostramos somente o que cada mtodo faz, no foi realizado nenhum controle de desativar o boto Salvar , se o componente Table no estiver no modo de Alterao ou

139

Incluso , esses controles podem ser feitos com a propriedade Enabled de cada componente SpeedButton.

Tratamento do Erro 'Key violation.'


Este erro ocorre quando estamos inclundo um registro , e o valor informado para a chave primria j existe. Para mostrar uma mensagem de erro mais clara para o usurio , podemos mostrar a nossa prpria mensagem de erro. Este erro ocorre quando o usurio confirma as informaes que foram colocadas, ou seja, quando o nosso programa executa o mtodo Post. Quando ocorre algum erro durante a execuo desse mtodo, gera o evento OnPostError, ento podemos criar um procedimento para este evento que ir mostrar a mensagem que desejamos.Neste procedimento coloque os comandos abaixo: if e.message = 'Key violation.' then begin showmessage('Fornecedor Cadastrado!'); abort; end; O parmetro 'E' contm o erro que ocorreu durante a gravao dos dados. Este parmetro da classe EDataBaseError,a propriedade message desta classe , contm a mensagem do erro. necessrio abortar o procedimento, para que a mensagem em ingls no aparece, por isso utilizamos o mtodo Abort;. Notas: Ao verificar uma mensagem com a propriedade message, para que a condio utilizada seja verdadeira, a mensagem que esta verificando case sensitive, portanto, tem que ser escrita idntica ao contedo da propriedade Vamos associar este formulrio ao formulrio principal, na Unit 'VENDPRIN.PAS', logo aps a seo implementation acrescente: Uses CadCliente, ....., CadFornecedor; Agora tecle [F12] para voltar ao formulrio. Clique no item de menu Cadastro|Fornecedor e, no procedimento de evento, coloque o seguinte comando: formCadFornecedor.show Salve o projeto e execute . Para testar cadastre alguns fornecedores , faa alteraes, tente cadastrar fornecedores que tenham o mesmo cdigo.

Usando um Controle DBLookupComboBox


Quando o usurio cadastra um produto, ele precisa digitar o cdigo do fornecedor, que deve corresponder a um valor vlido na outra tabela. Esse um processo sujeito a erros e torna difcil validar o valor que o usurio digita (para validar, seria necessrio pesquisar na tabela de fornecedores). Voc pode facilitar a entrada desse campo para o usurio permitindo a ele selecionar o fornecedor a partir de um lista de nomes. Para isso, no formulrio de produtos, apague o controle DBEdit que est sendo usado para o campo "CodFarnecedor". Vamos utilizar outro controle que o DBLookupComboBox ( ) da pgina Data Controls. Esse controle tem a capacidade de gravar valores em uma tabela e mostrar uma lista de valores de outra. Coloque um controle DBLookupComboBox no formulrio ao lado do rtulo "CodFornecedor". Altere o Caption do rtulo para "Fornecedor". No controle DBLookupComboBox, mude o nome para 'cboFornecedor'. Vamos alterar tambm as seguintes propriedades: DataSource para 'dsProduto', e DataField para 'CodFornecedor', ou seja, os mesmos valores do DBEdit anterior. Essas propriedades, como para qualquer controle de dados, dizem quais os dados que o controle vai acessar. Alm dessas propriedades, outras propriedades determinam de onde o controle busca a lista de valores a ser mostrada. Mas antes de alterar essas propriedades, precisamos criar novos componentes de dados no formulrio.

140

No formulrio de fabricantes (FormCadFornecedor), selecione o componente 'tblFornecedor' e o componente 'dsFornecedor' e tecle [Ctrl+C] para copi-los. Agora volte para o formulrio de produtos (FormCadProduto) e tecle [Ctrl+V]. Isso vai colocar no formulrio duas cpias dos componentes, que acessam a tabela FORNECEDOR. Isso necessrio para fornecer os valores mostrados por 'cboFornecedor'. Retornando ao componente 'cboFornecedor', altere as seguintes propriedades: Propriedade Valor dsFornecedor ListSource CodFornecedor KeyField Nome ListField A propriedade ListSource determina qual a tabela que ser usada para buscar os valores a serem mostrados. Como 'dsFornecedor' est ligado tabela FORNECEDOR.DB, os dados sero lidos desta tabela. O valor de KeyField (CodFornecedor, nesse caso) o nome do campo, na tabela FORNECEDOR, que corresponde ao campo DataField na tabela PRODUTO. Finalmente ListField determina qual o campo que ser mostrado na lista, nesse caso, Nome. Falta um detalhe: voc deve ativar a tabela de fornecedores, 'tblFornecedor' nesse formulrio. Acrescente o seguinte no procedimento do evento OnCreate do formulrio: begin tblProduto.Open; tblFornecedor.Open; end; Agora execute o programa. Repare que voc pode selecionar o fornecedor pelo nome agora. Se voc quiser mostrar o cdigo tambm, alm do nome, voc pode alterar a propriedade ListField para incluir mais de um campo. Para isso, coloque os nomes dos campos, separados por ";" (sem espao entre os nomes e o ponto-e-vrgula). No nosso caso, coloque "Nome;CodFornecedor" em ListField e execute o programa. Quando a lista est fechada, aparece apenas o nome do fornecedor, mas quando voc abre a lista, vo aparecer os dois campos: nome e cdigo.

141

Captulo 16 Utilizando Mestre/Detalhe


Criando um Formulrio Mestre/Detalhe Usando Trs Tabelas no Formulrio

142

Criando um Formulrio Mestre/Detalhe


Uma situao muito comum na utilizao de bancos de dados o relacionamento entre duas tabelas, onde uma tabela tem um registro que se relaciona com vrios registros de outra. No Delphi, isto chamado de relacionamento mestre/detalhe [master/detail]. A tabela mestre aquela que tem um nico registro fazendo parte do relacionamento. A tabela detalhe aquela que tem vrios registros relacionados. No nosso caso, um cliente possui vrios registros de venda relacionados (1-N). A tabela Cliente ser a tabela mestre e a tabela Venda ser a tabela detalhe.

Usando o DFW para criar o formulrio


O Database Form Wizard pode criar automaticamente um formulrio mestre/detalhe, basta voc informar as tabelas e quais os campos relacionados. No nosso caso, usaremos a tabela Cliente como mestre e a tabela Venda, criada anteriormente, como detalhe. Esse formulrio ser criado no projeto VENDA.DPR , portanto ele tem que estar aberto. No menu Database|Form Wizard.... Na primeira tela, no primeiro grupo de opes, selecione a segunda opo, "Create a master/detail form" e clique em Next. Na prxima tela, voc deve escolher a tabela mestre. Primeiro clique na lista "Drive or Alias name" e selecione "CursoDelphi", o nome de alias que for criado anteriormente. Agora, na lista de tabelas, escolha CLIENTE.DB e clique em Next. Depois selecione apenas os campos CodCliente e Nome (clique no campo e no boto ">"). Na prxima tela, escolha um layout horizontal para o formulrio. Agora voc deve selecionar a tabela detalhe. Selecione a tabela VENDA.DB, e na outra tela adicione todos os campos (clique no campo e no boto ">>"). Na prxima tela, escolha o layout "Grid". Isso vai colocar um controle DBGrid na parte "detalhe" do formulrio, em vez de controles de dados separados, este componente permite visualizar vrios registros ao mesmo tempo.. Por ltimo, o Database Form Wizard vai perguntar quais os campos que compem o relacionamento entre as tabelas. A tabela detalhe deve ter um ndice definido para o campo que faz o relacionamento. A lista dos ndices disponveis aparece abaixo de "Index Name". Selecione o ndice "CodCliente", que foi criado quando colocamos a restrio de integridade . Agora, na lista da esquerda, aparece o campo "CodCliente" (se o ndice tivesse mais de um campo, todos estariam na lista). Selecione o campo. Na lista da direita, aparecem os campos da tabela mestre. Selecione o campo que tem o mesmo nome, "CodCliente". A tela do DFW ficar como a seguinte:

Isso define o seguinte relacionamento entre as tabelas:

143

Agora clique em Next e depois no boto "Finish". O formulrio ser adicionado com as opes definidas.

Testando o Formulrio Gerado


Execute o programa, e veja como funciona o relacionamento mestre/detalhe. Na parte "detalhe" do formulrio (o controle DBGrid da parte inferior), voc pode adicionar registros que estaro automaticamente relacionados com o registro de cliente que aparece na parte superior. Se voc usar o DBNavigator do topo do formulrio para mudar de registro na tabela mestre, os registros de detalhe que aparecem embaixo sero diferentes. Como a tabela Venda no continha dados, inicialmente nenhum cliente tem registros associados. Note que o campo "CodCliente", que define o relacionamento com o cliente, aparece no Grid. Quando voc comea a incluir um registro, ele preenchido automaticamente de acordo com o valor do cdigo do cliente atual. Se voc alterar esse campo manualmente, o registro vai desaparecer da lista, pois vai estar relacionado com outro cliente. Aps entrar com alguns dados, finalize a execuo.

Analisando o Formulrio
Vejamos exatamente como definido o relacionamento mestre/detalhe pelo DFW. Como antes, so utilizados os componentes Table e DataSource, s que desta vez existem dois componentes Table e dois DataSource, todos no topo do formulrio, ao lado do DBNavigator, como na figura:

O primeiro 'Table1', est associado com a tabela CLIENTE.DB, atravs da propriedade TableName. O 'DataSource1' est ligado com 'Table1', atravs da propriedade DataSet. De forma anloga, os outros dois acessam a tabela de vendas: Table2.TableName tem o valor "VENDA.DB" e DataSource2.DataSet Table2. Os dois controles DBEdit da parte superior do formulrio esto ligados ao DataSource1 e o controle DBGrid da parte inferior est ligado ao DataSource2. Vamos alterar os nomes desses componentes de dados, para facilitar o entendimento. Mude os nomes para os seguintes:

Alm das ligaes que j vimos, num formulrio mestre/detalhe, preciso relacionar as duas tabelas. Isso feito com propriedades que ligam 'tblVenda' (antes Table2) a 'dsCliente' (antes DataSource1). Selecione o componente 'tblVenda' e veja que a propriedade MasterSource est ligada com 'dsCliente'. Isso define qual tabela ser a mestre para essa tabela. A propriedade MasterFields diz qual o campo (ou campos, se mais de um) na tabela mestre, que faz o relacionamento, e nesse caso "CodCliente". A propriedade IndexFieldNames, nesse caso, define qual o campo (ou campos) na tabela detalhe, que faz o relacionamento com o outro, e nesse caso tem o mesmo nome, "CodCliente" (mas no obrigatrio que tenha o mesmo nome).

144

Nota: O valor que aparece na propriedade DataSet o nome do outro componente, mas para propriedades de ligao, o Delphi guarda internamente um ponteiro de objeto, independente do nome. Tente executar o programa o Delphi vai mostrar um erro de compilao dentro do procedimento de evento 'FormCreate' , que foi criado pelo Database Form Wizard. Os dois comandos, "Table1.Open" e "Table2.Open", so para abrir as duas tabelas em tempo de execuo. Eles no funcionaro mais, porque voc alterou os nomes dos componentes Table. Substitua pelo seguinte: begin tblCliente.Open; tblVenda.Open; end; Notas: Os comandos existente no procedimento de evento OnCreate sero executados no momente que o formulrio for criado.

Alterando Propriedades do Formulrio


Vamos alterar algumas caractersticas desse formulrio. Ao executar observe que ele permite alterar registros da tabela mestre, no caso a tabela de clientes. Mas voc pode proibir esse tipo de alterao. A forma mais simples de fazer isso alterar a propriedade ReadOnly de 'tblCliente' para o valor True. Isso probe qualquer forma de alterao na tabela, seja edio, incluso ou excluso de registros. Com isso, alguns botes do DBNavigator, como , , , e , que fazem alteraes na tabela, estaro sempre desabilitados e no tm mais funo. Por isso vamos remov-los do DBNavigator. Selecione o controle e a propriedade VisibleButtons. Essa uma propriedade de conjunto que determina quais botes so visveis. Clique duas vezes no nome da propriedade para expandir os elementos do conjunto. Cada um deles corresponde a um boto do DBNavigator. Altere para False os elementos nbInsert (afeta o boto ), nbDelete

( ), nbEdit ( ), nbPost ( ) e nbCancel ( ). No DBGrid da parte inferior, o campo 'CodCliente' est disponvel para visualizao e edio, mas ele sempre ter o mesmo valor que o campo CodCliente da parte superior, portanto vamos torn-lo invisvel. Para tornar o campo invisvel, clique duas vezes no componente 'tblVenda' para abrir o editor de campos. Selecione o campo CodCliente. No remova da lista, seno o Delphi no vai conseguir manter o relacionamento. Apenas altere sua propriedade Visible para False. Altere o Caption do formulrio para "Clientes e Vendas" e a propriedade Name para formCadCliVend . Altere tambm o label "CodCliente", para "Cdigo". Se quiser, reduza o tamanho do painel que contm os controles de edio para a tabela de clientes. Voc deve clicar na borda mais espessa e no no fundo do painel. Execute o programa e verifique que agora no possvel editar os campos da tabela de clientes, apenas adicionar e remover registros de vendas relacionados.

Salvando o Projeto
Salve esse projeto como CADCLIVEND.

145

Usando Trs Tabelas no Formulrio


Com o Database Form Wizard s possvel criar um formulrio mestre/detalhe para no mximo duas tabelas. Algumas situaes exigem tratar um relacionamento mestre detalhe detalhe, com trs tabelas, ou dois relacionamentos mestre/detalhe no mesmo formulrio. Para isso preciso criar manualmente os relacionamentos, alterando as propriedades MasterSource e MasterFields do componente Table. Agora vamos relacionar a tabela de vendas com a tabela de itens vendidos (ITEM), que contm informaes sobre cada item individual vendido.

Ligando os Componentes de Dados


Abra o projeto anterior, VENDA.DPR, se ele j no estiver aberto no Delphi. Ns precisamos alterar o formulrio de clientes e vendas. Primeiro adicione ao formulrio mais um componente Table e mais um DataSource. Para o componente Table, altere as seguintes propriedades: Name para 'tblItem', DatabaseName com o nome do alias, "CursoDelphi" e, TableName com o nome da tabela "ITEM.DB" (note que a lista de valores de TableName mostra as trs tabelas). Para cada registro de venda, haver vrios registros de item de venda, relacionados atravs do campo "CodVenda". Para fazer esse relacionamento, altere a propriedade MasterSource, selecionando da lista o 'dsVenda'. Isso define qual a tabela mestre para esta. Agora clique na propriedade MasterFields e no boto de reticncias. Deve aparecer uma caixa de dilogo, onde voc pode facilmente definir o relacionamento, bem semelhante ao que aparece no Database Form Wizard. Em "Available indexes", selecione o ndice "IndVenda". Nas listas abaixo, selecione o campo "CodVenda" em cada uma e clique no boto Add. Depois clique em Ok. Isso vai alterar automaticamente a propriedade IndexFieldNames para conter "CodVenda", e MasterFields contm "CodVenda" tambm. Ambas definem os nomes dos campos que participam do relacionamento. Agora selecione o componente DataSource que voc colocou por ltimo. Mude o seu nome para 'dsItem' e na propriedade DataSet, selecione 'tblItem' para lig-lo com o ltimo componente Table. No evento Oncreate do formulrio coloque tblitem.open;

Criando Controles de Dados


Vamos ampliar o formulrio para incluir um grid para a tabela de itens. Mas antes de fazer isso, precisamos alterar propriedades do painel que contm o grid da parte inferior. Clique no grid de vendas e tecle [Esc] para selecionar seu painel. Altere sua propriedade Align para 'alTop'. O valor anterior era 'alClient', que alinhava o painel de acordo com o espao disponvel no formulrio. Clique no quadrado de seleo inferior e arraste-o para reduzir o tamanho vertical do painel. Isso vai deixar um espao vazio na parte inferior do formulrio. Se preciso, aumente o formulrio na vertical para aumentar essa rea. Para manter a aparncia do formulrio, selecione a pgina Standard e o componente , que o ltimo cone. Coloque um componente na parte inferior. Esse um Panel, controle cuja finalidade geralmente s a de conter outros controles. Altere suas propriedades da seguinte forma: Propriedade Valor Efeito (vazio) tira o texto "Panel2" Caption bvLowered efeito 3-d interno "afundado" BevelInner aumenta a borda BorderWidth 4 alClient preenche o espao disponvel Align Agora, selecione a pgina Data Controls na paleta de componentes e selecione o DBGrid ). Coloque-o em cima do painel. Altere sua propriedade Align para 'alclient', para que ele ( ocupe o espao do painel e BorderStyle para 'bsNone', para remover a borda preta em volta

146

do controle. Altere tambm DataSource para 'dsItem'. Com isso, a grade vai mostrar os dados da tabela de itens e permitir alterao. Para que o campo 'CodVenda' no aparea na grade, selecione o componente 'tblItem' e clique duas vezes para abrir o editor de campos. Adicione todos os campos, selecione 'CodVenda' na lista e altere a propriedade Visible para False.

Criando Campos Calculados


Usando um componente Table, voc pode mostrar, alm dos campos da tabela, campos calculados, que aparecem da mesma forma que campos do registro, mas sem permitir alterao. O valor de um campo calculado definido pelo cdigo do seu programa. Quando o Delphi precisa mostrar um campo calculado, ele aciona o evento OnCalcFields do componente Table. No nosso caso, a tabela de itens ter um campo calculado. O preo de venda do item um preo unitrio, que deve ser multiplicado pela quantidade de itens vendidos. Para isso, vamos criar um novo campo PrecoTotal contendo esse resultado. No formulrio, clique duas vezes no componente 'tblItem', para abrir o editor de campos. Para definir um novo campo calculado, clique com o boto direito e em "New Field...". Voc deve definir um nome para o campo. Digite "PrecoTotal". O nome do componente TField criado automaticamente como "tblItemPrecoTotal", mas voc pode mudar se precisar. Voc deve tambm escolher um tipo de dados para o campo. Escolha "FloatField" na lista (tipo real) e clique Ok. Todos os componentes TField tm nomes baseados no nome do componente Table ao qual eles pertencem, como "tblItemCodVenda" etc. Esses nomes podem ser alterados, se necessrio, selecionando o componente na lista e alterando sua propriedade Name. Para definir o valor de um campo calculado no programa, precisamos saber o nome dos componentes utilizados. Para realizar o calculo do Preo Total necessrio ter o preo de venda do produto, portanto vamos acrescentar um componente Table e um DataSource, que estaro associados com a tabela "Produto.db". Para o componente Table, altere as seguintes propriedades: Name para 'tblProduto', DatabaseName com o nome do alias, "CursoDelphi" e, TableName com o nome da tabela "PRODUTO.DB". Clique duas vezes no componente 'tblProduto', para abrir o editor de campos.Para adicionar os objetos de campos clique em "Add..." em seguida clique no boto 'Ok'. Agora selecione o componente 'tblItem' e crie um procedimento para o seu evento OnCalcFields. Esse procedimento executado a cada vez que um registro da tabela mostrado. Durante a sua execuo, voc pode atribuir valores para campos calculados, como 'tblItemPrecoTotal'. Digite o seguinte: begin if tblproduto.FindKey([tblitemCodProduto.value]) then tblItemPrecoTotal.Value := tblItemQuantidade.Value * tblProdutoPrecoVenda.Value; end; Para ler ou alterar o valor de um componente TField, leia ou altere sua propriedade Value. O tipo dessa propriedade depende do tipo de dados do campo. Como o Preco de Venda do produto est na tabela produto necessrio obter o valor desta tabela, portanto, utilizamos o mtodo FindKey para posicionarmos no produto que estamos querendo o preo. E o objeto de campo "PrecoTotal" ser o valor da quantidade vendida multiplicada pelo preo de venda do produto. Ao invs de ficar mostrando o cdigo do produto , iremos tambm mostrar o nome do produto, para isto temos que criar um outro campo LooKup, mas este ser mostrado o campo nome da tabela produto.

Usando um campo Lookup


Para mostrar o nome do produto , vamos criar um campo Lookup.Um campo Lookup traz dados de uma outra tabela relacionada. Neste caso, o campo ir buscar um registro na tabela de produto, atravs do campo CodProduto, e mostrar o nome do produto.

147

Para inserir um campo Lookup, clique duas vezes em 'tblItem' para abrir o editor de campos. Clique com o boto direito e selecione "New Field...". Em "Name", especifique "NomeProduto", em "Type" selecione "string", em "Size" informe 50. Marque a opo "Lookup". Agora em "Key Fields", selecione "CodProduto" .Esse o campo que ser usado para buscar o produto na outra tabela. Em "DataSet", selecione "tblProduto", que a tabela de onde ser buscado os dados. Finalmente , em "LooKup Keys", selecione "codproduto" este o campo que ser utilizado para fazer o relacionamente da tabela produto com a tabela item e em "Result Field" coloque nome (o campo de resultado que ser mostrado). As propriedades estaro como abaixo:

Arraste o campo LookUp 'NomeProduto' , para a primeira posio e o campo 'PrecoTotal' coloque-o na ltima posio, como na figura abaixo:

Testando e Salvando o Projeto


Para que o usurio possa acessar o formulrio de vendas , preciso mostrar esse formulrio a . partir do menu principal. Para isso , retorne ao formPrincipal. Voc pode usar o boto Agora, acrescente o seguinte cdigo ao evento Onclick do item de menu Cadastro|Vendas: procedure TformPrincipal.menuCadVendasClick(Sender: TObject); begin formCadCliVend.show end;

148

Para funcionar, voc precisa adicionar uma clusula uses, no incio da seo de implementao (implementation) do formulrio. Adicione o seguinte: uses CadCliVend Agora execute o programa para ver o efeito das modificaes. Note que no grid da tabela Item, o campo calculado PrecoTotal , os campos LooKup PrecoVenda e Nome vo aparecer para cada registro. Se voc alterar os campos Quantidade , PrecoVenda ou o Produto, o evento OnCalcFields ser executado, e o valor do campo ser alterado. Na verdade, esse evento executado para qualquer alterao de campo, mesmo os que no afetam seu valor. Finalize a execuo e salve o projeto novamente.

Atualizando Quantidade em Estoque


Ao realizar uma venda de um determinado produto, necessrio atualizar a quantidade disponvel em estoque. Ento antes de salvar os dados na tabela de item, iremos atualizar a tabela de produto. O evento que ocorre antes de gravar um determinado registro o evento OnBeforePost, crie um procedimento para este evento na tabela 'tblItem', e acrescente o cdigo a seguir: procedure TformCadCliVend.tblItemBeforePost(DataSet: TDataSet); begin if not tblproduto.findkey([tblItemCodProduto.value]) then begin showmessage('Produto no encontrado!'); abort; end; tblproduto.edit; if tblItem.State in [dsEdit] then tblProdutoqtdEstoque.value := tblprodutoqtdEstoque.value + QuantidadeAnterior; if tblitemquantidade.value > tblprodutoqtdEstoque.value then begin showMessage('Quantidade Insuficiente no Estoque!'); tblProduto.cancel; if tblitem.State in [dsEdit] then tblItem.Cancel. tblItemQuantidade.FocusControl; abort; end else tblProdutoqtdEstoque.value := tblprodutoqtdEstoque.value - tblItemQuantidade.value; tblproduto.post; end; O mtodo FindKey foi utilizado para verificar se o produto includo existe, caso no exista ir aparecer uma mensagem e o procedimento ser abortado. Quando o procedimento OnBeforePost abortado o evento OnAfterPost no ocorre, portanto, a venda no ser efetuada. O mtodo Edit foi utilizado para colocar a tabela 'Produto' em modo de Alterao , com isso pode ser feito alteraes em qualquer campo desta tabela . Antes de atualizar o campo 'QtdEstoque' , necessrio verificar se a tabela 'Item' esta sendo alterada, caso esteja , o campo alterado 'Quantidade' ( pois o nico campo que iremos permitir alterao) , portanto, temos que adicionar o valor antigo ao estoque , para depois retirar a quantidade desejada, o valor antigo foi armazendo na varivel QuantidadeAnterior. Em seguida feito uma verificao se o valor que esta sendo vendido maior que o estoque existente, se isso ocorrer no podemos permitir a venda do item, ento cancelamos a alterao feito na tabela produto(est alterao ocorre somente se o campo 'quantidade' da tabela item esta sendo alterado) , cancelamos tambm as alteraes da tabela item , caso ela esteja em modo de edio e em seguida abortamos o procedimento. Caso no tenha ocorrido nenhum dos problemas citados

149

anteriormente, finalmente podemos subtrair a quantidade vendida pela quantidade existente no estoque. Para atualizar o estoque estamos considerando que o nico campo que possa ser alterado da tabela 'Item' o campo 'Quantidade', para fazer a alterao do produto necessrio excluir o item de venda e incluir novamente. No iremos aceitar modificao no campo 'codproduto' da tabela 'item', vamos criar um procedimento no evento OnChange do objeto 'tblItemQuantidade', para criar este procedimento clique duas vezes na tabela 'Item', com isso ir abrir o editor de cdigo, escolha o campo 'Quantidade', no 'Object Inspector ', clique na pgina 'Events', em OnChange, acrescente o cdigo a seguir: procedure TformCadCliVend.tblItemCodProdutoChange(Sender: TField); begin if tblItem.state in [dsEdit] then begin showmessage('No permitido a alterao do produto!'); tblitem.cancel; abort; end end; Falta criar a varivel 'QuantidadeAnterior' e atribuir um valor, abaixo da seo implementation acrescente: Var QuantidadeAnterior : integer; Essa varivel ir conter o valor do campo 'Quantidade' antes de ser modificado, crie um procedimento para o evento OnBeforeEdit, este evento ocorre antes de fazer modificaes nas tabelas, neste procedimento coloque: procedure TformCadCliVend.tblItemBeforeEdit(DataSet: TDataSet); begin Quantidadeanterior := tblItemQuantidade.value; end; Quando o item for excludo , temos que acrescentar a quantidade que foi retirada ao estoque, portanto, no evento OnBeforeDelete (antes de excluir) , coloque o procedimento abaixo: procedure TformCadCliVend.tblItemBeforeDelete(DataSet: TDataSet); begin if tblproduto.findkey([tblItemCodProduto.value]) then begin tblproduto.edit; tblProdutoqtdEstoque.value := tblprodutoqtdEstoque.value + tblItemQuantidade.value; tblproduto.post; end; end; Neste procedimento realizado uma procura do produto pertencente ao item , caso o produto seja encontrado , ser adicionado ao campo 'qtdEstoque' a quantidade do item excludo.

150

Captulo 17 Consultas e SQL


Exemplo: Usando Consultas Exemplo: Consultando Vrias Tabelas Outros Comandos SQL Consultas num Ambiente Cliente/Servidor Mtodos e Eventos do Componente Query

151

Exemplo: Usando Consultas


O componente - Query usado para obter dados baseados em um comando SQL. Ele pode ser usado em situaes onde uma tabela no seria suficiente, por exemplo: Acessar um subconjunto da tabela, em vez de todos os registros (isso fundamental para ter bom desempenho num ambiente cliente/servidor) Reunir dados de mltiplas tabelas (junes) Totalizaes de dados de vrios registros A forma mais fcil de usar um componente Query usar o Database Form Expert para criar um formulrio.

Criando o Formulrio
Abra o projeto VENDAS.DRP e acione o menu Database |Form Wizard.... Na primeira tela do DFW, mantenha a opo "Create a simple form" na parte superior, mas na parte de baixo selecione "Create a form using TQuery objects". Clique em Next. Na prxima tela, na lista "Drive or alias", selecione CursoDelphi. Na lista de tabelas, selecione a tabela VENDA.DB, depois selecione todos os campos e escolha o layout "In a grid". Na ltima tela, desmarque a opo "Generate a main form" e clique em Finish. O formulrio gerado semelhante aos que j criamos com o DFW, mas ele utiliza um componente Query em vez de um Table. Os componentes de dados esto no topo do formulrio: Query1 DataSource1 Selecione o componente 'Query1' e veja suas propriedades. Note que o 'DataSource1' tem na propriedade Dataset o valor 'Query1'. Isso faz a ligao entre os dois. Vamos alterar os nomes dos componentes para 'qryVenda' e 'dsVenda', respectivamente. Depois altere tambm o cdigo do evento OnCreate do formulrio, para abrir 'qryVenda' em vez de 'Query1'. A propriedade mais importante do componente Query a propriedade SQL. Essa propriedade uma lista de strings (TStrings), que contm um comando da linguagem SQL. Clique em SQL e no boto com reticncias. Repare que o contedo da propriedade o seguinte: Select venda."CodVenda", venda."CodCliente", venda."DataVenda" From "c:\cursodelphi\venda.DB" As venda O comando select um comando SQL que consulta registros. Primeiro so especificados os campos da tabela que sero retornados pelo select. Depois do from, vem o nome da tabela. Nesse caso, um nome completo, incluindo subdiretrio. A expresso "as Venda" cria um apelido para a tabela dentro do comando, que utilizado anteriormente, na lista do select (Venda."CodCliente", por exemplo). Clique OK para fechar o editor de strings. Altere a propriedade Name do formulrio para 'formConsVendasporCliente' e a propriedade Caption para 'Vendas por Cliente". Para o usurio poder visualizar esse fomulrio temos que cham-lo no evento Onclick do menu Consultas|Vendas por Cliente da Unit VendPrin. Neste evento coloque o cdigo abaixo: formConsVendasporCliente.show; Para isso funcionar, voc precisa adicionar uma clusula uses , no incio da seo implementation do formulrio VendPrin. adicione o seguinte: uses ConsVendasCliente; Salve o formulrio criado como "CONSVENDASCLIENTE.PAS". Execute o programa e veja o resultado: voc pode percorrer os registros da tabela, mas no pode alter-los.

152

Obtendo um Resultado Modificvel


Uma consulta geralmente retorna um resultado que no modificvel, ou seja, registros apenas para leitura. Mas voc pode pedir ao Delphi para retornar um conjunto de registros modificvel ["live" result set], que permite acessar a tabela como atravs de um componente Table. Para isso, altere a propriedade RequestLive do componente Query para True. Quando esta propriedade verdadeira, o componente vai tentar retornar um conjunto de registros modificvel, mas nem sempre isso possvel. Em tempo de execuo, voc pode verificar se a consulta modificvel, consultando sua propriedade CanModify (do tipo boolean). Execute o programa e agora voc deve ser capaz de fazer alteraes nos registros.

Simplificando o Select
O comando select, que retorna os dados, pode ser simplificado, e podemos evitar que o diretrio da tabela seja codificado de forma fixa. Abra novamente a propriedade SQL e substitua todas as linhas do comando pelo seguinte: select * from Venda Voc pode colocar os comandos na mesma linha, ou em linhas separadas. O "*" (asterisco) no select em vez de uma lista de campos seleciona todos os campos da tabela, independentemente da estrutura dessa tabela. Note que no preciso colocar a extenso de arquivo (.DB) e melhor no colocar porque isso torna mais fcil alterar o programa para trabalhar com outros formatos de dados (onde tabelas no so arquivos). Execute o programa e repare que ele continua funcionando como antes.

Alterando a Consulta
Uma consulta que retorna todos os registros no realmente muito utilizada. A principal funo de consultas restringir os registros retornados a um subconjunto dos dados. Para fazer isso, vamos alterar a propriedade SQL novamente, acrescentando uma clusula where ao final: select * from Venda where DataVenda = '08/02/98' Isso vai retornar todos os registros onde o campo DataVenda tenha o valor '02/08/98', e apenas esses registros. Observe que a data deve ser informada como 'mm/dd/yy' . Execute o programa e veja o resultado. Note que se voc alterar o valor do campo DataVenda, e salvar o registro, o registro vai desaparecer do resultado. Quando o tipo do campo for data ou Caracter a condio deve ser passada entre apstrofos, caso seja um valor numrico especifique somente o nmero. Nota: na sintaxe do SQL, para inserir um texto, voc pode usar " (aspas) ou ' (apstrofos).

Alterando a Consulta Dinamicamente


A consulta como est uma consulta esttica, ou seja, a condio de seleo de registros nunca muda, porque est usando um valor constante, '08/02/98'. Voc pode fazer tambm uma consulta dinmica, e alterar a condio em tempo de execuo. Para fazer isso, vamos alterar a propriedade SQL para incluir um parmetro no lugar da constante '08/02/98'. Um parmetro uma varivel dentro do comando SQL, que voc pode alterar dinamicamente. Altere o SQL para o seguinte: select * from Venda where DataVenda = :ValorData Isso cria um parmetro chamado 'valorData'. O que define o parmetro so os dois-pontos antes do nome. Depois de fazer essa alterao, clique Ok. Nota: No deve haver nenhum espao entre o dois-pontos e o nome do parmetro. Agora selecione a propriedade Params e abra o seu editor. O editor de parmetros, que vai aparecer, onde voc define qual o tipo de dados a ser usado pelo parmetro, primeiro deve-se escolher o parmetro e ir no object inspector:

153

Expande a propriedade Value em type escolha "Date", que ser o tipo de dados do campo , ao confirmar o Object Inspector ira ficar como a figura abaixo:

Notas: Nos parmetros colocamos as datas sendo 'dd/mm/yy', pois, nos parmetros as datas so do tipo date e ao passar para a linguagem SQL o Delphi coloca no formato que o SQL utiliza. Em "Value" voc pode, opcionalmente, fornecer um valor inicial para o parmetro, ou marcar a opo "Null Value", que significa que ele comea com o valor nulo, ou vazio. Nesse caso digite "02/08/98" e depois clique Ok. Precisamos de uma interface para alterar o parmetro dinamicamente. Na pgina ) e coloque um controle no formulrio, em Standard, selecione o cone do GroupBox ( qualquer espao vazio. Altere sua propriedade Caption para "Parmetros". Agora crie controles dentro do GroupBox "Parmetros", dentro dele acrescente o ) , seu funcionamento idntico ao Edit a diferena que ele componente MaskEdit ( permite utilizar mscaras. Altere a propriedade Name para mskDataVenda, clique na reticncias da propriedade EditMask e escolha a opo "Date", substitua os '0' por '9', em seguida clique em "Ok", com uso definimos uma mscara para o componente de edio. Acrescente um componente Button e um Label , conforme a figura abaixo:

154

Chame o boto de 'btnAlterar' e mude a sua propriedade Default para True. No cdigo associado ao 'btnAlterar', alterar os parmetros, e abrir a consulta novamente com os parmetros modificados. Com isso o usurio pode realizar a consulta para qualquer data. Digite o seguinte: begin try with qryvenda do begin Close; Params[0].AsDate := strtodate(mskDataVenda.Text); Open; end; except on EConvertError do begin showmessage('Data Invlida!'); mskDataVenda.setfocus; end; end; end; Como feito uma converso de String para Date, foi feito o tratamento de exceo , pois, se a pessoa informar uma data invlida iremos mostrar a mensagem de erro 'Data Invlida'. A propriedade Params do componente Query um vetor de objetos do tipo TParam, com ndices comeando de zero. Cada um desses objetos tem propriedades como AsString, AsInteger, ... que permitem alterar o valor do parmetro. Execute o programa e veja o que acontece quando voc altera os parmetros. Nota: Outra forma de alterar o parmetro usando a funo-mtodo ParamByName, fornecendo o nome do parmetro em vez de sua posio na lista. Por exemplo, o cdigo abaixo tambm acessa o parmetro valorData: ParamByName('valorDAta').AsDate := strtodate(mskDataVenda.Text);

Alterando Outras Partes da Consulta


Os parmetros permitem que voc substitua constantes dentro da consulta por variveis do programa, mas se voc precisar alterar a estrutura da consulta, precisa alterar a propriedade SQL em tempo de execuo. Essa propriedade uma string list, que pode ser utilizada com os

155

mtodos de string lists j vistos. O exemplo abaixo mostra como mudar a propriedade SQL dinamicamente : with qryCliente.SQL do begin Clear; Add('select * from Cliente'); Add('where Estado = "' + estado1 + '"'); Add('or Estado = "' + estado2 + '"'); end; Ao abrir o componente QryCliente , a consulta ir mostrar os clientes que pertencem ao intervalo de estados pedidos. No faremos isso neste projeto, e na maioria das vezes isso no necessrio.

Exemplo: Consultando Vrias Tabelas


Tendo os nossos dados sobre clientes, vendas e itens, imagine que precisamos fazer o seguinte: consultar todos os itens vendidos para cada cliente para uma data especfica. Para isso, podemos usar um comando select do SQL envolvendo vrias tabelas, chamado de juno de tabelas.

Consulta com Duas Tabelas


Como no exemplo anterior realizamos uma consulta que mostra as vendas e os cdigos dos clientes, vamos mostrar o nome do cliente, para isto temos que alterar a propridade SQL do componente QryVenda . Como queremos mostrar o nome do cliente temos que utilizar a tabela 'cliente' na clausula from da consulta.Altere a propriedade SQL de acordo o comando abaixo: select cli.Nome, vend.CodVenda from CLIENTE cli, VENDA vend where cli.CodCliente = vend.CodCliente order by cli.Nome Notas: Quando o comando Select utiliza mais de uma tabela, o componente Query no permite alteraes dos dados. Note que na clusula from, os nomes das tabelas esto seguidos de nomes mais curtos, que so os apelidos [alias] utilizados para as tabelas dentro do SQL. Esses apelidos afetam apenas o comando atual. A lista de campos do select seleciona o campo Nome da tabela 'cli' (apelido de "CLIENTE.DB") e o campo CodVenda da tabela 'vend' (apelido de "VENDA.DB"). A condio cli.CodCliente = vend.CodCliente na clusula where importante numa juno de tabelas. Ela diz qual a ligao entre elas. Se no for especificada, a consulta vai funcionar, mas vai retornar o produto cartesiano das duas tabelas, ou seja, todas as combinaes possveis com o registro de uma e o registro da outra tabela. A clusula order by determina que o resultado ser ordenado pelo campo Nome da tabela CLIENTE.DB. Coloque a propriedade Active do componente qryVenda para true. Com isso ir aparecer a seguinte mensagem:

Isso ocorre porque antes de fazer a modificao na propriedade SQL , foi criado um objeto de campo para o cdigo do cliente , com a alterao foi retirado o campo, mas como o objeto ainda existe. Ele continua procurando o campo 'codcliente', para resolver o problema clique duas vezes no componente 'qryVenda' para abrir o objeto de campo, remove todos os objetos de campos existentes.

156

Altere a propridade Active para true e observe que cada registro do resultado tem o valor do campo Nome e do campo CodVenda. Existem vrios registros de resultado para cada cliente, ou seja, com o nome do cliente repetido, mas com cdigos de venda diferentes.

Consultando Trs Tabelas


Para adicionar mais uma tabela na consulta, a tabela de itens de venda, vamos alterar o select, acrescentando o nome da tabela e a condio de ligao. Desta vez vamos obter no resultado apenas o campo Nome da tabela de clientes e o campo Quantidade, da tabela de itens. Na propriedade SQL, digite o seguinte: select cli.Nome, item.Quantidade from CLIENTE cli, VENDA vend, ITEM where cli.CodCliente = vend.CodCliente and vend.CodVenda = item.CodVenda order by cli.Nome Repare que como so trs tabelas, temos duas condies de juno, uma ligando CLIENTE a VENDA e outra ligando VENDA a ITEM Quando voc altera a propriedade SQL, o componente automaticamente muda a propriedade Active para False, altere para True.

Usando Campos Calculados no SQL


Podemos ainda gerar um campo calculado para cada registro, que ser mostrado no resultado. Uma forma de fazer isso definindo campos calculados e usando o evento OnCalcFields. Mas quando se usa componentes Query, outra forma mais fcil usar expresses no SQL. Por exemplo, vamos calcular para cada item, o preo de venda multiplicado pela quantidade, gerando um campo calculado 'PrecoTotal', mas o preo de venda existe na tabela produto, portanto iremos acrescentar tambm a tabela produto. Altere a lista de campos do select para o seguinte: select cli.Nome, item.Quantidade , prod.precoVenda * item.Quantidade as PrecoTotal from CLIENTE cli, VENDA vend, ITEM, produto prod where cli.CodCliente = vend.CodCliente and vend.CodVenda = item.CodVenda and prod.codproduto = item.codproduto and datavenda =:ValorData order by cli.Nome Depois da expresso colocado um "as PrecoTotal", que define um nome de campo para a expresso (seno no cabealho do campo vai aparecer a prpria expresso). Altere Active para True novamente e veja o resultado.

Usando Funes de Resumo


Em vez de retornar registros com o nome do cliente repetido, como est sendo feito, voc pode, usando SQL, agrupar vrios registros, retornando um registro de resumo, contendo, por exemplo, o total de algum campo. Para isso, voc deve usar a clusula group by do SQL, alm de funes de resumo do SQL. Por exemplo, para totalizar o produto de 'Quantidade' e 'PrecoVenda' para todos os itens relacionados a cada cliente, basta usar o seguinte comando: select cli.Nome, sum(item.Quantidade * prod.PrecoVenda) as TotalVenda from CLIENTE cli, VENDA vend, ITEM item, PRODUTO prod where cli.CodCliente = vend.CodCliente

157

and vend.CodVenda = item.CodVenda and prod.codproduto = item.codproduto and datavenda =:ValorData group by cli.Nome A funo sum uma funo de resumo (ou funo agregada) do SQL, que faz o somatrio de um campo ou expresso. A clusula group by define como so formados os grupos de registros para fazer a totalizao. Outras funes de resumo que podem ser usadas em vez de sum so: avg(campo) calcula a mdia de um campo max(campo) calcula o valor mximo do campo min(campo) calcula o valor mnimo do campo count(campo) conta os valores do campo, mas s considera registros onde o campo est preenchido count(distinct conta quantos valores distintos do campo existem (em [4 2 2 4 2 3], a campo) contagem seria 3). count(*) conta os registros

Outros Comandos SQL


O comando select um comando SQL de consulta, mas existem comandos SQL para atualizao de tabelas, que permitem atualizar diversos registros. Esses comandos so utilizados tambm atravs de um componente Query, mas de uma forma ligeiramente diferente, como veremos.

Testando Comandos SQL


Para executar um comando SQL de atualizao, como os que sero usados, voc pode usar o Database Explorer. Clique em Database|Explore, no menu do Delphi. Na rvore "Databases", abra o alias "CursoDelphi". Ao fazer isso, do lado direito aparece um marcador de pgina "Enter SQL":

Clique em

(Execute Query) para executar o comando.

Alterando Registros
Para alterar valores de registros, use o comando update. Com ele, basta fornecer a tabela, a condio de atualizao e as alteraes de campos a serem feitas. Por exemplo, o comando a seguir atualiza a tabela Cliente, preenchendo o campo Estado, com o valor 'GO', mas apenas nos registros onde Estado era vazio (is null verifica se o campo est vazio): update Cliente

158

set Estado = 'GO' where Estado is null

Excluindo Registros
Para excluir um conjunto de registros baseado numa condio, use o comando delete. Por exemplo, o seguinte comando exclui todos os registros da tabela Venda, que estejam entre 01/01/94 e 01/01/95: delete from Venda where DataVenda >= '01/01/94' and DataVenda <= '01/01/95' ou, de forma equivalente: delete from Venda where DataVenda between '01/01/94' and '01/01/95'

Inserindo e Copiando Registros


Para inserir um registro em uma tabela, voc pode usar o comando insert: insert into Produto (CodProduto, Nome, CodFabricante) values (1234, 'Novo Produto', 34) Mas geralmente essa forma no tem muita utilidade. Outra forma, que de mais ajuda na programao, permite copiar dados de uma tabela para outra. Para isso, use um comando select dentro do insert. Por exemplo, para copiar todos os registros da tabela Cliente que tem Estado = 'GO' ou 'TO', para uma outra tabela 'ClienteCentroOeste', pode-se fazer: insert into ClienteCentroOeste select * from Cliente where Estado in ('GO', 'TO') Esse comando assume que ambas as tabelas tm a mesma estrutura. Se no tiverem, voc pode alterar a lista de campos do select para incluir apenas os que esto presentes na tabela de destino, por exemplo: insert into ClienteCentroOeste select Codigo, Nome from Cliente where Estado in ('GO', 'TO')

Executando um Comando de Atualizao


Para usar um comando SQL de atualizao, coloque o comando na propriedade SQL de um componente Query. Mas existe uma diferena em relao ao select: um comando de atualizao no retorna resultado nenhum. Por isso, voc no deve abrir a consulta (alterando Active), e nem ligar o componente com um DataSource, por exemplo. Para executar o comando, voc deve chamar o mtodo ExecSQL do componente. Esse mtodo no retorna resultado e s pode ser acionado em tempo de execuo. Voc pode tambm preencher parmetros do componente antes de executar o comando. Por exemplo, suponha que voc quer apagar todos os registros de VENDA.DB entre uma data inicial e uma data final. Voc pode definir a propriedade SQL com o seguinte: delete from Venda where DataVenda between :dataIni and :dataFin e, no programa, executar o cdigo a seguir quando for excluir os itens: with qryApagaItem do begin ParamByName('dataIni').AsString := editDataIni.Text; ParamByName('dataFin').AsString := editDataFin.Text; ExecSQL; end;

Consultas num Ambiente Cliente/Servidor


Num ambiente cliente/servidor, consultas so a forma mais eficiente de acesso aos dados. Nesse tipo de ambiente, uma consulta envia o comando SQL ao servidor, para ser processado localmente. O servidor ento retorna apenas os registros pedidos. Se voc utilizar um componente Table, voc sempre estar acessando todos os registros, e isso traz as desvantagens que j vimos, de gerar trfego de rede.

159

Voc pode tambm usar expresses em comandos SQL, como vimos nos exemplos. A vantagem que o clculo da expresso feito no servidor, aliviando o processamento na estao, que recebe apenas os resultados. Funes de resumo tambm repassam parte do processamento para o servidor, que vai fazer toda a operao de totalizao e retornar os resultados. Quando voc usa comandos de atualizao, como update, o comando enviado ao servidor, que o processa localmente. Nesse caso, como ele no retorna resultados, o trfego entre a estao e o servidor o mnimo possvel.

Mtodos e Eventos do Componente Query


As classes de componentes TTable ( ) e TQuery ( ) so ambas derivadas de uma classe ancestral comum, chamada TDataSet. Quase todos os mtodos e eventos que vimos para o componente Table se aplicam tambm a um componente Query: Mtodos de abertura e fechamento: Open, Close. Mtodos e propriedades de movimentao: First, Next, Prior, Last, MoveBy, propriedades BOF e EOF. Mtodos de modificao: Edit, Insert, Post, Cancel, Delete. Note que se a consulta no retorna um resultado modificvel, no possvel utilizar esses mtodos, e a propriedade CanModify ter o valor False. Mtodos e propriedades de acesso a campos: FieldByName, propriedade Fields. Mtodos para os controles de dados: EnableControls, DisableControls. Eventos: Before..., After..., OnCalcFields, OnNewRecord.

160

Captulo 18 Instalador e Alias Local


Usando um Alias Local Criando um Programa Instalador

161

Usando um Alias Local


Se voc quisesse alterar o diretrio dos dados em tempo de execuo, teria que alterar a propriedade DatabaseName de todos os componentes de dados. Mas, como j vimos, um alias resolve esse problema: ele armazena a localizao do diretrio, evitando que sejam necessrias alteraes no programa. Mas um alias no pode ser criado dinamicamente pelo programa, e no resolve algumas situaes, como por exemplo, um programa que usa um diretrio diferente a cada vez que rodado. Para esse tipo de situao, voc pode usar um alias local. Um alias local funciona apenas dentro do seu programa, enquanto ele est rodando, e pode ser modificado durante a execuo.

Usando o Componente Database


O componente Database da pgina Data Access ( ) permite criar um alias local. No 'FormPrincipal', coloque um componente Database. Mude o seu nome para 'dbVendas'. Esse componente tem vrias propriedades, mas a forma mais fcil de alter-las usando o Database Editor. Clique duas vezes no componente para chamar esse editor. A janela do Database Editor semelhante seguinte:

Em "Name", voc digita o nome do alias local que voc est criando. Depois, se voc escolher um valor da lista "Alias name", seu alias local ser sinnimo para um alias j existente. Seno, voc deve escolher um driver de banco de dados em "Driver name" e alterar seus parmetros de configurao em "Parameter overrides". Repare que "Alias name" e "Driver name" so mutuamente exclusivas. No nosso caso, em "Name", digite "VENDAS". Esse ser o nome do nosso alias local. Na lista "Driver name", selecione "STANDARD" e clique no boto "Defaults". Esse boto preenche a lista de parmetros, de acordo com os parmetros de configurao do driver. No caso do driver "STANDARD", usado para bancos de dados locais, s importa o parmetro PATH. A lista vai mostrar uma linha com o parmetro PATH, sem valor definido: PATH= Na lista de parmetros, coloque o diretrio atual dos dados depois do parmetro: PATH=C:\CURSODF\TABELAS Isso basta para definir o alias local. As outras opes s tem utilidade em bancos de dados cliente/servidor, onde necessrio fornecer uma senha para conectar com o gerenciador de bancos de dados: "Login prompt", se ativo, mostra uma janela que requisita o nome de usurio e senha para conexo. E "Keep inactive connection", se ativado, diz para manter a conexo com o banco de dados mesmo quando ele no estiver sendo usado.

162

Clique Ok e repare que o Database Editor altera vrias propriedades do componente Database, de acordo com as opes escolhidas: DatabaseName fica com o valor "VENDAS", DriverName com o valor "STANDARD", LoginPrompt e KeepConnection com o valor True e Params (do tipo TStrings) com os parmetros. Note que o nome do alias (DatabaseName = "VENDAS") no necessariamente igual ao nome do componente (Name = "dbVendas").

Alterando os Componentes de Dados


Agora, vamos alterar a propriedade DatabaseName de cada um dos componentes Table dos formulrios do projeto. Para comear, no formulrio de fabricantes, selecione o componente 'tblFabricante' e clique na propriedade DatabaseName. O nome do alias local que foi criado, VENDAS, vai aparecer na lista de valores, juntamente com os aliases globais, como CursoDelphi. Selecione VENDAS na lista. Agora no formulrio de produtos, selecione ambos os componentes 'tblProduto' e 'tblFabricante' e altere DatabaseName para VENDAS. Faa o mesmo para todos os formulrios e seus componentes Table ou Query. Execute o programa e verifique que ele ainda continua funcionando. De agora em diante, se voc quiser alterar o diretrio onde esto os dados, basta alterar a propriedade Params do componente 'dbVendas' no formulrio principal, em tempo de projeto. Mas a verdadeira utilidade deste componente permitir alterar a localizao dos dados em tempo de execuo.

Alterando o Caminho em Tempo de Execuo


A propriedade Params do componente 'dbVendas', no formulrio principal, contm uma lista de valores de parmetros de configurao. Essa uma propriedade do tipo string list, que pode ser manipulada com os mtodos j vistos para string lists. Vamos alterar o caminho do diretrio dinamicamente, de acordo com o diretrio onde est o programa executvel. Com isso, o programa vai sempre encontrar os dados, desde que os arquivos de dados estejam no mesmo diretrio. No formulrio principal, acrescente no procedimento do evento OnCreate, os cdigos abaixo: var diretorio: string; begin diretorio := ExtractFilePath(Application.EXEName); dbVendas.Connected := False; dbVendas.Params[0] := 'PATH=' + diretorio + 'tabelas\'; end; O objeto Application tem a propriedade EXEName, que contm o caminho completo do arquivo executvel. Usamos essa propriedade com a funo ExtractFilePath, para extrair apenas a parte do diretrio. Depois alteramos a primeira linha da propriedade Params, de 'dbVenda', para utilizar esse diretrio. A propriedade Connected do componente Database "ativa" o banco de dados, assim como Active faz para uma tabela. No normalmente necessrio alterar essa propriedade manualmente, porque o componente Table j faz isso automaticamente. Mas num ambiente cliente/servidor, geralmente melhor alter-la no incio da execuo. Para alterar os parmetros, ela deve estar com o valor False, por isso alterada logo no incio. importante notar que o cdigo acima executado antes do cdigo do OnCreate para os outros formulrios. Quando o programa tenta abrir uma tabela que depende de um componente Database, preciso que ele esteja configurado com parmetros vlidos. Execute o programa e veja que ele continua funcionando, desde que os arquivos de dados estejam no mesmo diretrio do executvel. Salve o projeto novamente. Lembre-se: A propriedade Params uma lista de strings (v. cap. 12), por isso pode ser acessada como um vetor onde o primeiro elemento tem o ndice zero.

163

Criando um programa instalador


Como j foi dito, ao executar um projeto no Delphi, ele cria um programa executvel, um arquivo que pode ser executado independentemente do Delphi. Por exemplo, no nosso projeto anterior (VENDAS.DPR), o programa se chama VENDAS.EXE. Voc pode execut-lo diretamente no Windows. Finalize o Delphi. No Windows, clique em [ ]|Executar... , digite "C:\CURSODF\VENDAS.EXE" e clique Ok. Isso ir executar o programa fora do Delphi. No entanto, preciso uma forma mais amigvel de executar o programa, para que o usurio no precise digitar o nome do executvel. Geralmente, os programas no Windows so executados atravs de atalhos, que muitas vezes ficam no menu . Se voc for copiar esse programa para outro usurio, no precisa do Delphi para execut-lo, mas precisa instalar alguns arquivos do BDE (quando se utiliza bancos de dados). O Delphi (edies Professional e Client/Server) vem com um programa chamado InstallShield Express, para criar programas instaladores. Um programa instalador copia para o computador do usurio o seu arquivo executvel e mais os arquivos que ele precisa utilizar.

Iniciando o InstallShield
O InstallShield trabalha com projetos de instalao [setup projects]. Um projeto de instalao um arquivo contendo um conjunto de opes que definiro o contedo e funcionamento do seu instalador. Para o projeto Vendas, iremos criar um projeto de instalao, que criar disquetes de instalao para o programa. Esses disquetes contm um programa de instalao (SETUP.EXE) e todos os arquivos necessrios ao funcionamento do programa VENDAS.EXE, compactados para ocupar menos espao. Quando voc fornece os disquetes de instalao a um usurio, ele pode executar o programa de instalao, que copia VENDAS.EXE e os outros arquivos necessrios para o computador do do Windows, para poder executar VENDAS.EXE. usurio e cria um atalho no menu ]|Programas, no cone "IS Express Delphi Execute o InstallShield atravs do menu [ 4.0 ". Ao execut-lo, aparece uma tela com trs opes: "Open an existing Setup Project" usado para abrir um projeto de instalao feito anteriormente. "Open your last Setup Project" abre o ltimo projeto de instalao usado (se houver). No nosso caso, use "Create a new Setup Project" para criar um novo projeto de instalao. Agora voc ver a janela New Project, que permite escolher o nome do projeto de instalao e o local onde ele ser salvo. Em "Project Name", digite "VENDAS". Na lista de diretrios, selecione CURSODF, sob o drive C:. Em "New Subdirectory", digite "INSTVEND". Isso ir criar um novo subdiretrio sob CURSODF, para conter os arquivos do projeto de instalao. Finalmente clique no boto Create. O InstallShield criar um novo arquivo, chamado VENDAS.iwz, no diretrio C:\CURSODF\INSTVEND. Agora voc ver uma janela semelhante a um caderno de anotaes, que contm a chamada checklist, com as tarefas que voc deve fazer para criar um programa instalador. Nota: o InstallShield no instalado em conjunto com o Delphi. Ele deve ser instalado separadamente a partir do diretrio ISXPRESS do CD do Delphi.

Criando um Instalador
A criao de um instalador envolve diversas fases: Definir o Projeto Visual [set the visual design]: nesta fase, voc fornece informao bsica ao InstallShield sobre sua aplicao, como nome descritivo, nome do arquivo executvel etc. e informaes sobre as mensagens que sero mostradas durante a instalao. Selecionar Objetos para o Delphi[Select InstallShield Objects for Delphi]: define se o programa usa ou no o BDE para acesso a banco de dados e, caso use, quais so os drivers necessrios que devem ser includos com o programa. Especificar Componentes e Arquivos [specify components and files]: O InstallShield permite criar uma instalao com vrias opes para o usurio. Voc pode definir tipos de instalao [setup types], como "tpica", "compacta", "personalizada" que sero apresentados como escolha para o usurio. Voc pode definir componentes [components], que so conjuntos de grupos [groups] a serem includos e cada grupo um conjunto de arquivos que pode ser

164

incluido ou no na instalao. O mais importante que nesta fase voc pode acrescentar arquivos adicionais alm do seu executvel. Escolher Componentes da Interface [select user interface components]: permite configurar as vrias janelas de dilogo que o programa de instalao mostra. Fazer Mudanas no Registro [make registry changes]: O Registro [registry] o banco de dados central de configurao do Windows. Nesta fase, possvel definir modificaes que sero feitas no registro. No entraremos em detalhes sobre este tpico. Especificar pastas e cones [specify folders and icons]: define qual o nome da pasta no menu iniciar que ser criada para o programa e quais os cones que o programa criar no menu iniciar. Aps definir as opes, voc pode gerar os discos com o Disk Builder, um processo que ir compactar todos os arquivos necessrios e dividir em disquetes. Depois voc pode testar a instalao, executando o programa de instalao no seu prprio computador para ver o funcionamento. Quando tudo estiver pronto, voc pode gerar os discos de distribuio.

Definindo as Opes de Instalao


Vamos definir as opes para o instalador do Controle de Vendas. Primeiro clique em "Application Information" para abrir a caixa de dilogo "App Info". Em "Application Name", informe "Controle de Vendas". Esse o nome que aparece para o usurio. Clique no boto Browse para buscar o arquivo executvel da aplicao. Procure o diretrio C:\CURSODF e selecione VENDAS.EXE nesse diretrio. Em "Version", deixe 1.0 e em "Company", digite o nome da sua empresa. Note que o diretrio de destino, onde o programa ser instalado, aparece embaixo como: <ProgramFilesDir>\nome-empresa\Controle de Vendas O nome <ProgramFilesDir> uma varivel do InstallShield que ser substituda no momento da instalao, com o nome do diretrio de programas do usurio (geralmente "C:\Arquivos de Programas"). Voc pode alterar esse diretrio se quiser. Voc pode clicar na pgina "Main Window" para alterar o texto que aparece durante a instalao, em "Main Title". Coloque tambm "Controle de Vendas". Voc poderia escolher um logotipo tambm (uma imagem desenhada no MS Paint do Windows, por exemplo), mas no vamos alterar essa opo. Clique Ok. Agora vamos alterar as opes do BDE. Clique em "General Options", abaixo de "InstallShield Objects for Delphi". Aparece uma lista com a opo BDE (Borland Database Engine). Marque a opo. Aparecer uma outra janela para escolher o tipo de instalao. Como nosso programa utiliza apenas o formato de bancos de dados Paradox, vamos selecionar instalao parcial ("Partial BDE Installation"). Em "BDE Driver Types", marque "Paradox driver". Em "Query Engine Types", marque "SQL Engine". Depois clique [Avanar]. O ttulo muda para "BDE Alias Step 1 of 4". Opcionalmente, voc pode definir para o InstallShield os apelidos de bancos de dados que sero criados no computador do usurio. No nosso caso, no estamos usando apelidos externos ao programa, mas sim locais, por isso voc pode pular todos os passos. Clique em Avanar trs vezes, depois clique em Fim. Agora clique em Ok para retornar tela principal.

Definindo os Arquivos Utilizados


Quando voc definiu as informaes iniciais, o InstallShield j acrescentou o arquivo do programa, VENDAS.EXE, lista de arquivos a serem instalados. Voc pode tambm acrescentar outros arquivos como, no nosso caso, as tabelas usadas pelo programa, que se compe dos seguintes arquivos: CLIENTE.DB, VENDA.DB, ITEMVEND.DB, PRODUTO.DB, FABRIC.DB e todos os arquivos que tm o mesmo nome, com extenses .PX, .X?? e .Y??. No "caderno" do InstallShield, clique em "Groups and Files". Aparece uma rvore com os grupos de arquivos. Clique no sinal [+] ao lado de "Program Files" para expandir esse grupo. Note que j contm o arquivo executvel, VENDAS.EXE. Para acrescentar outros arquivos, clique no boto "Insert Files...". Isso vai abrir uma janela, mostrando os diretrios do drive C:. Selecione o diretrio "CURSODF" para ver os arquivos que ele contm. Selecione s arquivos com extenso '.DB', '.PX', '.VAL', '.X','.Y' (como CLIENTE.XG0, FABRIC.YG0 etc.). Aps colocar todos os arquivos na lista e conferir, clique Ok.

Escolhendo as caixas de dilogo

165

O InstallShield tem vrias caixas de dilogo predefinidas, que so apresentadas durante a instalao do programa. Algumas delas tm opes de configurao diversas que podem ser alteradas. Para esse exemplo, no alteraremos nenhuma opo, mas vamos apenas ver quais esto disponveis. Clique em Dialog Boxes na janela do InstallShield. Se uma caixa de dilogo estiver marcada, ela ser usada no instalador. Se estiver desmarcada, ela no ser usada. Voc pode clicar no boto "Preview" para ver como a janela aparece em tela cheia. Se ela tiver opes a ser configuradas, voc pode clicar na pgina "Settings", do lado direito, para configurar. Vejamos cada uma: Welcome Bitmap [bitmap de boas-vindas]: mostra uma imagem inicial ao usurio. Na pgina Settings, voc pode escolher qualquer arquivo de imagem .BMP, de 16 cores (desenhado com o Paint, por exemplo). Welcome Message [mensagem de boas-vindas]: mensagem genrica do InstallShield, em ingls. Software License Agreement [contrato de licena do software]: voc pode escolher um arquivo texto (na pgina Settings) que ser mostrado ao usurio. Readme Information [informao tipo leia-me]: voc pode escolher um arquivo texto, que mostra informao de ltima hora sobre o software. User Information [informao de usurio]: uma janela que pede nome de usurio, senha e, opcionalmente, um nmero de srie. Choose Destination Location [escolha local de destino]: janela que permite ao usurio selecionar um diretrio qualquer para instalar o programa. Voc pode definir, em Settings, o local default. (Se voc desativar essa janela, o usurio no pode alterar esse local). Setup Type [tipo de instalao]: se voc usa tipos de instalao (tpica, personalizada, compacta), permite ao usurio selecionar uma delas. Custom Setup [instalao personalizada]: quando o usurio usa a instalao personalizada, permite escolher o que ser instalado ou no. Select Program Folder [escolher pasta do programa]: permite ao usurio escolher qual a pasta onde o programa ser instalado. Em Settings, voc pode mudar a opo padro. Recomendase usar o mesmo nome descritivo do programa. Start Copying Files [iniciar cpia de arquivos]: o instalador mostra uma janela avisando que vai comear a copiar os arquivos. Progress Indicator [indicador de progresso]: mostra a porcentagem de arquivos copiados. Billboards [anncios]: mostra vrios bitmaps enquanto o programa est sendo instalado. Em Settings, voc pode escolher um diretrio contendo seus arquivos de imagem. Desative a menos que voc tenha criado seus prprios arquivos Setup Complete: mostra uma janela avisando que a instalao foi completada e se oferece para executar o programa.

Definindo os cones do Programa


Agora clique em "General Settings", abaixo de "Specify Folders and Icons". Voc ver que o InstallShield j definiu um cone para o seu programa, com o nome "Vendas". Clique no cone, altere "Description" para "Controle de Vendas" e clique em "Modify Icon". Se houvessem outros arquivos executveis includos, voc poderia criar cones para eles tambm. Para isso, basta digitar seus parmetros e clicar em "Add Icon". Quando existe apenas um cone a ser instalado, recomendvel no criar um sub-menu na pasta Programas, mas sim colocar o cone diretamente na pasta Programas (veremos o funcionamento disso mais tarde). Para fazer isso, clique na pgina Advanced, marque a opo "Programs Menu Folder" e clique no boto "Modify Info". Clique Ok para sair dessa janela. Nota: o cone que aparece para o programa o que foi definido no formulrio principal. Para mudar esse cone, voc pode escolher outro na propriedade Icon, dentro do seu projeto. Gerando os arquivos e testando a instalao Para gerar os discos de instalao, clique em "Disk Builder". Voc pode escolher qual o tamanho do disquete de destino em "Disk Size" ou "CD-ROM" para gerar arquivos sem limite de tamanho. Depois clique no boto Build. O InstallShield ir compactar os arquivos e informar quantos disquetes foram gerados. Depois clique em Close.

166

Agora, para testar a instalao, no seu prprio computador, clique em "Test Run". O programa de instalao ser executado. Informe as opes indicadas at finalizar a instalao. Aps a instalao, voc pode executar o programa atravs do menu [ ]|Programas, cone Controle de Vendas. Para desinstalar o programa, abra o Painel de Controle do Windows, clique no cone "Adicionar ou remover programas", selecione "Controle de Vendas" na lista e clique no boto "Adicionar/remover". Aps confirmao, o programa ser removido do Windows.

Gerando os disquetes de instalao


Para instalar o programa em outro computador, voc pode gerar disquetes de instalao a partir do InstallShield. Clique em "Copy to floppy". Para copiar todos os discos, clique em "Copy all disk images". Ou selecione apenas um disco e clique em "Copy selected disk image". Para terminar, clique em File|Save para salvar o projeto de instalao e feche o InstallShield.

Captulo 19 Relatrios
Conceitos do QuickReport Usando o QuickReport Wizard Criando um Relatrio com Vrias Tabelas

167

Conceitos do QuickReport
O QuickReport um gerador de relatrios composto de vrios tipos de componentes que trabalham em conjunto. Com ele, voc pode criar visualmente o relatrio, sem se preocupar com detalhes como quebras de pgina, agrupamentos, subtotais etc. Os componentes do QuickReport esto na pgina QReport.

A pgina QReport

QuickRep O componente bsico sobre o qual voc monta os relatrios. Tem a aparncia de uma folha de papel. Como veremos, ele se conecta a um dataset, de onde traz os dados, e permite colocar componentes imprimveis sobre ele, que mostram os dados. QRSubDetail Faz a ligao do relatrio com outras tabelas, ligadas da forma mestre/detalhe. QRBand Uma banda uma faixa do relatrio que impressa em determinados momentos. Esse componente permite criar vrios tipos de bandas. QRChildBand Cria uma banda filha, que sempre impressa aps uma determinada banda mestra. til se uma banda muito grande e se expande, ocupando vrias pginas. QRGroup Cria um agrupamento de itens dentro do relatrio. Quando um determinado campo muda de valor, uma banda de cabealho de grupo impressa. QRLabel Funciona como um componente Label, mas para impresso. Imprime o contedo da propriedade Caption. QRDBText Imprime o contedo de um campo do banco de dados, escolhido atravs das propriedades DataSet e DataField. Pode se expandir verticalmente ou se dividir em vrias pginas se necessrio. QRExpr Imprime campos calculados e outros itens. QRSysData Imprime informaes diversas como nmero de pgina, data/hora etc. A propriedade Data define o que ser impresso. QRMemo Imprime um texto de vrias linhas, que no vem do banco de dados. Pode se expandir verticalmente ou se dividir em vrias pginas se necessrio. QRRichText Imprime texto formatado, com diferentes fontes, tamanhos e estilos. O texto deve ser definido via programao. QRDBRichText: Imprime texto formatado, com diferentes fontes, tamanhos e estilos. O texto vem de um campo do banco de dados, determinado pelas propriedades DataSet e DataField. QRShape Usado para colocar desenhos no relatrio, como linhas, retngulos, crculos etc. QRImage Imprime uma imagem no relatrio (ex.: o logotipo da empresa). QRDBImage Imprime uma imagem no relatrio, a partir de um campo do banco de dados, determinado pelas propriedades DataSet e DataField.

168

QRCompositeReport: Permite agrupar vrios relatrios para imprimir como se fossem um s QRPreview Usado para ver uma prvia de impresso do relatrio em outra janela.

Construindo o Relatrio
Um relatrio do QuickReport tira seus dados de um dataset principal (tabela ou consulta SQL) e de alguns datasets secundrios, que estejam de alguma forma ligados a ele. A propriedade DataSet do componente QuickRep determina o dataset principal. Funciona como a propriedade DataSet de um componente DataSource do Delphi. O relatrio construdo visualmente a partir de bandas, que so as diversas faixas horizontais e componentes imprimveis, que so colocados nessas bandas. Os relatrios mais simples tm uma banda de cabealho da pgina [page header], uma banda de detalhes [details] e uma banda de rodap [page footer]. Outros mais complexos podem usar outros tipos. Os tipos de bandas so: Ttulo [title]: impressa uma nica vez, na primeira pgina do relatrio, aps o cabealho de pgina. Resumo [summary]: impressa uma nica vez, no final da ltima pgina do relatrio. Usada geralmente para os totais gerais. Cabealho de pgina [page header]: impressa no topo de cada pgina. Rodap de pgina [page footer]: impressa na parte inferior de cada pgina. Cabealho de coluna [column header]: impressa no topo de cada coluna. S tem utilidade com relatrios de mltiplas colunas. (Vide propriedade Page.Columns no componente QuickRep). Detalhe [detail]: impressa uma vez para cada registro do dataset Cabealho de grupo [group header]: quando existe um agrupamento de itens, impressa uma vez para cada grupo. Ex.: se um relatrio imprime vendas agrupadas por cliente, um cabealho de grupo impresso para cada cliente, contendo o nome do cliente. Rodap de grupo [group footer]: impressa no final de um grupo de itens. Sub-detalhe [subdetail]: usada em relatrios mestre/detalhe, como veremos mais tarde. Filha [child]: banda que serve como continuao de outra. Usado apenas pelo componente QRChildBand. Voc pode construir um relatrio posicionando componentes QRBand, QRChildBand

QRGroup manualmente ou usar a propriedade HasBand do componente ou QuickRep para criar alguns tipos de bandas automaticamente. Os componentes imprimveis so colocados sobre as bandas em tempo de projeto e so impressos quando o relatrio impresso. Eles podem conter texto ou imagens fixos (como QRLabel, QRMemo, QRRichText, QRImage, QRShape), ou contedo ligado aos QRDBText, QRDBRichText, QRDBImage)

campos do banco de dados (como

QRExpr e ou ainda contedo varivel, calculado ou determinado pelo relatrio (como QRSysData). O componente QuickRep visual e aparece num formulrio em tempo de projeto. No entanto, esse formulrio no mostrado ao usurio, mas apenas usado internamente pelo programa. Para imprimir o relatrio, usa-se o mtodo Print do componente. Para ver uma prvia de impresso numa janela, usa-se o mtodo Preview.

169

Usando o QuickReport Wizard


Existem duas formas de criar um relatrio no QuickReport. A forma mais rpida usar o QuickReport Wizard, que cria um relatrio bem simples, com todos os campos de uma tabela. A outra forma desenhar o relatrio, colocando os componentes imprimveis e definindo suas propriedades, o que mais trabalhoso, mas necessrio com relatrios mais complicados. Para o primeiro exemplo, vamos criar um relatrio usando o QuickReport Wizard, com a relao de clientes cadastrados. Agora clique em File|New... O Delphi ir mostrar o repositrio de itens para voc escolher o que quer criar. Clique na pgina "Business", selecione o cone "QuickReport Wizard" e clique Ok. O assistente ir perguntar inicialmente se voc deseja criar um relatrio com os campos de uma tabela, cliqque no boto "Start Wizard" , em seguida qual o diretrio ou alias da tabela e qual o nome da tabela e os campos que deseja mostrar. Selecione "CursoDelphi" na lista superior e depois "CLIENTE.DB" na lista inferior, e selecione os campos "Nome" e "Telefone". Em seguida clique no boto "Finish".

Note que existe um componente Table no formulrio. Altere o seu nome para 'tblCliente' e a sua propriedade Active para True. Mude o Name do formulrio para "FormRelCliente".

Imprimindo o Relatrio
Salve o formulrio com RELCLIENTE.PAS. Retorne ao formulrio principal (formPrincipal), clique duas vezes no menu Relatrio|Clientes e coloque o seguinte comando; FormRelCliente.QuickRep1.Preview; Note que 'FormRelCliente' o nome do formulrio que contm o componente QuickReport e 'QuickRep1' o nome desse componente (no foi alterado). Preview um mtodo do componente que mostra uma janela de prvia de impresso. Caso queira imprimeir utilize o mtodo Print. Para que os comandos acima funcionem, acrescente uma clusula uses no incio da seo de implementao da unidade: uses RelCliente; Lembre-se de que 'RelCliente' o nome da outra unidade, que contm o formulrio do QuickReport. Agora execute o programa e teste o funcionamento do relatrio que ser mostrado no vdeo. Note que a janela de visualizao modal _ voc deve fech-la para voltar ao formulrio.

170

Nota: a qualquer momento, se voc quiser ver uma prvia de impresso, basta clicar com o boto direito no componente QuickRep (a folha em branco) e no item "Preview".

Analisando o Relatrio Gerado


Termine a execuo do programa e abra o formulrio 'FormRelCliente'. Vamos ver como funciona esse formulrio bsico. Note que ele possui um componente Table no canto. Esse componente est ligado tabela CLIENTE.DB, do banco de dados CursoDelphi, como foi informado no QuickReport Wizard, na propriedade DataBaseName altere seu contedo para 'Vendas', pois, em todos os formulrios estamos usando o Alias Local . Em vez de uma tabela, poderia ser um componente Query que faz uma consulta SQL. A "folha branca" com linhas horizontais e verticais um componente QuickRep, que o local de desenho do relatrio. Nesse componente, a propriedade DataSet faz referncia a "tblCliente", a tabela usada para os dados do relatrio. Sobre esse componente, so colocadas vrias bandas. A banda "Column Header", logo abaixo, tem um componente QRLabel para cada nome de campo, definindo os cabealhos das colunas. Se voc quiser alterar o texto de um deles, clique no componente e altere a propriedade Caption. A banda "Detail", mais abaixo, impressa repetidas vezes, uma para cada registro. Os componentes que esto nesta banda so da classe QRExpr e cada um est associado com um campo da tabela. Em tempo de projeto, o componente mostra o nome do campo entre colchetes. Esta escolha da campo que ser mostrado feito na propriedade Expression , no prximo exemplo iremos ver essa propriedade com mais detalhes. Finalmente, na parte inferior, existe uma banda "Page Footer", impressa no rodap da pgina. Clique na barra de rolagem horizontal, para ver o contedo do formulrio direita. Note que mais direita na banda, existe um componente que mostra "Page". Esse um componente QRSysData, cuja propriedade Data contm o valor 'qrsPageNumber', que o faz mostrar o nmero de pgina automaticamente. Salve o projeto novamente.

Criando um Relatrio com Vrias Tabelas


Agora que j usamos o QuickReport Wizard, veremos como criar um relatrio posicionando os componentes manualmente.Iremos criar um relatrio de vendas de produtos, por cliente, que envolve dados de vrias tabelas: CLIENTE, VENDA, ITEMVEND, PRODUTO. Inicialmente iremos colocar somente a tabela de CLIENTE,depois que estiver mostrando os Clientes, iremos acrescentar as vendas e os itens vendidos. Abra o projeto VENDAS.DPR. Nesse projeto, vamos utilizar o QuickReport para criar um . Altere o relatrio de clientes. Crie um novo formulrio, com File|New Form ou o boto nome do formulrio para 'FormRelVenda'. Agora coloque um componente Table no formulrio e altere suas propriedades para acessar a tabela de clientes: Name: tblCliente DatabaseName: CursoDelphi TableName: Cliente Agora clique na pgina 'QReport' e selecione o componente QuickRep para colocar no formulrio. Mova-o para o canto superior esquerdo e mude as seguintes propriedades: Name: qrpRelatorio DataSet: tblCliente Agora devemos escolher quais as bandas que sero includas no relatrio. Clique duas vezes no sinal de + da propriedade Bands para ver seus sub-itens. Altere HasPageHeader, HasPageFooter e HasDetail para True. medida que voc altera os valores, novas bandas iro aparecer no relatrio. O formulrio dever ter a seguinte aparncia:

171

Nota: ou, se preferir, copie o componente Table do formulrio de clientes [Ctrl+C] e cole [Ctrl+V] neste formulrio. Nota: basta clicar duas vezes em DataSet para aparecer o valor. Aumente a largura do formulrio para que ele ocupe a tela inteira, para melhor visualizao. Note que voc pode selecionar uma banda clicando nela com o o mouse. Voc pode aumentar a altura da banda, mas a largura determinada automaticamente baseado no tamanho de pgina. As medidas que aparecem no relatrio so dadas em centmetros, como padro. Vamos colocar um ttulo do relatrio, coloque um componente QRLabel na banda "Page Header". Altere o Caption para "Vendas por Cliente" e tambm as seguintes propriedades: Font.Size: 20, para aumentar o texto Alignment: taCenter, para centralizar o texto AlignToBand: True, para centralizar o componente em relao banda. Quando voc altera AlignToBand, a posio do componente se altera. Se voc mudar apenas Alignment, apenas a posio do texto em relao ao componente se altera. Agora na banda "Details", iremos mostrar somente o nome do cliente(essa seo ser impressa uma vez para cada cliente). Coloque um componente QRLabel e altere o

), com as Caption para "Nome" e, logo frente dele, um componenteQRDBText( propriedades DataSet ,selecione "tblCliente" e DataField, selecione o nome do campo, "Nome". Nota: para chamar o Object Inspector, se ele no estiver visvel, use a tecla [F11] ou [Enter].

Inserindo um Nmero de Pgina


Voc pode inserir, em qualquer posio do relatrio, um nmero de pgina que ser incrementado automaticamente. Vamos colocar um na banda "Page Footer". Primeiro coloque um componente QRLabel e altere o seu Caption com "Pgina:". Depois QRSysData e coloque direita do rtulo. Altere a propriedade selecione o componente Data, selecionando 'qrsPageNumber'. Vamos colocar tambm outro componente QRSysData para exibir a data e hora de impresso do relatrio. Coloque-o na banda "Page Footer" e altere as seguintes propriedades: Data: qrsDateTime, para mostrar data e hora AutoSize: True, para que o componente aumente de acordo com o contedo dele.

172

Alignment: taRightJustify, para alinhar o texto direita do componente AlignToBand: True, para alinhar o componente direita da banda

Visualizando o Relatrio
Para visualizar o relatrio como ele vai estar quando impresso, altere a propriedade Active do 'tblCliente' para True, clique no componente QuickRep (fora das bandas) com o boto direito e clique na opo Preview do menu. Isso vai mostrar, como antes, a janela de prvia de impresso. Essa janela contm vrios botes de controle. Os trs primeiros permitem escolher a quantidade de zoom: 100 % ou largura da pgina. Quando o relatrio tem primeira, ou

vrias pginas, podem ser usados botes para navegar entre as pginas: anterior, prxima e

ltima. Voc pode imprimir o relatrio clicando no boto . O boto

configurar as opes de impresso com o boto

permite salvar o relatrio

permite abrir esse arquivo novamente para visualizar. E o boto Close fecha num arquivo e a janela de visualizao. Desative a tabela (altere Active para False) porque ela ser ativada apenas durante a execuo do programa. Salve o projeto. Quando o Delphi pedir o nome da unidade do novo formulrio, informe "RVenda".

Acrescentando Vrias Tabelas ao Relatrio


Coloque trs componentes Table no formulrio. Para todos eles, altere DatabaseName, selecionando "Vendas". Defina as suas propriedades da seguinte forma: Name TableName VENDA.DB tblVenda ITEM.DB tblItem PRODUTO.DB tblProduto Agora coloque trs componentes DataSource no formulrio e conecte-os aos componentes Table correspondentes: Name DataSet tblCliente dsCliente tblVenda dsVenda tblItem dsItem

Conectando as Tabelas
Faremos ligaes mestre-detalhe para relacionar as tabelas. Primeiro vamos conectar 'Venda' a 'Cliente' (um cliente tem N vendas). Clique em 'tblVenda' e altere as propriedades: MasterSource: dsCliente, MasterFields: CodCliente, IndexName: CodCliente. Agora vamos conectar 'ITEM' e 'VENDA'. Clique em 'tblItem' e altere: MasterSource: dsVenda, MasterFields: CodVenda, IndexName: IndVenda. Finalmente, para buscar o nome do produto a partir da tabela ITEM, devemos conectar as duas. Clique em 'tblProduto' e altere: MasterSource: dsItem, MasterFields: CodProduto, IndexFieldNames: CodProduto. A aparncia do relatrio , nesse momento, ser semelhante figura:

173

Criando Sub-detalhes para Vendas


Quando se tem um relatrio com tabelas mestre-detalhe, a banda "detalhe" se relaciona apenas com a tabela mestra. Para colocar dados das outras tabelas, devemos colocar bandas QRSubDetail. "sub-detalhes", utilizando o componente Coloque no formulrio um componente QRSubDetail. Ele aparece como uma nova banda, abaixo de "Detail", mas acima de "Page Footer". Vamos mostrar nesse caso os dados da tabela de vendas. Na propriedade DataSet, selecione 'tblVenda'. Mude o nome desse componente para 'qrsubVenda'. Isso vai ajudar a identific-lo mais tarde, como veremos. Nesse componente, a propriedade Master define quem o 'relatrio mestre' para ele, que determina quando ele ser impresso. Note que a propriedade Master nesse caso foi definida como 'qrpRelatorio', que o nome do componente QuickRep. Deixe-a como est. Coloque na banda sub-detail um componente QRLabel, com o texto "Cdigo Venda:". Na frente coloque um componente QRDBText, com DataSet: tblVenda e DataField: CodVenda. Aps os dois, coloque mais um QRLabel, com o texto "Data Venda:" e um QRDBText, com DataSet: tblVenda e DataField: DataVenda. Destaque os rtulos em negrito. O resultado ficar como o seguinte:

Se quiser, use o Preview para visualizar o relatrio (tblVenda deve estar ativo). Note que primeiro impressa a seo 'Detail', com os dados do cliente, depois impressa vrias vezes a seo Sub-detail, contendo as vendas efetuadas. Por exemplo: Cliente: Primeiro Cdigo Venda:101 Data Venda: 04/07/97 Cdigo Venda:102 Data Venda: 05/07/97 Cdigo Venda:105 Data Venda: 13/07/97 Cliente: Segundo Cdigo Venda:107 Data Venda: 20/07/97 Cdigo Venda:108 Data Venda: 30/07/97 Cdigo Venda:110 Data Venda: 30/08/97 Cliente: Terceiro Cdigo Venda:107 Data Venda: 20/07/97 Cdigo Venda:108 Data Venda: 30/07/97 ........

Criando Sub-detalhes para Itens de Venda

174

Agora, para cada venda, devemos imprimir os itens de venda correspondentes a eles. Para isso, coloque mais um componente QRSubDetail no relatrio, que vai aparecer abaixo da banda de vendas. Altere as seguintes propriedades: Name: qrsubItem DataSet: tblItem Master: qrsubVenda A propriedade Master deve ser alterada, para dizer que essa banda sub-detalhe estar subordinada banda 'qrsubVenda', criada anteriormente ,ou seja, para cada registro de venda impresso, sero impressos vrios registros de itens de venda. Agora, para essa banda, vamos criar um cabealho de grupo e um rodap de grupo. Um cabealho de grupo uma banda impressa antes de todos os registros do grupo (no caso, todos os itens de uma determinada venda) e um rodap de grupo impresso aps todos os registros do grupo. O cabealho ser usado para mostrar os nomes de campos e o rodap ser usado para mostrar um total geral. Clique na propriedade Bands desse componente e expanda seus sub-itens. Altere os dois, HasHeader e HasFooter, para True. Isso vai criar as bandas de cabealho e rodap de grupo, acima e abaixo do 'sub-detail'. Clique na banda "Group Header". Na propriedade Font, clique no boto de reticncias, selecione "Negrito" e clique Ok. Com isso, todos os componentes colocados nessa banda ficaro em negrito. Coloque quatro rtulos de texto (QRLabel), alterando o Caption em cada um com os textos "Produto", "Quantidade", "Preo Unitrio" e "Preo Total". Deixe um espao maior entre "Produto" e "Quantidade". Agora clique na banda "sub-detail", abaixo do "Group Header" novamente. Vamos mostrar aqui o nome do produto (campo Nome de tblProduto), a quantidade vendida (campo Quantidade de tblItem) e o preo de venda (campo PrecoVenda de tblItem). O preo total um campo calculado, que ser colocado mais tarde. Coloque trs componentes QRDBText, debaixo dos rtulos correspondentes e defina suas propriedades da seguinte forma: DataSet DataField tblProduto Nome tblItem Quantidade tblItem PrecoVenda O resultado, visualmente, ser o seguinte:

Se desejar, clique com o boto direito no relatrio e depois em Preview(Para funcionar todas as tabelas tem que estar com a propriedade Active = True). Alguns detalhes ainda precisam ser acertados, como a formatao dos campos.

Formatando os Campos
Para melhorar a aparncia do relatrio, vamos mostrar os campos "Quantidade" e "PrecoVenda" alinhados direita e "PrecoVenda" formatado como um valor monetrio. Clique no componente QRDBText que mostra "[Quantidade]". Altere a propriedade AutoSize para False. Quando AutoSize True, ele muda de tamanho de acordo com o contedo. Posicione-o alinhado direita de acordo com o rtulo e mude a propriedade Alignment para 'taRightJustify'. Selecione o componente "[PrecoVenda]" e faa o mesmo: AutoSize=False e Alignment=taRightJustify. Alm disso, altere a propriedade Mask, colocando o texto "#,0.00". Essa propriedade tem o mesmo efeito de DisplayFormat para campos da tabela, como j foi visto. Agora visualize novamente a prvia de impresso. Note que os campos aparecem formatados corretamente.

Criando um Campo Calculado

175

Voc pode criar campos calculados no QuickReport, usando o componente QRExpr. Com ele, voc pode digitar uma expresso qualquer, envolvendo campos da tabela. Voc no precisa escrever cdigo de programa para fazer o clculo. Vamos usar esse componente para calcular o "Preo Total" do item, que PrecoVenda * Quantidade. Coloque no formulrio um componente QRExpr logo abaixo do rtulo "Preo Total". Clique na propriedade Expression, que define a frmula de clculo do campo e clique duas vezes no boto de reticncias. Voc ver uma janela onde poder montar uma expresso de clculo.

Clique no boto "Database Field", na lista "Select dataset", a tabela 'tblItem', que contm os valores a serem calculados. Os campos da tabela aparecem na lista abaixo do nome. Clique em 'Quantidade', em seguida pressione o boto 'OK'. No quadro de texto na parte superior da janela, aparece 'tblItem.Quantidade'. Agora, clique no boto com o sinal de multiplicao, [*]. Um sinal * ser inserido no texto da frmula. Para terminar, clique novamente em "Database Field", escolha a tabela 'tblProduto' e o campo 'PrecoVenda'. A frmula final aparecer como na figura:

A frmula de clculo do campo, portanto, 'tblItem.Quantidade * tblProduto.PrecoVenda'. Agora clique Ok para retornar ao formulrio.

176

Para visualizar esse componente melhor, altere a propriedade AutoSize para False e reduza a largura do componente de acordo com o rtulo na parte superior. Altere tambm as propriedades: Alignment: taRightJustify e Mask: "#,0.00", como foi feito antes para o preo de venda. Se voc usar o comando Preview novamente, ver que o campo calculado mostrado corretamente para cada registro.

Criando um Sub-total
Agora vamos totalizar o campo calculado criado, para mostrar o total de vendas para cada cliente. Selecione o componente QRExpr, que foi criado para calcular o preo total. Tecle [Ctrl+C] para fazer uma cpia dele. Clique na banda "Group Footer" e tecle [Ctrl+V] para trazer essa cpia. Na propriedade Expression, faa uma alterao manual (no clique no boto de reticncias, pois seria mais complicado). Onde est o valor atual: tblItem.PrecoVenda * tblItem.Quantidade substitua por: SUM(tblItem.PrecoVenda * tblItem.Quantidade) A funo SUM calcula o somatrio de uma expresso. Mas preciso tambm informar qual o conjunto de registros sobre os quais essa soma ser efetuada. No nosso caso, ser para os itens de cada venda. Para definir o escopo da soma, usada a propriedade Master do componente. Essa propriedade faz referncia a uma banda que define quando o somatrio ser atualizado. Quando essa banda for impressa, o componente atualiza internamente o total, antes de imprimir. No nosso caso, em Master, selecione 'qrsubItem', que a banda que contm os itens de venda. Com isso, a cada item de venda impresso, o componente acumular internamente o seu total. Altere tambm a propriedade ResetAfterPrint para True. Se ela for False, o componente continua acumulando o total at o fim da impresso. Quando ela True, o componente zera o seu acumulador depois de impresso. Para dar mais destaque ao sub-total, coloque-o em negrito. Agora coloque esquerda desse componente um QRLabel, com o texto "Total da venda" e em negrito. Use o comando Preview para visualizar o relatrio. Note agora que o sub-total ser impresso aps os itens de venda.

Chamando o Relatrio a Partir do Menu


Agora que o relatrio est pronto, faremos com que ele seja chamado a partir do menu principal, no item de menu Relatrios|Vendas. Mas antes vamos criar um procedimento no formulrio do relatrio para facilitar a sua chamada. Na unidade "RVendas", encontre a classe de formulrio (TFormRelVendas). Dentro da seo public, acrescente a seguinte declarao de procedimento: procedure VisualizarRelatorio; Agora, no comeo da seo implementation, acrescente o corpo do procedimento: procedure TFormRelVenda.VisualizarRelatorio; begin {abrir todas as tabelas usadas} tblCliente.Open; tblVenda.Open; tblItem.Open; tblProduto.Open; {visualizar o relatrio} qrpRelatorio.Preview; {fechar todas as tabelas usadas} tblCliente.Close; tblVenda.Close; tblItem.Close; tblProduto.Close;

177

end; Abra a unidade do formulrio principal, VENDPRIN.PAS. Para poder chamar o outro formulrio, clique em File|Use unit... e selecione "RVenda" para acrescentar a unidade na clusula uses. No formulrio, clique no item de menu Relatrios|Vendas. Coloque os seguinte comando: FormRelVenda.VisualizarRelatorio; Execute o programa e clique em Relatrios|Vendas. O programa mostrar a janela de prvia de impresso, como j foi visto. Salve o projeto novamente.

178

Bibliografia sugerida
Os seguintes livros so uma boa fonte de material para aprofundar-se um pouco mais no conhecimento do Delphi. LOBO, Rodrigo. Incrementando o Delphi. Ed. Advanced. ISBN: 8586916218. Este livro oferece uma srie de dicas, truques, utilitrios e componentes para o Delphi, visando tornar o trabalho do programador mais prtico e produtivo. Englobando as reas de banco de dados, multimdia, Internet, arquivos, etc. Inclui CD contendo os componentes e utilitrios. CANT, Marco. Dominando o Delphi 4 "A bblia". Ed. Makron. ISBN: 8534610460. Esta a edio completamente revisada e atualizada do livro de programao Delphi mais louvado de todos os tempos. Escrito pelo destacado especialista em Delphi, Marco Cant, este livro dedicado a usurios iniciantes e avanados, oferecendo a cobertura mais efetiva e cuidadosa da programao Delphi que se pode encontrar. PACHECO, Xavier e TEIXEIRA, Steve. Delphi 4 Developer's Guide (Developer's Guide Series). ISBN: 0672312840 Este livro uma referncia de nvel avanado mostrando aos desenvolvedores o mais importante que eles devem saber sobre o Delphi 4. Os autores lidam com desenvolvedores todos dias e citam tcnicas poderosas, dicas e conhecimento tcnico das mais avanadas caractersticas do Delphi 4. Tpicos incluem: Componentes de nvel avanado incluindo links embutidos, caractersticas especiais e DLLs, inclusive a criao de suas prprias Bibliotecas de Componentes Visuais (VCL), programao orientada a objeto avanada e object Pascal. O livro discute assuntos sobre desenvolvimento de aplicaes e conceitos de estrutura para aplicaes de bancos de dados cliente/servidor, desktop, bem como componentes MIDAS (Multi-tier Distributed Applications Services Suite), e como trabalhar com eles.

179