Você está na página 1de 176

Linguagens de Programao 1 Delphi 7 Anotaes de aula

Prof. Joo Carlos Almeida Prado ltima Reviso : 11/03/2010

Pag. 1/176

ndice 1. Conceitos gerais 2- O DELPHI 2.1- Programao orientada a objetos. 2.2- Usando o DELPHI. 2.3- Programao orientada a componente 2.4- Entendendo melhor o programa fonte (UNIT.PAS) 2.5- Entendendo EVENTOS, MTODOS, PROCEDIMENTOS e FUNES 2.5.1- Os eventos mais importantes 2.5.2- Que evento utilizar? 2.5.3- Abandonando a aplicao com o ESC 2.6- Programando por evento 2.6.1- O componente TIMER 2.7- Grficos: a classe Tcanvas 2.8- Vetores e Matrizes 2.9- RECORD 2.10- Manipulando arquivos tipo INI 2.11- Arquivo texto 2.12- Agenda de telefones 2.13- Agenda usando XML 2.14- Bancos de dados e tabelas 2.15- Gerando relatrio 3- O INTERBASE (FIREBIRD) 3.1- Conceitos bsicos 3.2- o SQL 3.3- Os componentes da palheta DBExpress 4- Uma aplicao completa com o DBExpress 4.1- Criando o banco de dados 4.2- Criando uma aplicao 4.3- Criando uma DataSet navegvel 4.4- Outras aplicaes do SimpleDataSet 5- Criando um componente em tempo de execuo 6- Rotinas teis 7- Artificios de programao 7.1- Verificando qualquer coisa antes de eventos em componentes 7.2- Travando a aplicao 7.3- Determinando o ponto flutuante do seu sistema operacional 7.4- Cancelando evento se o operador quiser sair 7.5- Criptografando dados 7.6- Mudando a cor das linhas do DBGrid 7.7- Lista de erros de compilao 3 5 5 7 12 22 25 32 33 34 42 43 50 54 78 80 82 88 97 103 107 107 114 116 121 121 122 128 130 138 140 170 171 171 172 172 172 175 176 Pag. 2/176

1. Conceitos gerais
Para a programao necessrio que o aluno tenha em mente que o computador segue sempre uma seqncia lgica de aes. Esta seqncia lgica, para o ser humano, muitas vezes quebrada, pois no necessitamos passar por todos os passos de um raciocnio para chegarmos a uma concluso. J o computador, como ele no inteligente, no pensa por si s, precisa receber todos os comandos, passo a passo para executar uma tarefa, qualquer que seja ela. Fazer um fluxograma nada mais que organizar idias, seqencialmente, de forma que possamos codificar, ou seja, transformar para a linguagem do computador. Inicialmente precisamos definir alguns conceitos: Comando: Comando ou instruo um conjunto de letras que, ao serem enviadas CPU, faz com que a mesma execute uma operao. O comando, como o prprio nome diz, comanda a mquina a fazer uma determinada operao. A finalidade do fluxograma organizar as idias de forma a atingir o nvel da linguagem que ser utilizada. Quanto menor o nvel da linguagem, mais detalhado dever ser o fluxograma. Devemos lembrar ainda que o computador no pensa, portanto, mesmo aquilo que pode parecer o bvio, dever ser detalhado at que possamos abranger todas as condies e ocorrncias possveis. Programa: O programa uma seqncia de comandos, que sero executados a partir de um interpretador, ou sero transformados em linguagem de mquina e posteriormente executados. Utilitrio ou Aplicativo: todo programa que tem uma finalidade bem especfica. Sistema: um conjunto de programas que tem um conjunto de finalidades, destinada a abranger o maior numero de tarefas de automao dentro de uma empresa. Algoritmo: o nome que damos soluo de um problema. Organograma: uma representao grfica de uma organizao. Ex: organograma de uma empresa. Fluxograma: uma representao grfica, esquemtica de uma seqncia de aes. Existem dois tipos principais de fluxograma: o convencional e o estruturado. Fluxograma convencional: Neste sistema de fluxograma procuramos esquematizar, mesmo que de forma no muito organizada, todas as tarefas que devero ser efetuadas para se atingir um determinado objetivo. Fluxograma estruturado: No fluxograma estruturado no temos desvios incondicionais, ou seja, no existem saltos no meio do programa, todos os programas que desenvolvemos possuem uma seqncia lgica, seqencial e linear. Para a programao em DBASE ou CLIPPER era utilizado este tipo de fluxograma, uma vez que estas linguagens so estruturadas e no possuem desvio incondicional. Entrada de dados: So todas as rotinas de programao que interagem com o operador de forma que o mesmo estar fornecendo dados para que o sistema possa process-los. Sada de dados: So os resultados do processamento. Processamento: So os comandos que efetivamente transformam o estado da mquina a partir dos dados, ou seja, a manipulao dos dados para que se obtenha um determinado resultado. Programa fonte: Programa escrito em linguagem de alto nvel, o operador entende a linguagem quando editamos o programa fonte num editor de tento. Interpretador: Programa que permite ao operado executar um programa diretamente a partir Pag. 3/176

do seu fonte. Compilador: Transforma o programa fonte em cdigo objeto (extenso OBJ). Arquivo: conjunto de bytes. Todo arquivo possui um nome e uma extenso, sendo que a finalidade da extenso indicar a finalidade do arquivo. Ex: TESTE.EXE - ARQUIVO EXECUTVEL, est em linguagem de mquina. Assembly: a linguagem que o microprocessador entende, dentro dele existe uma "tabela" que indica a finalidade de cada comando. Ela pode estar em cdigo fonte ou em linguagem de mquina. O programa compilador do assembly o assembler. Linker (ou Link-editor) : Programa que serve para criar um executvel, a partir do cdigo objeto de um programa e as bibliotecas da linguagem. (OBJ + LIB = EXE). Cdigo ASCII - Tabela que associa para cada smbolo utilizado pelo computador (como letras, nmeros, etc). Editor: Programa que permite abrir um arquivo e alter-lo.

Pag. 4/176

2- O DELPHI
O DELPHI uma ferramenta de desenvolvimento de programas visuais, baseada NA LINGUAGEM OBJETCT PASCAL, orientada a objetos. Para podermos programar usando o DELPHI precisamos entender, em linhas gerais, o que a orientao a objeto. Vale ressaltar que o DELPHI facilita muito o desenvolvimento, pois possui diversos componentes e ferramentas disponveis em tempo de desenvolvimento, ou seja, durante a montagem do programa possvel para o operador visualizar a situao final da maioria dos componentes inseridos na aplicao. 2.1- Programao orientada a objetos. Toda a programao orientada a objetos parte do conceito de classe. Uma determinada classe consiste em um conjunto de definies de propriedades, mtodos e eventos atribudos a todos os elementos que compem uma classe. Sempre que criamos um elemento a partir de uma classe, estamos criando um objeto. Note que o nome objeto uma atribuio virtual de referncia, pois tem-se que, por definio, objeto algo fsico e palpvel. por isso que se define o objeto como sendo a instncia de uma classe, pois na realidade ela no existe fisicamente, apenas uma representao grfica que surgir apenas durante a execuo de um programa. Para elucidar melhor este conceito pode-se comparar a classe como sendo uma fbrica. Para esta fbrica forneceremos matria prima e a ligaremos, ela produzir objetos quando comear a funcionar. Portanto, a partir de uma classe e desta matria prima, criamos um objeto. A matria prima essencial para a criao de um objeto so as propriedades. Todas as propriedades possuem valores padres que sero utilizados caso o programador no as defina. Por se tratar de um ambiente de desenvolvimento bem completo, o DELPHI permite ao programador visualizar os objetos que devero aparecer na execuo do programa. Quando podemos visualizar este objeto, em tempo de desenvolvimento, chamamos de componente. Desta forma, do ponto de vista prtico, objeto e componente passam a ser sinnimos. importante Lembrar que deste 2004, o DELPHI 4 passou a ser de uso livre. E a partir de 2005 ele foi totalmente integrado a plataforma DOT NET, portanto pode ser aproveitado neste tipo de aplicao. Pode-se utilizar o DELPHI para criar aplicaes onde todos os objetos que sero utilizados j sero definidos em tempo de edio do programa fonte, visualizados exatamente da forma que iro aparecer. O principal beneficio disto que o programador ter mais facilidade em manutenir o sistema, pois estar visualizando a apresentao da aplicao quando ela estiver rodando. Em contra partida, a aplicao (nome dado ao programa desenvolvido em DELPHI, composto por todas as partes, incluindo programas, modulo, funes e formulrios com seus objetos) s ser efetivamente iniciada aps a criao de todos os formulrios criados, isto se reflete numa demora na entrada do sistema. Neste caso, aconselha-se que o comando de criao seja retirado do modulo principal do projeto, e colocado na tela inicial, mostrando ao usurio que o sistema est sendo carregado. Outra forma de programar criar todos os objetos em tempo de execuo, o que torna a entrada na aplicao muito mais rpida, e diminui o uso da memria RAM do computador. A desvantagem neste caso que, como a apresentao da aplicao no visual, todos ajustes de tela devero ser feitos aps exaustivos testes. como se voltssemos ao processo de programao procedural. Para facilitar o entendimento e uso do DELPHI, vamos entender o objeto como sendo um componente que pode ser colocado na aplicao. Todos estes componentes esto disponveis nas Pag. 5/176

palhetas disponibilizadas pelo DELPHI. A programao orientada a objetos, interpretada de forma simplificada e considerando os objetos como componentes, tem como ponto de partida o formulrio inicial. Neste formulrio iremos incluir novos objetos (note que o formulrio tambm um objeto, porm funciona como suporte para os demais, no possvel incluir um formulrio dentro de outro). Cada objeto pertence a uma classe que determina o comportamento deste objeto e define suas diretrizes bsicas. Para cada objeto definimos: 1- Propriedades: so parmetros que quando alterados alteram as caractersticas fsicas do objeto; 2- Eventos: so aes do usurio sobre o objeto, que resultam na execuo de algum processo; 3- Mtodos: so funes e procedimentos que alteram o objeto em relao ao seu contedo e/ou caractersticas. Para ficar mais claro vamos exemplificar : Objeto : Boto (Buttom) Propriedade : - nome do boto (Caption) Evento : - clicar o boto (ButtomClick). Objeto : Caixa de listagem Propriedade: -posio do ListBox em relao ao topo do formulrio (top) Evento: - digitar uma tecla (OnKeyDown) Mtodo: - limpar caixa (ListBox1.Clear ), - incluir itens no ListBox (ListBox1.Items.Add(teste) Note que as propriedades podem ser alteradas em tempo de execuo, os eventos so criados em tempo de programao, e os mtodos so pr-definidos para cada classe. Novas propriedades, mtodos e eventos podem ser definidos para os objetos, mas sempre em tempo de programao. Este processo um pouco mais complicado e deixaremos para abord-lo mais adiante.

Pag. 6/176

2.2- Usando o DELPHI. A linguagem de programao do DELPHI o OBJECT PASCAL. Para que possamos entender sua utilizao, precisamos conhecer toda a interface do DELPHI. Ao ser iniciado, o DELPHI j abre o ambiente de programao, criando um projeto vazio, denominado Project1 (caso no exista nenhum gravado com este nome, se existir, abrir o projeto com nome Project2, e assim por diante) com um nico formulrio, chamado de form1, que ser o principal, responsvel pelo acesso da aplicao. Estes nomes podem ser alterados no momento que o programador gravar seu projeto pela primeira vez. A tela inicial do DELPHI apresentada seguir:

importante ressaltar que esta a tela de uma ferramenta de programao.

O DELPHI no uma linguagem (a linguagem utilizada pelo DELPHI o PASCAL), uma Pag. 7/176

ferramenta de desenvolvimento, contendo um poderoso editor grfico ( que a estrutura inicial que iremos estudar) um compilador e um link editor (acionado pela tecla F9 como veremos a seguir) um utilitrio de debbug e tracing (para rastrear e identificar defeitos no programa em tempo de execuo), um gerenciador de banco de dados prprio (DBE com estrutura PARADOX, que tambm prpria do DELPHI), um manipulador de tabelas do banco de dados para que se possa criar todo o banco de dados (DATABASE DESKTOP), diversos componentes, incluindo integrao com vrios tipos de bancos de dados, programao para internet, tratamento de imagens e ainda outras ferramentas de conectividade. Podemos nesta primeira tela identificar trs janelas. A principal, que contem todos os comandos do DELPHI (na parte superior):

A OBJECT INSPECTOR, posicionada a esquerda:

E as janelas da Aplicao, ocupando o centro e encostada a direita (acima denominada Pag. 8/176

FORM1):

Sempre antes de comear, iniciamos uma nova aplicao: para isso, na janela principal, clique em FILE e depois em NEW APLICATION:

Note que, antes de iniciar o desenvolvimento necessrio definir se a aplicao ser compilada em KYLIX (para LINUX). Se a resposta for afirmativa, use CLX Application, se no, selecione Application. Vamos conhecer passo a passo como utilizar o DELPHI e construir pequenos programas. Inicialmente use a tecla F12. Cada vez que a teclar, o DELPHI alterna as telas da Pag. 9/176

aplicao, entre o formulrio (FORM1) e o programa fonte em PASCAL (UNIT1.PAS). Use a tecla F11 e estar alternando entre as telas de formulrio (FORM1) programa fonte (UNIT1.PAS) e a janela OBJECT INSPECTOR, que contem todas as propriedades e eventos do objeto que est selecionado no formulrio. Todos os itens existentes no formulrio contem sua prpria Janela OBJECT INSPECTOR, inclusive o prprio formulrio. Vamos salvar o nosso projeto. Para isso escolha a opo FILE, SAVE PROJECT AS e escolha um nome para UNIT1.PAS (por exemplo TESTE1, esta ser a unidade que estar ligada ao FORM1) e para o projeto ( por exemplo PROG1 ), que devem ser diferentes. Note que o nome do executvel ser o nome do projeto. Nunca altera estes nomes por fora do DELPHI (usando o WINDOWS EXPLORER por exemplo). Caso queira mudar o nome da unidade, use a opo SAVE AS, e do projeto, SAVE PROJECT AS. Use a tecla F9 para compilar e rodar o programa. Como nosso programa ainda no tem nada, ser compilado o formulrio em branco, aparecendo apenas o FORM1 com os botes padres no canto superior direito. Clique no X para fechar, voltando ao DELPHI. Para melhor visualizar seu programa, como prximo passo, vamos mudar algumas configuraes.Vamos acessar TOOLS e depois ENVIROMENT OPTIONS, ser apresentada a tela a seguir:

Clique em SHOW COMPILER PROGRESS (mostra o processo de compilao) e MINIMIZE ON RUN (minimiza o DELPHI quando estiver rodando o programa).

Vamos mudar outra configurao do DELPHI. Selecione a opo TOOLS, depois EDITOR Pag. 10/176

OPTIONS e depois COLOR. Nesta opo ser possvel fazer com que o editor do programa apresente caracteres com finalidades diferentes, escritos com cores diferentes. Na tela de configurao, mude pelo menos a cor das palavras COMMENT para azul, RESERVED WORDS para vermelho, SYMBOL para marrom, STRING para lils e NUMBER para verde. Isto ir facilitar, mostrando a finalidade de cada palavra ou caracter digitado, ficando mais fcil a correo:

Note que durante o processo de digitao ficar fcil identificar erros como falta de aspas em string, falta de pontuao, ou pontuao errada, variveis com nomes reservados (que proibido). Vamos mudar o titulo que aparece no formulrio. Clique no formulrio e use a tecla F11 at que a janela OBJECT INSPECTOR esteja ativada. Mude o campo CAPTION para Meu Primeiro Programa em DELPHI. Mude agora o nome do formulrio, que identificar o formulrio do programa. Mantenha a letra F para indicar que formulrio, por exemplo F_inicial. Use a tecla F9 e veja o resultado. O nome do formulrio nada influenciou no programa, apenas o CAPTION.

Pag. 11/176

2.3- Programao orientada a componente: Para facilitar, vamos inicialmente programar pensando nos objetos como componentes. Assim, iremos colocar componentes em nossa aplicao de acordo com a nossa necessidade. Vamos incluir o primeiro texto. Para isto clique no boto de LABEL e clique no formulrio. O DELPHI colocar um LABEL (texto) no seu formulrio:

Ajuste o texto, atravs da sua OBJECT INSPECTOR para que apresente a mensagem, conforme apresentado a seguir :

Para estes ajustes, clique na janela OBJECT INSPECTOR, Mude o CAPTION e depois clique no FONT (+) e aparecero as configuraes dos caracteres. Mude cor, tamanho, tipo e fonte. Pag. 12/176

Clique agora em eventos e de um duplo clique na parte branca em frente ao ON CLICK, ficar:

Inclua agora o condicional para mudar a cor do texto. Entre o Begin e o end; digite: if Label1.Font.Color=clRed then Label1.Font.Color:=clBlue else Label1.Font.Color:=clRed; O resultado ser:

Pag. 13/176

Use agora o F9 para COMPILAR, LINKAR e EXECUTAR. Ao executar o programa, clique no texto ol mundo e voc perceber que o texto muda de cor. Isto por que estamos mudando uma propriedade do LABEL. Esta a base de funcionamento do DELPHI: manipular propriedades, eventos e mtodos dos objetos de cada formulrio, a partir de um evento acionado pelo usurio. Este processo ganha muito em produtividade na formatao de telas, perde somente para programao de procedimentos. Note que mesmo programando com DELPHI precisamos ter pleno controle dos condicionais, pois so eles que executam os processos dentro do sistema, mesmo que este sistema seja ORIENTADO A OBJETO. Como prximo passo inclua um boto de SAIDA. Ao clicar este boto o programa dever ser abandonado. Isto se consegue incluindo o objeto boto e no seu evento ON CLICK colocaremos o comando CLOSE. Como estamos fechando o formulrio principal, automaticamente o programa abandonado. Veja a tela:

e o evento :

Vamos agora incluir : Pag. 14/176

1- um boto de OK que no evento ON CLICK ir executar o comando : Showmessage(digite ok); Que mostra uma tela com boto de OK 2- EDIT que no evento ON CLICK ir executar o comando: Edit1.text:=; Que limpa a caixa de texto 3- um boto MOSTRA que no evento ON CLICK ir executar o comando: Label2.Caption:=Edit1.text; Que muda o LABEL2 deixando igual ao que foi escrito na caixa EDIT O resultado ser :

Vamos agora incluir um RADIO BUTTON com a mensagem selecionado e um novo BUTTON (boto) com o nome SELECIONA. Este boto ser capaz de deixar o RADIO BUTTON Selecionado se no estava, e no selecionado se estava. Para isso, no ON CLICK do boto SELECIONA, mudamos a propriedade CHECKED do RADIO BUTTON.

Veja como fica a programao : Pag. 15/176

if RadioButton1.Checked=true then RadioButton1.Checked:=false else RadioButton1.Checked:=true; A nossa tela ficar assim:

Vamos agora incluir um novo boto. Este novo boto ir chamar um novo formulrio. Este novo formulrio possuir um campo de EDIT e um LIST BOX. Sempre que eu digitar ENTER no campo EDIT, o sistema dever perguntar se deseja incluir a mensagem no LIST BOX. Se a resposta for positiva, incluir. Para isso, precisamos inicialmente incluir o boto incluso e criar um novo formulrio. Para isto clique em FILE, NEW FORM. Mude inicialmente o CAPTION do formulrio, alterando-o para incluso. Inclua um EDIT, um LIST BOX e um boto SAIDA. No CAPTION do boto sada, coloque um & antes do S e ver que o S passa a ficar sublinhado, indicando que se for acionado o comando ALT S, ser a mesma coisa que clicar no boto. Mude tambm o nome do formulrio para FINCLUSAO para ficar mais fcil de identificar. No esquea de no evento ON CLICK do boto de sada colocar o comando CLOSE. A seguir apresentamos os resultados destas alteraes:

Pag. 16/176

Volte agora para o formulrio principal. No evento ON CLICK do boto INCLUSAO, coloque o comando FINCLUSAO.SHOWMODAL; Compile para ver os resultados ( F9) . Note que o DELPHI perguntar se a varivel Finclusao que foi mencionada deve ser definida. Responda Sim e mande compilar de novo. Vamos agora incluir a programao para, ao digitarmos um texto na caixa EDIT e usarmos o ENTER, este texto ser adicionado ao LIST BOX mediante confirmao do usurio. Selecione o EDIT e no seu evento ONKEYDOWN coloque a programao : if Key=VK_RETURN then if MessageDlg('Confirma a incluso do texto ?', Mtinformation, [mbYes,mbNo], 0)=mryes then ListBox1.Items.Add(Edit1.Text); KEY : retorna a tecla digitada pelo usurio VK_RETURN : varivel interna que contem o cdigo da tecla enter MESSAGEDLG : funo que cria uma caixa de dilogo permitindo ao usurio escolher ente LISTBOX1.ITEMS.ADD(EDIT1.TEXT): inclui no LIST BOX o contedo de EDIT1.TEXT Podemos melhorar ainda, fazendo com que, alem de incluir o item no LIST BOX, apague o contedo do EDIT. Neste caso mudamos o cdigo acima para: if Key=VK_RETURN then if MessageDlg('Confirma a incluso do texto', Mtinformation, [mbYes,mbNo], 0)=mryes then begin ListBox1.Items.Add(Edit1.Text); Edit1.Text:=; End; Note que na mesma posio que criamos o formulrio o mesmo executado. Para alterar isto, acesse as propriedades do formulrio em questo e mude sua propriedade POSITION para PODESKTOPCENTER. Com esta configurao a tela aparecer no meio. Pag. 17/176

Vale Ressaltar a diferena que existem nos trs eventos de tecla digitada: ONKEYPRESS : o primeiro a ser acessado, e a tecla digitada retornada como sendo caracter (CHAR). Neste caso a tecla pode ser comparada diretamente com seu cdigo ASC, pela funo #asc (#13 o enter, por exemplo) ou com a funo CHR(), associada varivel de ambiente VK_tecla (CHR(VK_ENTER)), por exemplo). Vale ressaltar que este evento no acessado caso seja pressionada uma tecla que seja de controle, como as teclas F1 a F12, insert, etc... ONKEYDOW: o segundo evento a ser acessado, e a tecla digitada retornada como sendo u byte (WORD). Neste caso a tecla pode ser comparada diretamente com a varivel de ambiente VK_tecla (VK_F1, por exemplo) ONKEYUP: o terceiro evento a ser acessado, e a tecla digitada retornada como sendo u byte (WORD). Neste caso a tecla pode ser comparada diretamente com a varivel de ambiente VK_tecla (VK_F1, por exemplo) Vamos agora fazer a nossa prpria opo MESSAGEDLG. Vamos chamar este procedimento de XXOPCAO. Este procedimento receber uma pergunta e apresentar dois botes : se for clicado o boto SIM, retorna SIM se for clicado NAO retornar NAO. Vamos incluir uma nova caixa no formulrio de incluso para implementar esta funo. Veja a seguir como fica:

O fonte do nosso xxopcao fica (comentrios na cor marrom): unit xxopcao;// as duas barras indicam observao de uma linha esta linha determina o nome da unidade { as chaves determinam o inicio das observaes, mesme que sejam por varias linhas, e ser fechada com a chaves ao contrrio } interface // apresenta as definies referentes a processamento entre formulrios da aplicao uses // lista de bibliotecas utilizadas Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; Type { classes criadas na unidade. Note que foi criada a classe Tfcxxopcao a partir da classe Tform, este o conceito de Herana, a classe Tfcxxopcao passa a ter todas as propriedades, mtodos e eventos da classe original. Pag. 18/176

Tfxxopcao = class(TForm) // aqui esto os components que passam a ser considerados como propriedades da classe criada Sim: TButton; // proveniente da classe Tbutton, responsvel por gerar botes. Nao: TButton; Label1: TLabel; // aqui est os eventos desta classe procedure SimClick(Sender: TObject); procedure NaoClick(Sender: TObject); private { Private declarations } // propriedades e mtodos enxergados somente por esta UNIT public { Public declarations } // propriedades e mtodos enxergados por todas UNIT que referenciem esta UNIT end; var { aqui so inclusas as variveis puras. Para serem enxergadas em outras UNIT devem ser por elas referenciadas } fxxopcao: Tfxxopcao; ropcao: string; implementation // inicio da programao {$R *.DFM} // indica que para compilar todos os formulrios de mesmo nome. procedure Tfxxopcao.SimClick(Sender: TObject); // evento on click do boto sim begin ropcao:='SIM'; close; end; procedure Tfxxopcao.NaoClick(Sender: TObject); // evento on click do boto no begin ropcao:='NAO'; close; end; end. Note que no fonte acima, inclumos MANUALMENTE a varivel ropcao ( destacada em negrito-itligo) . O procedimento em vermelho o evento ON CLICK do boto SIM. Neste evento inclumos a atribuio da varivel ropcao:=SIM MANUALMENTE que ser o resultado do procedimento ao ser clicado o boto SIM. Note que em seguida fechamos o formulrio com o comando CLOSE. O procedimento em AZUL o evento ON CLICK do boto NAO. Neste evento inclumos a atribuio da varivel ropcao:=NAO MANUALMENTE que ser o resultado do procedimento ao ser clicado o boto NAO. Note que em seguida fechamos o formulrio com o comando CLOSE.

Pag. 19/176

Para utilizar o nosso xxopcao, vamos no formulrio de incluso colocar mais um campo EDIT, conforme apresentado a seguir :

Neste campo EDIT, no evendo ON KEY DOWN colocamos a programao: if key=VK_RETURN then // IDENTIFICA QUE FOI DIGITADO O ENTER begin fxxopcao.label1.caption:='Confirma a incluso ?'; // APRESENTA A MENSAGEM NO XXOPCAO fxxopcao.showmodal; // MOSTRA O FORMULARIO XXOPCAO if xxopcao.ropcao='SIM' then // SE FOI DIGITADO SIM NO FXXOPCAO begin ListBox1.Items.Add(Edit2.Text); // INCLUI O ITEM Edit2.Text:=''; // ZERA O CONTEUDO DO CAMPO end; end; end; Note que o IF XXOPCAO.ROPCAO serve para identificar que a varivel ROPCAO uma varivel que foi definida na unidade XXOPCAO. importante entender a diferena que existe entre a UNIT que o programa fonte, e o FORM que so os formulrios. Caso seja necessrio, poder trabalhar com este formulrio em modo texto. Para isso basta clicar, sobre o formulrio, com o boto direito. Escolha a opo VIEW AS TEXT e o DELPHI abrir o formulrio em modo texto. Note que este formulrio nada mais que uma relao de definies de propriedades de objetos. Todas as propriedades necessrias para a definio de formato, tamanho, posio cor, e demais propriedades obrigatrias, do objeto em questo so definidas aqui. Note que todos os objetos que podem ser colocados dentro de outros objetos, como o LABEL dentro de um GROUPBOX se encontra dentro do mesmo definido antes da sua finalizao.

Pag. 20/176

Veja o formulrio acima em modo texto: object Form1: TForm1 Left = 228 Top = 110 Width = 565 Height = 500 Caption = 'Incluso' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object ListBox1: TListBox Left = 72 Top = 96 Width = 201 Height = 297 ItemHeight = 13 TabOrder = 0 end object Edit1: TEdit Left = 320 Top = 128 Width = 177 Height = 21 TabOrder = 1 end object Edit2: TEdit Left = 320 Top = 200 Width = 177 Height = 21 TabOrder = 2 end object Button1: TButton Left = 352 Top = 296 Width = 97 Height = 33 Caption = 'Saida' TabOrder = 3 end end Pag. 21/176

2.4- Entendendo melhor o programa fonte (UNIT.PAS) O programa fonte (*.pas) pode ser dividido nas partes: Para entender vamos apresentar as partes de um programa fonte de um formulrio com apenas um boto e uma chamada a um segundo formulrio. Para isso vamos criar uma aplicao conforme a figura a seguir:

Inclua o formulrio em branco, clicando no boto indicado na figura a seguir:

Automaticamente este ser o FORM2.

Pag. 22/176

No evento ON CLICK do boto do FORM1, coloque o comando: FORM2.SHOWMODAL; Ao compilar o DELPHI pede confirmao para introduzir a referencia do formulrio, confirme. Pronto. Veja como ficou o programa fonte, comentado linha a linha: unit Unit1; NOME DA UNIT, DO PROGRAMA FONTE interface INICIO DO FONTE uses BIBLIOTECAS DE COMPONENTES E FUNES UTILIZADAS, SO DO DELPHI Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type CRIAO DA CLASSE, UM TYPE PARA CADA CLASSE TForm1 = class(TForm) CLASSE Tform1 DE FINIDA A PARTIR DA CLASSE PADRO TFORM Button1: Tbutton; BOTAO 1, UM COMPONENTE DO FORMULRIO procedure Button1Click(Sender: Tobject); EVENTO ON CLICK DO BOTO BUTTON1 private { Private declarations } DECLARAES VISTAS SOMENTE POR ESTE FORMULRIO AQUI PODEM SER INCLUSOS PROPRIEDADES E MTODOS DESTE FORMULRIO public { Public declarations } DECLARAES VISTAS POR TODOS FORMULRIOS QUE, DENTRO DA SUA implementation TIVER, NO uses A REFERENCIA DESTA unit end; var VARIVEIS DESTA UNIT. Form1: Tform1; CRIA A INSTNCIA DO FORMULRIO Form1 implementation IMPLEMENTAO DO FONTE uses Unit2; REFERENCIAS DE OUTROS FORMULRIOS {$R *.dfm} NOME DO ARQUIVO QUE CONTM A CONFIGURAO DO FORMULRIO A PARTIR DAQUI APARECEM OS EVENTOS E SERO COLOCADAS AS PROGRAMAES procedure TForm1.Button1Click(Sender: Tobject); EVENTO ON CLICK DO BOTO BUTTOM1 begin FORM2.SHOWMODAL; PROGRMAO COLOCADA PELO PROGRAMADOR end; end. FIM DO PROGRAMA FONTE

Pag. 23/176

Veja agora o Form1 em formato texto: object Form1: Tform1 FORMULRIO E SUAS PROPRIEDADES Left = 192 Top = 124 Width = 388 Height = 342 Caption = 'Form1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Button1: Tbutton COMPONENTE BUTTON1 DO FORMULARIO Left = 136 Top = 152 Width = 75 Height = 25 Caption = 'FORM 2' TabOrder = 0 OnClick = Button1Click NOTE QUE AQUI FICA A CHAMADA AO EVENTO ONCLICK end end

Pag. 24/176

2.5- Entendendo EVENTOS, MTODOS, PROCEDIMENTOS e FUNES Vamos entender melhor o que so eventos, mtodos, procedimentos e funes EVENTO: uma ao do usurio. O DELPHI permite criar uma programao para cada um dos eventos possiveis de um componentes. Entre eles, ON CLICK (Quando o operador do programa clica com o MOUSE) ON KEY DOWN (quando o operador digita uma tecla). Todos os EVENTOS SO PROCEDIMENTOS. IMPORTANTE: O DELPHI cria automaticamente a definio e o esqueleto do detalhamento, bastando que vc digite apenas a programa dentro do EVENTO. PROCEDIMENTO: Trecho de programao, que recebe um nome, pode ou no possuir parmetro, mas NUNCA tem retorno. Para ser criado necessrio sua chamada, que pode ser colocada diretamente como um procedimento puro (diretiva VAR) ou como METODO os EVENTO de uma classe. Para criar um procedimento usada a diretiva procedure Veja no fonte apresentado no tpico anterior. A definio do procedimento : procedure Button1Click(Sender: Tobject); EVENTO ON CLICK DO BOTO BUTTON1 como este procedimento est referenciado na definio do componente (veja no exemplo anterior, no formato texto da aplicao), ele ser executado no momento do ONCLICK OnClick = Button1Click NOTE QUE AQUI FICA A CHAMADA AO EVENTO ONCLICK Na parte de implementao do fonte, encontramos o detalhamento do procedimento: procedure TForm1.Button1Click(Sender: Tobject); EVENTO ON CLICK DO BOTO BUTTOM1 begin FORM2.SHOWMODAL; PROGRAMAO COLOCADA PELO PROGRAMADOR end; Note que voc poder criar PROCEDIMENTO que NO SEJAM EVENTOS. Portanto, iro processar algo, para uma determinanda finalidade, mas no precisam estar ligado a um EVENTO de um componente. MTODOS: os mtodos podem ser PROCEDIMENTOS ou FUNES e servem para alterar caracteristicas de componentes. Normalmente j fazem parte da piblioteca do componente, e voc no necessitar criar, a menos que precise de algo que no exista no DELPHI. FUNES: Trecho de programao, que recebe um nome, pode ou no possuir parmetro, mas SEMPRE tem retorno. Para ser criado necessrio sua chamada, que pode ser colocada diretamente como uma funo pura (diretiva VAR) ou como METODO de uma classe. Para criar uma funo usada a diretiva function Veja o exemplo a seguir, que criaria um mtodo do formulrio form1, para verificar uma data. Primeiro coloque sua chamada na diretiva private ou public:

Pag. 25/176

Function verifica_data(data:string):boolean; Depois, aps a diretiva Implementation, coloque a programao: Function tform1.verifica_data(data:string):boolean; Begin Try Strtodate(data); // converte o string para data Result:=true; // retorna true se a data for valida Except Result:=false; // se nao for possivel executar strtodate, retorna falso End; End; Note que atravs da varivel Result passamos o resultado da funo. Veja agora um exemplo de uma UNIT que possui uma classe, destinada a conter vrios mtodos de uso geral. Estes mtodos podem ser procedimentos ou funes, de acordo com a necessidade: Unit teste Interface Uses Windows, Messages, SysUtils, StdCtrls; Type TP_F = class estamos criando uma classe em branco para colocar todas as funes e procedimentos Public definiremos as funes e procedimentos como public para que possam ser acessadas por qualquer unit Procedure mostraoi; procedimento sem parmetro Procedure mostramensagem(mostra:string); procedimento com parmetro mostra Function somainttofloat(x:integer;y:integer):float; funo com dois parmetros (x e y) e retorno End; // fim da definio da classe Var aqui incluem-se as variveis que podem ser enxergadas pelas UNIT que tenham esta em sua referncia P_F:TP_F; criou-se a instncia P_F, com todos os mtodos (procedimentos e funes) acima implementation procedure TP_F.mostraoi; begin showmessage(oi, sou um procedimento); Pag. 26/176

end; procedure TP_F.mostramensagem(mostra:string); begin showmessage(devo mostrar :+mostra); end; Function TP_F.somainttofloat(x:integer;y:integer):float; begin result:=strtofloat(inttostr(x+y)); end; end. finaliza a UNIT Para utilizar qualquer um destes procedimentos nesta UNIT, basta usar o nome do mesmo. Caso queira utilizar este procedimento em qualquer outra UNIT, no esquea de mencionar o nome desta UNIT no USES depois do INPLEMENTATION na UNIT onde o mtodo aqui criado ser utilizado, indicando a classe a que ele pertence. Ex.: P_F.mostramensagem(teste); A grande vantagem de se criar funes e procedimentos como sendo mtodos de uma classe, que, ao digitarmos o nome de qualquer objeto e colocarmos o ponto e pararmos a digitao, o DELPHI mostra uma tela contendo todas as propriedades, mtodos e eventos que podem ser acessados em tempo de execuo, ficando fcil de relembrar o nome do que estamos querendo acessar. Ao criar uma funo ou um procedimento puro, no teramos este recurso. Aplicando os conhecimentos anteriores, vamos desenvolver uma aplicao. Primeiro iniciamos um novo projeto: O Delphi iniciar como UNIT1 E FORM1. O primeiro passo salvar a aplicao. Vamos dar a UNIT1 o nome PRINCIPAL, pois o primeiro formulrio que ser executado. O projeto chamaremos de EXEMPLO_A. Ser tambm o nome do executvel. Na propriedade NAME do formulrio, colocaremos F_PRINCIPAL. Veja que acessando PROJECT e depois OPTIONS, ser apresentada a tela:

Pag. 27/176

Note que o DELPHI define automaticamente o primeiro fomulrio como o principal, o primeiro que ser executado, portanto, para executarmos comandos logo no inicio da aplicao, devemos colocar estes comandos no primeiro evento que acontece neste formulrio. Para conhecermos a ordem que se d uma determinada sequncia de eventos de um componente, podemos utilizar o SHOWMESSAGE. Vamos ento colocar: showmessage('estou do CREATE'); NO EVENTO ONCREATE do formulrio showmessage('estou do SHOW'); NO EVENTO ONSHOW do formulrio showmessage('estou do ACTIVE'); NO EVENTO ONACTIVATE do formulrio Ao compilar, linkar e executar a aplicao, atravs da tecla F9, as mensagens sero apresentadas exatamente na sequencia anterior. Note que no ACTIVATE o formulrio j aparece no funco da tela. Outra forma de conhecer a sequncia dos eventos, pois o clique no SHOWMESSAGE pode atrapalhar a execuo de eventos, e colocar um LISTBOX e nele incluir os nomes dos eventos, assim, aparecero do LISTBOX na ordem que foram executados.

Pag. 28/176

Para testar este procedimento vamos incluir um EDIT, um LISTBOX, e os comandos: ListBox1.Items.Add('down'); no evento ONKEYDOWN do EDIT ListBox1.Items.Add('press'); no evento ONKEYPRESS do EDIT ListBox1.Items.Add('up'); no evento ONKEYUP do EDIT No LISTBOX aparecer:

Vamos agora incluir um novo formulrio, clicando no NEW FORM:

Vamos salvar nossa aplicao, e a UNIT1 que foi criada, chamaremos de segundo. Foltamos ao novo formulrio, e na propriedade NAME colocamos F_segundo. Agora incluimos um boto em nosso formulrio principal, e a chamada a este formulrio: F_segundo.showmodal; ao compilar, o DELPHI apresentar a mensagem:

Pag. 29/176

Esta mensagem est avisando que do F_principal existe uma chamada ao F_segundo da UNIT segundo, que no est na lista de USES. E pergunta se quer adicionar. Clicando no YES, o DELPHI incluir na lista de USES da implementao o comando: implementation uses segundo; Vamos nesta segunda tela colocar um EDIT e criar uma funo capaz de bloquear a introduo de letras, transformar ponto em vigula, e deixar introduzir o ponto, ou a virgula somente uma vez. Inicialmente definimos a funo, na diretiva PUBLIC, o que tornar esta funo um MTODO do formulrio F_segundo. Se quisermos utilizar esta funo em outros formulrio, deveremos cham-la como F_segundo.<nome da funo>. Defina ento a funo: public { Public declarations } function pega_numero(variavel:char;conteudo:string):char; Agora, no final da UNIT (antes do end.) crie a funo: function TF_segundo.pega_numero(variavel:char;conteudo:string):char; begin result:=variavel; if Ansipos(variavel, '.,') > 0 then begin if Ansipos(',', conteudo) = 0 then result := ',' else result := chr(0); end else if Ansipos(variavel, '0123456789' + chr(8)) = 0 then result := chr(0); end; Agora, no evento ONKEYPRESS do EDIT, coloque a chamada da funo: with sender as Tedit do key := F_segundo.pega_numero(key, text); Veja que, como usamos SENDER, este evento pode ser usado para todo edit numrco, sem a necessidade de repetir programao.

Pag. 30/176

2.5.1- Os eventos mais importantes vamos agora apresentar uma relao dos eventos mais importantes dos objetos. Como voc poder constatar, muitos deles j foram utilizados. Evento OnCLick Descrio ao clicar no objeto Classes TButton (boto); TForm (formulrio);TEdit (caixa de texto); Tlabel (texto)

OnEnter OnExit OnKeyDown

ao entrar no objeto (quando o objeto ficar TButton; TForm;TEdit ativo, no momento do seu acesso inicial) ao sair do objeto (ele estava selecionado e TButton; TForm;TEdit outro objeto foi selecionado) uma tecla foi digitada (seu conteudo ainda TButton; TForm;TEdit no foi atribudo a nada, seu contedo WORD) uma tecla foi digitada (seu conteudo ainda TButton; TForm;TEdit no foi atribudo a nada, seu contedo CHAR) a tecla acabou de ser solta, e seu conteudo TButton; TForm;TEdit j foi atribuido. seu contedo WORD o boto do mouse foi precionado o boto do mouse foi solto o mouse foi movimentado sobre o objeto foi dado um duplo clique o formulrio apareceu o formultio foi ativado o formulrio foi fechado o formulrio foi criado o formulrio foi destruido TButton; TForm;TEdit TButton; TForm;TEdit TButton; TForm;TEdit TButton; TForm;TEdit TForm (formulrio) TForm (formulrio) TForm (formulrio) TForm (formulrio) TForm (formulrio)

OnKeyPress

OnKeyUp OnMouseDown OnMouseUp OnMouseMove OnDblClick OnShow OnActive OnClose OnCreate OnDestroy OnKeyDown

(com KeyPreview = true): uma tecla foi TForm (formulrio) digitada, se sobrepe ao de todos os componentes o contedo do edit foi alterado TEdit (caixa de texto);

OnChange

Pag. 31/176

2.5.2- Que evento ultizar? Surge para o aluno uma pergunta: que evento devo utilizar? A deciso de usar um evento ou outro vem de outras perguntas: 1- que prioridade preciso dar ao comando que vou executar? Quanto maior a prioridade, preciso utilizar o evento mais antecessor, ou seja, que acontece antes de qualquer outro. Numa aplicao, todos os comando iniciais, colocamos no evento ONCREATE do formulrio principal. Os comandos iniciais, que devem acontecer antes do formulrio ser acessado, mas j com seus componentes disponveis, devem ser colocados no evento ONSHOW. 2- Que parametros preciso ter disponivel? Se voc precisa ter a posio do mouse sobre um formulrio, por exemplo, no pode usar o evento ONCLICK, se voc criar este evento, ver que ele no fornece as coordenados do mouse: procedure TForm1.FormClick(Sender: TObject); begin end; Se voce utilizar o evento ONMOUSEDOWN: procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end; Veja que o procedimento informa o boto que foi usado, atrabs da varivel Button que do tipo TmouseButton, se foi apertada tambm uma tecla de controle, atravs da varivel Shift, do tipo TshiftState, e ainda as coordenadas do MOUSE atravs das variaveis X e Y que so inteiras. Para a variavel do tipo TmouseButton , seu retorno ser: (mbLeft, mbRight, mbMiddle) posso ento fazer um teste: if (Button = mbLeft) then ... Para a variavel do tipo TshiftState , seu retorno ser: SET OF (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble) posso ento fazer um teste: if ( Shift = [ssShift,ssLeft]) then Note que como o TshiftState um SET OF, na comparao devem existir todos os estados que ele assume. No exemplo acima, foi segurada a tecla Shift e clicado com o boto esquerdo do mouse.

Pag. 32/176

3- Qual o tipo do parmetro que preciso? No evento ONKEYDOWN a tecla digitada, retornada como key do tipo word (cdigo ASCII) No evento ONKEYPRESS a tecla digitada, retornada como key do tipo char (caracter) Da relao de eventos acima preciso ressaltar que, caso voc precise que uma determinada tecla tenha efeito imediato e anterior ao evendo de qualquer componente, a programao desta decla deve ser colocada no evento ONKEYDOWN do formulrio, a a propriedade KEYPREVIEW do formulrio de ve estar TRUE. Veja um exemplo para que a aplicao seja abandonada quando a tecla ESC for digitada, em qualquer ponto do formulrio, ou qualquer componente: 2.5.3- Abandonando a aplicao com ESC Primeiro mude a propriedade KEYPREVIEW do formulrio para TRUE; Agora, no evendo ONKEYDOWN do formulrio, coloque a progralao a seguir (em vermelho): procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin IF KEY=27 THEN CLOSE; end;

Pag. 33/176

2.6- Programando por evento Vamos agora apresentar uma forma de programao que consiste em programar de forma direcionada ao evento dos compenentes. Esta forma permite que travemos a aplicao, forando o operador a seguir uma determinhada sequencia. Veja a tela a seguir:

Vamos agora amarrar a aplicao, ou seja, deixar habilitado somente o primeiro componente, onde o operador dever digitar o valor, finalizando por <ENTER>. Os demais componentes deixaremos desabilitados. A tela, ao executar, ficar assim:

Pag. 34/176

Note que mesmo clicando nos demais componente, o cursos continua no primeiro campo. Para ficar mais claro, vamos colocar um comando que moda a cor para amarelo, quando o foco entrar no edit. Assim, coloque no evento ON ENTER do primeiro edit a programao: with sender as Tedit do color:=clYellow; Compile novamente e o resultado ser:

No evento de saida, valor voltar a cor original, colocando a programao: with sender as Tedit do color:=clwhite; Agora, para todos os demais EDITs, colocaremos, em seu evento ON ENTER, a chamada ao evento criado para o promeiro edit. Como a programao genrica, funcionar para qualquer que seja o SENDER, se o SENDER for TEDIT. Veja o object inspector do segundo edit como fica, quando configuramos a chamada ao evendo do primeiro edit, na figura a seguir. Note que no Edit2, em seu evendo OnEnter, estamos chamados o Edit1Enter. Isto economiza cdigo.

Pag. 35/176

Agora, faremos com que, no evento keydonw, quando o operador digitar ENTER, a aplicao desabilitar o anterior, habilitar o proximo campo, e mudar o foco para a prximo. Veja a programao para o evendo ONKEYDOWN: procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key = 13 then begin Edit1.Enabled := false; Edit2.Enabled := true; Edit2.SetFocus; end; end; No esquea que o comando de habilitao tem SEMPRE que estar ANTES do comando SETFOCUS, ou ocorrer um erro:

Pag. 36/176

Mudando o nome dos botes para Bsoma, Bsubtrai, Bdivide e Bmultiplica, ficar mais intuitivo, e o fonte completo fica: unit principal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; GroupBox1: TGroupBox; Bsoma: TButton; Bsutrais: TButton; Bdivide: TButton; Bmutiplica: TButton; procedure Edit1Enter(Sender: TObject); procedure Edit1Exit(Sender: TObject); procedure Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure Edit2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure BsomaClick(Sender: TObject); procedure BsutraisClick(Sender: TObject); procedure BdivideClick(Sender: TObject); procedure BmutiplicaClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Edit1Enter(Sender: TObject); begin with sender as Tedit do color := clYellow; end; Pag. 37/176

procedure TForm1.Edit1Exit(Sender: TObject); begin with sender as Tedit do color := clwhite; end; procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key = 13 then begin Edit1.Enabled := false; Edit2.Enabled := true; Edit2.SetFocus; end; end; procedure TForm1.Edit2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key = 13 then begin Edit2.Enabled := false; GroupBox1.Enabled := true; Bsoma.SetFocus; end; end; procedure TForm1.BsomaClick(Sender: TObject); begin Edit3.Text := floattostr(strtofloat(Edit1.Text) + strtofloat(Edit2.Text)); GroupBox1.Enabled := false; Edit1.Enabled := true; Edit1.SetFocus; end; procedure TForm1.BsutraisClick(Sender: TObject); begin Edit3.Text := floattostr(strtofloat(Edit1.Text) - strtofloat(Edit2.Text)); GroupBox1.Enabled := false; Edit1.Enabled := true; Edit1.SetFocus; end; procedure TForm1.BdivideClick(Sender: TObject); begin if strtofloat(Edit2.Text) = 0 then showmessage('diviso por zero') else Pag. 38/176

Edit3.Text := floattostr(strtofloat(Edit1.Text) / strtofloat(Edit2.Text)); GroupBox1.Enabled := false; Edit1.Enabled := true; Edit1.SetFocus; end; procedure TForm1.BmutiplicaClick(Sender: TObject); begin Edit3.Text := floattostr(strtofloat(Edit1.Text) * strtofloat(Edit2.Text)); GroupBox1.Enabled := false; Edit1.Enabled := true; Edit1.SetFocus; end; end. Podemos ainda economizar programao, ao invs de colocar um evento para cada boto vamos criar um evento s para os quatro. Para isso, apague todos os eventos dos botes e crie, somente no primeiro boto, o evento on click, com a programao: with sender as Tbuttom do begin try case Ansipos(caption,'+-*/') of 1: Edit3.Text := floattostr(strtofloat(Edit1.Text) + strtofloat(Edit2.Text)); 2: Edit3.Text := floattostr(strtofloat(Edit1.Text) - strtofloat(Edit2.Text)); 3: Edit3.Text := floattostr(strtofloat(Edit1.Text) * strtofloat(Edit2.Text)); 4: if strtofloat(Edit2.Text) = 0 then showmessage('diviso por zero') else Edit3.Text := floattostr(strtofloat(Edit1.Text) / strtofloat(Edit2.Text)); end; except showmessage('valores invlidos') end; end; Pronto, agora nos demais boto, configure-os para chamar o evento ON CLICK do boto 1

Pag. 39/176

RESUMO: Vamos agora fazer um resumo das principais informaes passadas at aqui. Aprendemos a criar variveis: var i: integer; x:real; teste:string; aprovado:boolean; nome_extenso:AnsiString; Aprendemos a criar funes: No public definimos (na verdade um MTODO que estamos criando para o formulrio): Function somainttofloat(x:integer;y:integer):float; aps o implementation, detalhamos: Function Tform1.somainttofloat(x:integer;y:integer):float; begin result:=strtofloat(inttostr(x+y)); end; Aprendemos as propriedades: caption texto (STRING) do LABEL, do FORM, do BUTTOM, do CHECKBOX text texto (STRING) do EDIT, LISTBOX, COMBOBOX visible todos componentes visiveis enabled - quase todos (connected, active,...) left - todos componentes visiveis top - todos componentes visiveis width - todos componentes visiveis height - todos componentes visiveis Aprendemos os mtodos: add adiciona itens, em componentes com propriedade Tstring setfocus muda o foco do componente (PRECISA, PARA A TECLA ENTER) clear limpa o conteudo do compoente: LISTBOX, COMBOBOX, EDIT Aprendemos as funes: Ansipos(a,b) indica a posio inicial do string a no string b floattostr(x) converte x (real) para string strtofloat(x) converte x (string) em real inttostr(x) inteiro para string strtoint string para inteiro length(x) retorno o comprimento do string x copy(x,i,j) retorna substring de X, a partir da posio i, j caracteres. trim(x) tira espaos em branco a direita. Pag. 40/176

Aprendemos a otimizar a nossa aplicao: with sender as <classe> do begin end; Aprendemos as diretivas: if <condio> then begin end else begin end; while <condio> do begin end; case <retorno inteiro> of 1: begin end; 2: begin end; else begin end; end; for i:=<inteiro> to <inteiro> {downto} {step <inteiro>}

Pag. 41/176

2.6.1- O componente TIMER Acessando a palheta SYSTEM, voc encontrar o componente TIMER. Este compenente TIMER serve para executar um procedimento, a cada INTERVAL transcorrido (propriedade do componente que se trara de tempo a esperar em milisegundos), se o componente estiver ENABLED (true). O exemplo que uso mais simples apresentar a hora la tela. Para isso coloque um LABEL no formulrio, mudando a propriedade NAME dele para Lhora. Mude a propriedade VISIBLE para false. Coloque agora no formulrio o componente TIMER, mantendo o INTERVAL em 1000 (a cada segundo) e habilitado (ENABLED=TRUE). No evento ONTIMER, coloque os comandos: Lhora.visible:=true; Lhora.caption:=timetostr(time); Com estes comandos sero execuados a cada segundo: o TIMER deixar o LABEL visivel (na verdade somente precisaria na primeira vez) e atribuir ao label a hora atual. Podemos usar o TIMER para verificar TIME OUT. Outra aplicao simular movimento: Para testar, coloque um componente no meio do formulrio e um TIMER, mudando seu interval para 100. No seu evento, coloque <componente>.left:=<componente>.left+1; execute a aplicao e voc ver o componente se movimentando para a direita.

Pag. 42/176

2.7- Grficos: a classe Tcanvas Esta classe permite desenhar superficies a partir de pixels. A resoluo a mesma utilizada para localizao de componentes no formulrio. O canto superior direito a posio 0,0, e o campo inferior direito dado pelo TOP e pelo WIDTH do formulrio. Note que a simples clamada do objeto faz com que a aplicao o crie, sem a necessidade de uma declarao. Por exemplo, se colocamos o comando CANVAS.MOVETO(0,0) em qualquer evento da aplicao, o objeto CANVAS automaticamente criado, e a aplicao executa o metodo MOVETO. Apresentamos a seguir a relao dos principais mtodos e sua finalidade: Mtodo Draw Arc Ellipse Rectangle MoveTo LineTo TextOut Polygon Finalidade Desenha um grfico/cone Desenha um arco Desenha uma elipse, dentro do paralelogramo de vrtices diagonais fornecidos Faz um retangulo Posiciona a referncia em uma posio Faz uma linha da referencia anterior at a referencia informada Desenha um texto onde se encontra a referencia Faz um poligono a partir de uma relao ordenada de pontos (array) Agora apresentamos as principais propriedades desta classe: CanvasOrientation Brush Font Pen Define a orientao dos graficos Define a cor do preenchimento de figuras cheias (Ellipse, Rectangle, e outras) Define a fonte do TextOut Define a cor das linhas

Pag. 43/176

Para explicar a classe Tcanvas, vamos desenvolver uma aplicao conforme a tela a seguir:

O objetivo desta aplicao fazer com que o operador clique com o mouse, indicando os pontos a serem utilizados, e depois escolher o que vai desenhar: uma reta, um circulo ou um triangulo. Alm dos componentes descritos na tela anterior, precisaremos criar variveis de uso geral. Veja como fica a diretiva VAR do formulrios principal:
var form_principal: Tform_principal; VG_X1: integer; VG_Y1: integer; VG_X2: integer; VG_Y2: integer; VG_X3: integer; VG_Y3: integer; FLAG: integer;

Usamos VG para inidicar Varivel Geral, Y,Y para coordenadas, e 1,2 ou trs o nmero de ordem do ponto.

Pag. 44/176

Para ficar mais amigvel, deixaremos todos os componentes invisveis, a faremos com que eles apaream de acordo com a seleo dos pontos. Isso porque sem dois pontos, no possivel fazer uma reta, e sem trs pontos, no se pode fazer um triangulo. Para facilitar, orientaremos, para o operador, o que deve ser feito, passo a passo:

Nesta tela, todos os demais componentes apresentados na tela de desenvolvimento estaro inivisveis. A cada passo ser necessrio desabilitar componentes anteriores e habilitar os componentes do passo seguinte. Para a tela anterior, a programao do boto OK ser:
// sumir com o painel que tem os componentes de seleo de cor Pcores.Visible := false; // sumir com o boto OK Bok.Visible := false; // aviso do prximo passo Laviso.Caption := 'Agora, clique no formulrio, ser o Ponto 1:'; // faz uma tela branca, com um contorno preto. canvas.Pen.Color := clBlack; canvas.Brush.Color := clwhite; canvas.Pen.Width := 1; canvas.Rectangle(16, 96, 848, 504); // atualiza as cores da caneta, fundo e respectiva grossura CBBpen.OnChange(nil); CBBbrush.OnChange(nil); CBBwidth.OnChange(nil); // FLAG QUE INDICA EM QUE PASSO DO PROGRAMA EST FLAG := 1;

Para que a tecla ESC possa reiniciar a aplicao ou, se estiver na tela inicial, fechar a aplicao, colocaremos no evento ONKEYDOWN do formulrio a programao a seguir (no esquea de deixar o KEYPREVIEW do formulrio como TRUE:
if KEY = 27 then if FLAG = 0 then CLOSE else P_inicia;

O P_inicia um procedimento criado como mtodo do formulrio principal, que reinicia as variveis e componentes para reiniciar a aplicao. Na diretiva PUBLIC do formulrio, coloque:
procedure P_inicia;

Pag. 45/176

E na IMPLEMENTATION da aplicao coloque:


procedure Tform_principal.P_inicia; begin Laviso.caption := 'Escolha a cor e o preenchimento -------------------------->'; Pcores.Visible := true; Bok.Visible := true; Lp1.Visible := false; Lp2.Visible := false; Lp3.Visible := false; Breta.Visible := false; Bcirculo.Visible := false; Btriangulo.Visible := false; FLAG := 0; end;

No esquea de no evento ONCREATE do formulrio voc precisa iniciar a varivel FLAG:


FLAG := 0;

Para que a escolha das cores tenha efeito, necessrio, no evento ONCHANGE de cada COMBOBOX, o sistema atribua a cor ou espessura escolhida. Veja a programao de cada um dos COMBOBOX:
procedure Tform_principal.CBBpenChange(Sender: TObject); begin case CBBpen.ItemIndex of 0: Canvas.Pen.Color := clred; 1: Canvas.Pen.Color := clyellow; 2: Canvas.Pen.Color := clblue; 3: Canvas.Pen.Color := clBlack; end; end; procedure Tform_principal.CBBbrushChange(Sender: TObject); begin case CBBbrush.ItemIndex of 0: Canvas.brush.Color := clred; 1: Canvas.brush.Color := clyellow; 2: Canvas.brush.Color := clblue; 3: Canvas.brush.Color := clBlack; end; end; procedure Tform_principal.CBBWidthChange(Sender: TObject); begin canvas.Pen.Width := CBBwidth.ItemIndex; end;

Aps escolhida as cores, o operador dever clicar no boto OK, e a aplicao apresentar: Pag. 46/176

Para que o Clique do mouse determine o boto escolhido, colocaremos no evento ONMOUSEDOWN a programao:
// FLAG=0 AINDA EST ECOLHENDO AS CORES E GROSSURA DA CANETA, NO PODE ACEITAR O CLIQUE if FLAG > 0 then begin // faz um ponto na tela para o operador vber onde clicou CANVAS.Ellipse(X, Y, X + 2, Y + 2); case FLAG of 1: // boto OK foi precionado, est no passo de escolher o primeiro ponto begin // atribui a posio do mouse ao primeiro ponto VG_X1 := X; VG_Y1 := Y; FLAG := 2; Laviso.Caption := 'Clique novamente, ser o Ponto 2:'; Lp1.Visible := true; Lp1.Caption := 'Ponto 1: X=' + inttostr(X) + ' Y=' + inttostr(Y); end; 2: // primeiro poto j escolhido, passa para o segundo begin // atribui a posio do mouse ao segundo ponto VG_X2 := X; VG_Y2 := Y; FLAG := 3; Laviso.Caption := 'Clique novamente ou escolha um desenho...'; // como escolheu dois ponto, d pra fazer rela ou circulo Breta.Visible := true; Bcirculo.Visible := true; Lp2.Visible := true; Lp2.Caption := 'Ponto 2: X=' + inttostr(X) + ' Y=' + inttostr(Y); end; 3: // ecolhido o terceiro ponto begin // atribui a posio do mouse ao terceiro ponto VG_X3 := X; VG_Y3 := Y; FLAG := 4; Laviso.Caption := 'Agora escolha fazer um triangulo, ou ESC recomea'; // como escolheu trs ponto, d pra fazer triangulo Breta.Visible := false; Bcirculo.Visible := false; Btriangulo.Visible := true; Lp3.Visible := true; Lp3.Caption := 'Ponto 3: X=' + inttostr(X) + ' Y=' + inttostr(Y); end; end; end;

Pag. 47/176

Aps clicar o primeiro ponto, a aplicao mostrar o ponto (a indicao em vermelho apenas ilustrativa) e suas coordenadas:

Aps o segundo clique, mostrar o segundo ponto e disponibilizar os botes de reta e circulo:

Pag. 48/176

Clicando em um terceiro ponto, o sistema sumir com os botes de reta e circulo, e aparecer com o boto triangulo:

Pronto. A Aplicao est terminada. Fica como sugesto, criar um grfico de barras, que indique a frequencia das notas dos alunos de uma turma, e a nota mdia.

Pag. 49/176

2.8- Vetores e Matrizes Um vetor nada mais que uma relao de variveis indexadas. Pode ser entendido tambm como uma matriz de uma linha s. No delphi possivel criar um vetor de comprimento fixo, atravs do comando a seguir, onde <tipo> o tipo de varivel, podendo ser string, real, integer, etc: var vetor: array[1.. n] of <tipo>; Para criar um vetor de comprimento variavel, defina-o com o comando a seguir: var vetorvariavel: array of <Real>; E depois, dentro da programao, defina o tamanho, em tempo de execuo, com o comando a seguir: SetLength(vetorvariavel, 20); Isto muito til, quando no sabemos o tamanho que o vetor ter, por exemplo no caso de uma lista de alunos, onde o numero de alunos pode variar de caso para caso. Se criarmos um array dentro de cada elemento de um vetor, ou seja, de uma matriz-linha, teremos um vetor de vetores, ou uma matriz bi-dimencional. O comando para a sua criao seria: var matriz: array[1.. n] of array of [1.. m] <tipo>; O comando acima pode ser escrito da forma a seguir: var matriz: array[1.. n, 1.. m] <tipo>; Tecnicamente o resultado o mesmo e a forma de utilizar o elemento tambm, mas conceitualmente, o segunto caso trata-se efetivamente de uma matriz. Para definies de matrizes mais complexas, pode-se criar um tipo (ou uma classe simples) atravs do comqando: type TMatrix = array[1..10,1..50] of Real; Por se tratar de uma definio de Tipo, deve estar localizado na parte superior de seu oprograma funte, juntamente com os outros TYPE. Com o tipo criado, basta, na diretiva VAR, criar a instncia para utilizar a matriz: var Matrix:TMatrix; Exemplo: vamos criar uma plaicao onde introduziremos um numero N de nomes e em seguida estes nomes sero mostrados sequencialmente.

Pag. 50/176

Veja a tela:

Inicialmente deixe visivel somente os dois primeiros componentes (Numero de alunos e o Edit a sua fretente). Em vermelho esto indicados os nomes dados a cada componente. Coloque, na diretiva PRIVATE da UNIT, o comando a seguir que criar o vetor: vetorvariavel: array of string; No evento ONKEYDOWN do primeiro edit, coloque a programao a seguir, que servir para, ao ser ditada a tecla ENTER, definir o comprimento do array.: if key = vk_return then if strtoint('0' + E1.Text) > 0 then begin SetLength(vetorvariavel, strtoint('0' + E1.Text)); L1.Visible := false; E1.Visible := false; L3.Caption := '1'; L2.Visible := true; L3.Visible := true; E2.Visible := true; E2.SetFocus; end else showmessage('ERRO!' + #10 + 'defina o numero de alunos.'); Agora, no evento ONKEYDOWN do segundo edit, coloque a programao: Pag. 51/176

if key = vk_return then if length(E2.Text) > 0 then begin vetorvariavel[strtoint(L3.Caption)-1] := E2.Text; E2.Text:=''; if strtoint(L3.Caption) = strtoint(E1.Text) then begin for i := 1 to strtoint(E1.Text) do showmessage('Aluno ' + inttostr(i) + ':' + #10 + vetorvariavel[i-1]); showmessage('Terminou.'); L1.Visible := true; E1.Visible := true; E1.Text := ''; L2.Visible := false; L3.Visible := false; E2.Visible := false; E1.SetFocus; end else L3.Caption := inttostr(strtoint(L3.Caption) + 1); end else showmessage('ERRO!' + #10 + 'digite um nome para o aluno.'); No esquea que antes do BEGIN do procedimento, necessrio criar a variavel i: var i: integer; Pronto, o programa est concluido. Uma coisa importante entender que, sem utilizar um WHILE ou um FOR explicito, voc criou um LOOP! Para a introduo de um vetor, utilizando um WHILE ou um FOR explicito, teriamos que usar um artificio de programao que TRAVASSE a aplicao, sempre que o operador fosse introduzir um dado. Vamos a seguir descrever esta aplicao. Vamos montar a mesma tela que apresentado anteriormente:

Pag. 52/176

No evento ONKEYDOWN do primeiro edit, colocamos (em vermelho est o nosso LOOP explicito): if key = vk_return then if strtoint('0' + E1.Text) > 0 then begin SetLength(vetorvariavel, strtoint(E1.Text)); L1.Visible := false; E1.Visible := false; L3.Caption := '1'; L2.Visible := true; L3.Visible := true; E2.Visible := true; for i := 1 to strtoint(E1.Text) do begin E2.Visible := true; E2.SetFocus; while E2.Visible do Application.ProcessMessages; vetorvariavel[i - 1] := E2.Text; L3.Caption := inttostr(i); end; L2.Visible := false; L3.Visible := false; E2.Visible := false; for i := 1 to strtoint(E1.Text) do showmessage('Aluno ' + inttostr(i) + ':' + #10 + vetorvariavel[i - 1]); showmessage('Terminou.'); L1.Visible := true; E1.Visible := true; E1.Text := ''; E1.SetFocus; end; end else showmessage('ERRO!' + #10 + 'defina o numero de alunos.'); Falta agora colocar no evento ONKEYDOWN do segundo edit, a programao: if key = vk_return then if length(E2.Text) > 0 then E2.Visible := false else showmessage('ERRO!' + #10 + 'digite um nome para o aluno.'); Pronto, terminamos. Note que sempre que digitamos ENTER no segundo EDIT, fazemos com que ele fique invisivel, destravando o LOOP while E2.Visible do Application.ProcessMessages; e fazendo com que o programa pea o proximo valor.

Pag. 53/176

2.9- RECORD O RECORD um tipo mais elaborado: como uma classe, mas tem somente as propriedades, no possui nem mtodos, nem evento. Veja o exemplo a seguir: type Titem = record codigo: string; descricao: string; peso: real; unidade: string; preco: real; quantidade: real; end; Agora crio a instncia: var item:Titem; Dentro da programao, meu RECORD pode ser usado assim: item.codigo:='001'; item.descricao:='CAMISA'; item.peso:=0.3; item.unidade:='UNI'; item.preco:=3.5; item.quantidade:=10; O RECORD pode ser utilizado como um registro de uma tabela. Veja o codigo a seguir: type Titem = record codigo: string; descricao: string; peso: real; unidade: string; preco: real; quantidade: real; situacao: (disponivel,emfalta,inativo); end; var itens : array[1.. 10] of Titem;

Podemos usar, durante a programao, nossos itens assim: Pag. 54/176

item[0].codigo:='001'; item[0].descricao:='CAMISA'; item[0].peso:=0.3; item[0].unidade:='UNI'; item[0].preco:=3.5; item[0].quantidade:=10; item[0].situacao :=disponivel; item[1].codigo:='002'; item[1].descricao:='CALA'; item[1].peso:=0.7; item[1].unidade:='UNI'; item[1].preco:=9.5; item[1].quantidade:=10; item[1].situacao :=disponivel;

Podemos ainda usar array dinmico:


var itens : array of Titem;

E dentro da aplicao, definimos o tamanho:


Setlength(itens,100);

Desta forma podemos imaginar que cada item da minha matriz um registro de uma tabela. Vamos agora fazer uma aplicao simples, considerando que desejamos montar uma lista de itens, conforme descrito anteriormente. Crie inicialmente a tela principal, com o formulrio de nome form_principal, como indicado a seguir:

Pag. 55/176

No evento onclick de cada boto indicado acima, nomeados respectivamente como Binclui, Baltera, Bexclui, Bconsulta; destinados respectivamente a incluir, alterar, excluir e consultar itens; coloque a programao de chamada de um segundo formulrio chamado form_dados (este ser o nome do formulrio que conter os campos disponiveis para a inclusa de cada item), conforme descrito a seguir: procedure Tform_principal.BincluiClick(Sender: TObject); begin form_dados.Caption := 'Incluso'; form_dados.Eordem.Text := inttostr(-1); form_dados.showmodal; end; procedure Tform_principal.BalteraClick(Sender: TObject); begin if LBcod_item.ItemIndex < 0 then showmessage('Selecione o item.') else begin form_dados.Caption := 'Alterao'; form_dados.Eordem.Text := inttostr(LBcod_item.ItemIndex); form_dados.showmodal; end; end; procedure Tform_principal.BexcluiClick(Sender: TObject); begin if LBcod_item.ItemIndex < 0 then showmessage('Selecione o item.') else begin form_dados.Caption := 'Excluso'; form_dados.Eordem.Text := inttostr(LBcod_item.ItemIndex); form_dados.showmodal; end; end; procedure Tform_principal.BconsultaClick(Sender: TObject); begin if LBcod_item.ItemIndex < 0 then showmessage('Selecione o item.') else begin form_dados.Caption := 'Consulta'; form_dados.Eordem.Text := inttostr(LBcod_item.ItemIndex); form_dados.showmodal; end; end; Pag. 56/176

Ainda no formulrio principal, criamos dois mtodos para gravar ou carregar, de arquivos textos, os array. Criaremos um arquivo texto para cada campo do array, isto porque o componente LISTBOX que vamos utilizar, possui um mtodo para carregar itens de um arquivo texto, e um mtodo para gravar seus itens em um arquivo texto. Para isto criaremos funes que usaro o Lbgeral, que ficar VISIBLE:=FASE na aplicao: public { Public declarations } procedure P_grava_array(arquivo: string; campo: integer); procedure P_carrega_array(arquivo: string; campo: integer); end; E sua programao, definida no final da UNIT (coloque antes do END.); procedure Tform_principal.P_grava_array(arquivo: string; campo: integer); var i: integer; dado: string; begin LBgeral.Items.Clear; for i := 0 to LBcod_item.Items.Count - 1 do begin case campo of 1: dado := item[i].codigo; 2: dado := item[i].descricao; 3: dado := floattostr(item[i].peso); 4: dado := item[i].unidade; 5: dado := floattostr(item[i].preco); 6: dado := floattostr(item[i].quantidade); 7: dado := inttostr(ord(item[i].situacao)); end; LBgeral.Items.Add(dado); end; LBgeral.Items.SaveToFile(arquivo); end; procedure Tform_principal.P_carrega_array(arquivo: string; campo: integer); var i: integer; dado: string; continua: boolean; begin continua := true; LBgeral.Items.Clear; try LBgeral.Items.LoadFromFile(arquivo); except Pag. 57/176

if campo = 1 then showmessage('Sem dados'); continua := false; end; if continua then for i := 0 to LBgeral.Items.Count - 1 do begin dado := LBgeral.Items[i]; case campo of 1: begin LBcod_item.Items.Add(dado); item[i].codigo := dado; end; 2: begin LBdes_item.Items.Add(dado); item[i].descricao := dado; end; 3: item[i].peso := strtofloat(dado); 4: item[i].unidade := dado; 5: item[i].preco := strtofloat(dado); 6: item[i].quantidade := strtofloat(dado); 7: case strtoint(dado) of 0: item[i].situacao := disponivel; 1: item[i].situacao := emfalta; 2: item[i].situacao := inativo; end; end; end; end; Note que os LISTBOX LBcod_item e LBdes_item servem apenas para o operador visualizr os dados, pois os dados ficam mesmo no array. Colocaremos ainda o botao GRAVA, para gravar os dados, sendo que no seu evento onclick teremos: procedure Tform_principal.BgravaClick(Sender: TObject); begin P_grava_array('codigo.txt', 1); P_grava_array('descricao.txt', 2); P_grava_array('peso.txt', 3); P_grava_array('unidade.txt', 4); P_grava_array('preco.txt', 5); P_grava_array('quantidade.txt', 6); P_grava_array('situacao.txt', 7); end; Pag. 58/176

Colocaremos o boto SAIDA para sair da aplicao, sendo que no seu evento onclick teremos o comando close, que fecha o formulrio principal e portando finaliza a aplicao. E por ultimo, no evendo onshow do formulrio principal, colocaremos a leitura dos arquivos, conforme a seguir: procedure Tform_principal.FormShow(Sender: TObject); begin P_carrega_array('codigo.txt', 1); P_carrega_array('descricao.txt', 2); P_carrega_array('peso.txt', 3); P_carrega_array('unidade.txt', 4); P_carrega_array('preco.txt', 5); P_carrega_array('quantidade.txt', 6); P_carrega_array('situacao.txt', 7); end; Inclua agora o formulrio form_dados clicando o boto indicado na figura a seguir:

Para o formulrio criado, mude a sua propriedade NAME para form_dados.Em seguida, monte a tela como mostrado a seguir, respeitando os nomes indicados:

Pag. 59/176

Note que so todos Tedit, somente o Rgsituacao ser um TradioGroup. Para aparecer as opes, no Objetc inspector do RadioGroup, clique no boto indcado e inclua as opes:

No evento onshow do formulrio, colocaremos a programao que ir colocar os dados nos edits, de acordo com a opo chamada a partir do formulrio principal. Veja a programao dentro do enveto onshow: procedure Tform_dados.FormShow(Sender: TObject); var i, j: integer; begin Bconfirma.Visible := true; if form_dados.Caption = 'Incluso' then begin Ecodigo.Text := ''; Edescricao.Text := ''; Epeso.Text := ''; Eunidade.Text := ''; Epreco.Text := ''; Equantidade.Text := ''; end; // if (form_dados.Caption = 'Alterao') or (form_dados.Caption = 'Excluso') or (form_dados.Caption = 'Consulta') then begin i := strtoint(Eordem.Text); Ecodigo.Text := item[i].codigo; Edescricao.Text := item[i].descricao; Epeso.Text := floattostr(item[i].peso); Pag. 60/176

Eunidade.Text := item[i].unidade; Epreco.Text := floattostr(item[i].preco); Equantidade.Text := floattostr(item[i].quantidade); RGsituacao.ItemIndex := ord(item[i].situacao); end; // if form_dados.Caption = 'Consulta' then begin Ecodigo.Enabled:=false; Edescricao.Enabled:=false; Epeso.Enabled:=false; Eunidade.Enabled:=false; Epreco.Enabled:=false; Equantidade.Enabled:=false; RGsituacao.Enabled:=false; Bconfirma.Visible := false; end; end; Agora, no evento onclick do boto confirma, voc dever colocar a programao que ir executar o processo escolhido: procedure Tform_dados.BconfirmaClick(Sender: TObject); var i, j: integer; begin if form_dados.Caption = 'Incluso' then begin form_principal.LBcod_item.Items.Add(Ecodigo.Text); form_principal.LBdes_item.Items.Add(Edescricao.Text); i := form_principal.LBcod_item.Items.Count - 1; // item item[i].codigo := Ecodigo.Text; item[i].descricao := Edescricao.Text; item[i].peso := strtofloat(Epeso.Text); item[i].unidade := Eunidade.Text; item[i].preco := strtofloat(Epreco.Text); item[i].quantidade := strtofloat(Equantidade.Text); case RGsituacao.ItemIndex of 0: item[i].situacao := disponivel; 1: item[i].situacao := emfalta; 2: item[i].situacao := inativo; end; end; // if form_dados.Caption = 'Alterao' then begin Pag. 61/176

i := strtoint(Eordem.Text); form_principal.LBcod_item.Items[i] := Ecodigo.Text; form_principal.LBdes_item.Items[i] := Edescricao.Text; // item item[i].codigo := Ecodigo.Text; item[i].descricao := Edescricao.Text; item[i].peso := strtofloat(Epeso.Text); item[i].unidade := Eunidade.Text; item[i].preco := strtofloat(Epreco.Text); item[i].quantidade := strtofloat(Equantidade.Text); case RGsituacao.ItemIndex of 0: item[i].situacao := disponivel; 1: item[i].situacao := emfalta; 2: item[i].situacao := inativo; end; end; // if form_dados.Caption = 'Excluso' then begin i := strtoint(Eordem.Text); form_principal.LBcod_item.Items.Delete(i); form_principal.LBdes_item.Items.Delete(i); for j := i to form_principal.LBcod_item.Items.Count - 1 do begin item[j].codigo := item[j + 1].codigo; item[j].descricao := item[j + 1].descricao; item[j].peso := item[j + 1].peso; item[j].unidade := item[j + 1].unidade; item[j].preco := item[j + 1].preco; item[j].quantidade := item[j + 1].quantidade; item[j].situacao := item[j + 1].situacao; end; end; // close; end; Pronto, a aplicao est pronta para ser utilizada.

Pag. 62/176

Veja outra aplicao interessante, criaremos um RECORD destinado a conter o resultado de uma tela de seleo padro, que receber vrios parmetros. Inicialmente criamos o RECORD: Primeiro definimos o RECORD: type Tselecao = record // usada para conter todas as selees referente ao formulrio F_seleciona selecionado_c: string; // retorno do list box, conteudo string da linha selecionada selecionado_i: integer; // retorno do list box, itemindex do selecionado periodo_v1: string; // conteudo do primeiro edit periodo_v2: string; // conteudo do segundo edit CB_1_checked: boolean; // retorno do check box 1 CB_2_checked: boolean; // retorno do check box 2 CB_3_checked: boolean; // retorno do check box 3 CB_4_checked: boolean; // retorno do check box 4 CB_5_checked: boolean; // retorno do check box 5 CB_6_checked: boolean; // retorno do check box 6 CB_7_checked: boolean; // retorno do check box 7 CB_8_checked: boolean; // retorno do check box 8 CB_9_checked: boolean; // retorno do check box 9 CB_10_checked: boolean; // retorno do check box 10 CB_11_checked: boolean; // retorno do check box 11 CB_12_checked: boolean; // retorno do check box 12 CB_13_checked: boolean; // retorno do check box 13 CB_14_checked: boolean; // retorno do check box 14 CB_15_checked: boolean; // retorno do check box 15 CB_16_checked: boolean; // retorno do check box 16 nao_cancelou: boolean; // retorna true, se clicou n o boto seleciona CBB1_selecionado_c: string; // retorno do combo box 1, conteudo string da linha selecionada CBB1_selecionado_i: integer; // retorno do combo box 1, itemindex do selecionado CBB2_selecionado_c: string; // retorno do combo box 2, conteudo string da linha selecionada CBB2_selecionado_i: integer; // retorno do combo box 2, itemindex do selecionado end;

Pag. 63/176

Depois criamos o formulrio padro:

Agora, criamos uma classe, para contem funes e procedimentos de uso geral, e j definimos a funo que manipular o formulrio acima, retornando o resultado em um RECORD tipo Tselecao: Tgeral = class // processos gerais public // retorna a opo selecionada da lista de opes separadas por separador se retornar string nulo, cancelou. function F_seleciona(tipo_Data_Mes_mesAno_Valor_Tabela_Lista_Periodo: string; parametros: AnsiString; mostra_selecao: boolean = true; opcao_todos_com_pipe: string = ''; titulo_com_pipe: string = ''; numero_do_retorno: integer = 0; conexao: TSQLConnection = nil; check_box_com_pipe: string = ''; check_box_checked_com_pipe: string = ''; check_box_enabled_com_pipe: string = ''; label_combo_box1: string = ''; label_combo_box2: string = ''; lista_com_pipe_combo_box1: string = ''; lista_com_pipe_combo_box2: string = ''; separador: string = '|'; formulario: Tform = nil; sem_cancela: boolean = false): Tselecao; end;

Pag. 64/176

E agora, toda a funo:


function Tgeral.F_seleciona( tipo_Data_Mes_mesAno_Valor_Tabela_Lista_Periodo: string; // sendo: // D data, M ms, A mes/ano, V valor, T - tabela do banco de dados, L - lista fornecida, P - periodo parametros: AnsiString; // parametros de manipulao, de acordo com o tipo acima // D - data: // - informe a data , e ser gerada a lista de datas do mes, posicionando no dia da data. // M - ms: // - informe a data, gera lista com doze meses (do ano) para posicionar no mes atual // A - mes/ano: // - informe o intervalo de anos e a data (para posicionar no mes atual . // - Ex: 1<separador>13/02/2005<separador> -> (ano atual-1) at (ano atual+1), posiciona em 02/2005 // V - valor // no caso de Valor, informar incial <separador> final <separador> digitos <separador> sufixo <separador>, // ser gerada uma lista de valores inteiros // T - tabela do banco de dados: // informar: // tabela<separador> // campo ou campos separados por virgula (sem virgula no final) <separador> // condio<separador> condio em branco se for todos, ??? para fornecer o comando integralmente pelo complemento // complemento<separador> // formatos, separados por ; <separador> se no fornecer, sem formato // tipos dos formatos, separados por ; <separador> se no fornecer, sem formato // L - lista fornecida: // no caso de lista, lista separada por separador // P - periodo: // no caso de periodo, informe a primeira data<separador> segunda data<separador>Label1<separador>Label2<separador> // Ex.: 01/01/2005|31/01/2005| ( assim para poder usar juntamente com outros parametros, colocar sempre no final // se Label1 ou Label2 = 'No usado' FAZ INVISIVEL, SE OUTRO, USA, SE NADA ou com a palavra Data, ENTENDE COMO DATA // se for fornecida: atual|, pega como periodo o mes atual // se for fornecida: ultima|, pega ultima data do mes anterior ao atual // hoje|, poe a data de hoje, nos dois campos // no_ano|, poe a primeira e a ultima data do ano atual // este o unico que pode ser usado juntamente com outro (coloque em segundo) mostra_selecao: boolean = true; // mostra a seleo opcao_todos_com_pipe: string = ''; // se length>0, inclui as palavras separadas por pipe no inicio da lista, default sem opo todos titulo_com_pipe: string = ''; // se o titulo for diferente do default, se tiver PIPE, separa em dois numero_do_retorno: integer = 0; // use: // 0 para retornar a linha inteira, // OU o numero de ordem do campo (separado por separador), // OU -1 par retornar o ItemIndex do lista seleciona conexao: TSQLConnection = nil; // conexao, se for tabela precisa fornecer, se for nil, iginora a conexo (serve para, numa

Pag. 65/176

dada aplicao no precisar ter conexo check_box_com_pipe: string = ''; // coloque o que para aparecer nos check-box, nulo o check_box desaparece. check_box_checked_com_pipe: string = ''; check_box_enabled_com_pipe: string = ''; label_combo_box1: string = ''; label_combo_box2: string = ''; lista_com_pipe_combo_box1: string = ''; lista_com_pipe_combo_box2: string = ''; // coloque a situao default dos CHECKBOX, sendo S para checked:=true, qualquer outra coisa para checked:=false separador: string = '|'; // separador usado no caso de lista. Para data ou mes no tem utilidade formulario: Tform = nil; // formulrio que chamou, se houver, se for nil, autmaticamente pega o VG_formatual sem_cancela: boolean = false // se true, some com o cancela, para processos que no pode cancelar ): Tselecao; // retorna os parametros: // selecionado_c - conteudo string da seleo ( se numero_do_retorno=-1 retorna inttostr(item.index) da seleo ) // selecionado_i - item.index da seleo (-1 se a chamada foi somente para periodo) // periodo_v1 - conteudo do Einicio // periodo_v2 - conteudo do Efim // CB_1_checked - situao do CB1_seleciona // CB_2_checked - situao do CB2_seleciona // CB_3_checked - situao do CB3_seleciona // CB_4_checked - situao do CB4_seleciona // CB_5_checked - situao do CB5_seleciona // CB_6_checked - situao do CB6_seleciona // CB_7_checked - situao do CB7_seleciona // CB_8_checked - situao do CB8_seleciona // CB_9_checked - situao do CB9_seleciona // CB_10_checked - situao do CB10_seleciona // CB_11_checked - situao do CB11_seleciona // CB_12_checked - situao do CB12_seleciona // nao_cancelou - retorna false se clicou no boto cancela // CBB1_selecionado_c - retorno do CBB1 // CBB1_selecionado_i - retorno do CBB1 // CBB2_selecionado_c retorno do CBB2 // CBB2_selecionado_i retorno do CBB2 var incremento, registros, ano, mes, i: integer; data: TDateTime; local_SDS: TSimpleDataset; descricao: string; begin if length(separador) = 0 then separador := '|'; if (formulario = nil) then begin if length(VG_formatual) > 0 then USU.P_disableform(VG_formatual); end

Pag. 66/176

else formulario.Enabled := false; Application.CreateForm(Tform_seleciona, form_seleciona); result.selecionado_c := ''; result.selecionado_i := -1; result.periodo_v1 := ''; result.periodo_v2 := ''; result.CB_1_checked := false; result.CB_2_checked := false; result.CB_3_checked := false; result.CB_4_checked := false; result.CB_5_checked := false; result.CB_6_checked := false; result.CB_7_checked := false; result.CB_8_checked := false; result.CB_9_checked := false; result.CB_10_checked := false; result.CB_11_checked := false; result.CB_12_checked := false; result.CB_13_checked := false; result.CB_14_checked := false; result.CB_15_checked := false; result.CB_16_checked := false; result.nao_cancelou := false; result.CBB1_selecionado_c := ''; result.CBB1_selecionado_i := -1; result.CBB2_selecionado_c := ''; result.CBB2_selecionado_i := -1; with form_seleciona do begin if sem_cancela then begin BBcancela_seleciona.Visible := false; BBseleciona_seleciona.Left := (form_seleciona.Width div 2) - (BBseleciona_seleciona.Width div 2); end; LBaviso_seleciona.Caption := 'Selecione:'; LBcomplemento_seleciona.Caption := ''; for i := 1 to STM.F_contanumero(check_box_com_pipe) do begin case i of 1: V_check_box := CB1_seleciona; 2: V_check_box := CB2_seleciona; 3: V_check_box := CB3_seleciona; 4: V_check_box := CB4_seleciona; 5: V_check_box := CB5_seleciona; 6: V_check_box := CB6_seleciona; 7: V_check_box := CB7_seleciona; 8: V_check_box := CB8_seleciona; 9: V_check_box := CB9_seleciona; 10: V_check_box := CB10_seleciona; 11: V_check_box := CB11_seleciona; 12: V_check_box := CB12_seleciona; 13: V_check_box := CB13_seleciona; 14: V_check_box := CB14_seleciona; 15: V_check_box := CB15_seleciona; 16: V_check_box := CB16_seleciona;

Pag. 67/176

17: PRO.F_opcao(' Excesso de CHECK BOX na funo F_seleciona. ', 'Informe o suporte do sistema ' + fue.F_cliente_versao(3)); end; v_check_box.Checked := false; if STM.F_pegastring(check_box_checked_com_pipe, i, '|') = 'S' then v_check_box.Checked := true; V_check_box.Visible := false; if length(STM.F_pegastring(check_box_com_pipe, i, '|')) > 0 then begin V_check_box.Caption := STM.F_pegastring(check_box_com_pipe, i, '|'); V_check_box.Visible := true; end; // fiz ao contrrio, assim, s onde quero desabilitar precis passar os parametros V_check_box.Enabled := true; if STM.F_pegastring(check_box_enabled_com_pipe, i, '|') = 'N' then v_check_box.Enabled := false; end; LBlista_seleciona.Items.Clear; if length(opcao_todos_com_pipe) > 0 then for i := 1 to STM.F_contanumero(opcao_todos_com_pipe, '|') do LBlista_seleciona.Items.add(STM.F_pegastring(opcao_todos_com_pipe, i, '|')); case AnsiPos(copy(tipo_Data_Mes_mesAno_Valor_Tabela_Lista_Periodo, 1, 1), 'DMAVTL') of 1: begin data := strtodate('01/' + inttostr(MonthOf(strtodate(parametros))) + '/' + inttostr(YearOf(strtodate(parametros)))); while MonthOf(data) = MonthOf(strtodate(parametros)) do begin LBlista_seleciona.Items.add(datetostr(data)); data := data + 1; end; if length(opcao_todos_com_pipe) = 0 then // se no tem as opoes todos, tem que fazer -1 LBlista_seleciona.ItemIndex := DayOf(strtodate(parametros)) - STM.F_contanumero(opcao_todos_com_pipe, '|') else LBlista_seleciona.ItemIndex := DayOf(strtodate(parametros)); LBaviso_seleciona.caption := 'Selecione a data desejada:'; end; 2: begin // para nao dar erro de data data := strtodate(DET.F_tratadata(parametros, false, true)); for i := 1 to 12 do LBlista_seleciona.Items.add(CVS.F_completa(inttostr(i), 2, '0', false)); LBlista_seleciona.ItemIndex := MonthOf(data) + STM.F_contanumero(opcao_todos_com_pipe, '|') - 1; LBaviso_seleciona.caption := 'Selecione o ms desejado:'; end; 3:

Pag. 68/176

begin data := strtodate(DET.F_tratadata(STM.F_pegastring(parametros, 2, separador), false, true)); i := CVS.F_cartoint(STM.F_pegastring(parametros, 1, separador)); for ano := -i to i do for mes := 1 to 12 do LBlista_seleciona.Items.add(CVS.F_completa(inttostr(mes), 2, '0', false) + '/' + inttostr(YearOf(data) + ano)); LBlista_seleciona.ItemIndex := MonthOf(data) + 12 * i - STM.F_contanumero(opcao_todos_com_pipe, '|') - 1; // LBaviso_seleciona.caption := 'Selecione o mes/ano desejado:'; end; 4: begin for i := CVS.F_cartoint(STM.F_pegastring(parametros, 1, separador)) to CVS.F_cartoint(STM.F_pegastring(parametros, 2, separador)) do LBlista_seleciona.Items.add(CVS.F_completa( inttostr(i), CVS.F_cartoint(STM.F_pegastring(parametros, 3, separador)), '0', false) + STM.F_pegastring(parametros, 4, separador)); LBaviso_seleciona.caption := 'Selecione o valor desejado:'; LBlista_seleciona.ItemIndex := 0; end; 5: begin local_SDS := TSimpleDataset.Create(nil); local_SDS.Connection := form_principal.Cautobyte; if STM.F_pegastring(parametros, 3, separador) = '???' then registros := SDS.F_pega_simples(local_SDS, '', '???', STM.F_pegastring(parametros, 4, separador)) else registros := SDS.F_pega_simples(local_SDS, STM.F_pegastring(parametros, 2, separador), STM.F_pegastring(parametros, 1, separador), // invertido mesmo... STM.F_pegastring(parametros, 3, separador), false, STM.F_pegastring(parametros, 4, separador)); if registros > 0 then begin local_SDS.first; while not local_SDS.eof do begin descricao := ''; if Ansipos(',', STM.F_pegastring(parametros, 2, separador)) > 0 then begin for i := 1 to STM.F_contanumero(STM.F_pegastring(parametros, 2, separador), ',') do begin if length(STM.F_pegastring(parametros, 5, separador)) > 0 then descricao := descricao + CVS.F_formata_arredonda(

Pag. 69/176

local_SDS.FieldByName( STM.F_pegastring( STM.F_pegastring( parametros, 2, separador ), i, ',')).AsString, STM.F_pegastring(STM.F_pegastring(parametros, 6, separador), i, ';'), STM.F_pegastring(STM.F_pegastring(parametros, 5, separador), i, ';')) + separador else descricao := descricao + local_SDS.FieldByName( STM.F_pegastring( STM.F_pegastring( parametros, 2, separador ), i, ',')).AsString + separador; end; descricao := copy(descricao, 1, length(descricao) - 1); end else descricao := local_SDS.FieldByName(STM.F_pegastring(parametros, 2, separador)).AsString; LBlista_seleciona.Items.add(descricao); local_SDS.Next; end; end; FreeAndNil(local_SDS); LBaviso_seleciona.caption := 'Selecione um Item da relao'; LBlista_seleciona.ItemIndex := 0; end; 6: begin for i := 1 to STM.F_contanumero(parametros, separador) do begin // se o separador for , vai dar problema com seleo de periodo if not (separador = '') then begin if Ansipos('', STM.F_pegastring(parametros, i, separador)) = 0 then // no o marcador de periodo LBlista_seleciona.Items.add(STM.F_pegastring(parametros, i, separador)); end else // se o separador for , considera os parmetro de periodo tambm como sendo da lista. LBlista_seleciona.Items.add(STM.F_pegastring(parametros, i, separador)); end; LBaviso_seleciona.caption := 'Selecione a opo desejada:'; LBlista_seleciona.ItemIndex := 0; end;

Pag. 70/176

else LBlista_seleciona.Visible := false; end; // sempre q tem digitao de valores, o P utilizado if AnsiPos('P', tipo_Data_Mes_mesAno_Valor_Tabela_Lista_Periodo) > 0 then begin LBlista_seleciona.Visible := false; // se s seleo de periodo LBaviso_seleciona.Caption := 'Selecione o periodo desejado:'; Linicio.Caption := 'Data inicial:'; Linicio.visible := true; Einicio.visible := true; Lfim.Caption := 'Data final:'; Lfim.visible := true; Efim.visible := true; Einicio.Text := ''; Efim.Text := ''; parametros := copy(parametros, Ansipos('', parametros) + 1, length(parametros)); if length(trim(parametros)) > 0 then begin // verifica se para mudar o caption da funo if length(STM.F_pegastring(parametros, 3, '|')) > 0 then if STM.F_pegastring(parametros, 3, '|') = 'No usado' then begin Linicio.Caption := 'Nada'; Linicio.Visible := false; Einicio.Visible := false; end else begin Linicio.Caption := STM.F_pegastring(parametros, 3, '|'); if length(Linicio.Caption) > 12 then Linicio.Left := 10; end; if length(STM.F_pegastring(parametros, 4, '|')) > 0 then if STM.F_pegastring(parametros, 4, '|') = 'No usado' then begin Lfim.Caption := 'Nada'; Lfim.Visible := false; Efim.Visible := false; end else begin Lfim.Caption := STM.F_pegastring(parametros, 4, '|'); if length(Lfim.Caption) > 12 then Lfim.Left := 10; end;

Pag. 71/176

//// pra funcionar o case. case STM.F_achanumero(STM.F_pegastring(parametros, 1, '|'), 'atual|hoje|no_ano|ultima|') of 1: begin Einicio.Text := '01/' + inttostr(MonthOf(date)) + '/' + inttostr(YearOf(date)); if MonthOf(date) = 12 then Efim.Text := datetostr(strtodate('01/01/' + inttostr(YearOf(date) + 1)) - 1) else EFim.Text := datetostr(strtodate('01/' + inttostr(MonthOf(date) + 1) + '/' + inttostr(YearOf(date))) - 1); end; 2: begin Einicio.Text := datetostr(date); Efim.Text := datetostr(date); end; 3: begin Einicio.Text := '01/01/' + inttostr(YearOf(date)); EFim.Text := '01/12/' + inttostr(YearOf(date)); end; 4: begin Einicio.Text := '01/' + inttostr(MonthOf(date)) + '/' + inttostr(YearOf(date)); if MonthOf(date) = 12 then Efim.Text := datetostr(strtodate('01/01/' + inttostr(YearOf(date) + 1)) - 1) else EFim.Text := datetostr(strtodate('01/' + inttostr(MonthOf(date) + 1) + '/' + inttostr(YearOf(date))) - 1); Einicio.Text := datetostr(strtodate(Einicio.Text) - 1); EFim.Text := datetostr(strtodate(EFim.Text) - 1); end; else begin Einicio.Text := STM.F_pegastring(parametros, 1, '|'); Efim.Text := STM.F_pegastring(parametros, 2, '|'); end; end; end; end else begin Linicio.Visible := false; Einicio.Visible := false; Lfim.Visible := false; Efim.Visible := false; end; // se tem mais de um caracter, porque tem periodo e algum tipo de lista if length(tipo_Data_Mes_mesAno_Valor_Tabela_Lista_Periodo) > 1 then

Pag. 72/176

begin LBlista_seleciona.Visible := true; LBlista_seleciona.Height := 137; Linicio.Top := 184; Einicio.Top := 176; Lfim.Top := 208; Efim.Top := 200; end; // CBB e CB if length(titulo_com_pipe) > 0 then begin if Ansipos('|', titulo_com_pipe) > 0 then begin LBaviso_seleciona.Caption := STM.F_pegastring(titulo_com_pipe, 1, '|'); LBcomplemento_seleciona.Caption := STM.F_pegastring(titulo_com_pipe, 2, '|'); end else LBaviso_seleciona.caption := titulo_com_pipe; end; if length(label_combo_box1) > 0 then // se tem combo box if not LBlista_seleciona.visible then //se no tem lista_seleciona if not Linicio.Visible then begin // sem periodo LCBB1_seleciona.Top := 36; CBB1_seleciona.Top := 50; LCBB2_seleciona.Top := 36; CBB2_seleciona.Top := 50; end else begin // com periodo Linicio.Top := Linicio.Top - 60; Lfim.Top := Lfim.Top - 60; Einicio.Top := Einicio.Top - 60; Efim.Top := Efim.Top - 60; LCBB1_seleciona.Top := LCBB1_seleciona.Top - 128; CBB1_seleciona.Top := CBB1_seleciona.Top - 128; LCBB2_seleciona.Top := LCBB2_seleciona.Top - 128; CBB2_seleciona.Top := CBB2_seleciona.Top - 128; end; if length(label_combo_box1) > 0 then begin LCBB1_seleciona.Caption := label_combo_box1; LCBB1_seleciona.Visible := true;

Pag. 73/176

end; if length(label_combo_box2) > 0 then begin LCBB2_seleciona.Caption := label_combo_box2; LCBB2_seleciona.Visible := true; end; if STM.F_contanumero(lista_com_pipe_combo_box1) > 0 then begin CBB1_seleciona.Visible := true; for i := 1 to STM.F_contanumero(lista_com_pipe_combo_box1) do CBB1_seleciona.Items.Add(STM.F_pegastring(lista_com_pipe_combo_box1, i)); CBB1_seleciona.ItemIndex := 0; end; if STM.F_contanumero(lista_com_pipe_combo_box2) > 0 then begin CBB2_seleciona.Visible := true; for i := 1 to STM.F_contanumero(lista_com_pipe_combo_box2) do CBB2_seleciona.Items.Add(STM.F_pegastring(lista_com_pipe_combo_box2, i)); CBB2_seleciona.ItemIndex := 0; end else CBB1_seleciona.Width := CBB1_seleciona.Width * 2; // // ACERTA O FOCO // // SE tem lista if length(tipo_Data_Mes_mesAno_Valor_Tabela_Lista_Periodo) > 1 then LBlista_seleciona.SetFocus else // se tem inicio if Einicio.Visible then Einicio.SetFocus else // se tem fim if Efim.Visible then Efim.SetFocus else // se tem Combobox1 if CBB1_seleciona.Visible then CBB1_seleciona.SetFocus else // se tem Combobox2 if CBB2_seleciona.Visible then CBB2_seleciona.SetFocus else // se tem Checkbox1 e est habilitado if CB1_seleciona.Visible and CB1_seleciona.Enabled then CB1_seleciona.SetFocus else if BBcancela_seleciona.Visible then BBcancela_seleciona.SetFocus else

Pag. 74/176

if BBseleciona_seleciona.Visible then BBseleciona_seleciona.SetFocus; // // ajuste de posio dos CHECK BOX // incremento := 0; if not LCBB1_seleciona.Visible then begin if Lfim.Visible then begin CB1_seleciona.Top := Lfim.Top + 26; CB2_seleciona.Top := Lfim.Top + 26; incremento := 4; end else begin if LBlista_seleciona.Visible then begin CB1_seleciona.Top := 228; CB2_seleciona.Top := 228; end else begin CB1_seleciona.Top := LBlista_seleciona.Top; CB2_seleciona.Top := LBlista_seleciona.Top; incremento := 14; end; end; end else begin CB1_seleciona.Top := CBB1_seleciona.Top + 26; CB2_seleciona.Top := CBB1_seleciona.Top + 26; end; CB3_seleciona.Top := CB1_seleciona.Top + 16 + incremento; CB4_seleciona.Top := CB2_seleciona.Top + 16 + incremento; CB5_seleciona.Top := CB3_seleciona.Top + 16 + incremento; CB6_seleciona.Top := CB4_seleciona.Top + 16 + incremento; CB7_seleciona.Top := CB5_seleciona.Top + 16 + incremento; CB8_seleciona.Top := CB6_seleciona.Top + 16 + incremento; CB9_seleciona.Top := CB7_seleciona.Top + 16 + incremento; CB10_seleciona.Top := CB8_seleciona.Top + 16 + incremento; CB11_seleciona.Top := CB9_seleciona.Top + 16 + incremento; CB12_seleciona.Top := CB10_seleciona.Top + 16 + incremento; CB13_seleciona.Top := CB11_seleciona.Top + 16 + incremento; CB14_seleciona.Top := CB12_seleciona.Top + 16 + incremento; CB15_seleciona.Top := CB13_seleciona.Top + 16 + incremento;

Pag. 75/176

CB16_seleciona.Top := CB14_seleciona.Top + 16 + incremento; // Linicio.Left := 248 - (length(Linicio.Caption) * 7); Linicio.Left := Linicio.Left div 2; if Linicio.Left < 2 then Linicio.Left := 2; Lfim.Left := 248 - (length(Lfim.Caption) * 7); Lfim.Left := Lfim.Left div 2; if Lfim.Left < 2 then Lfim.Left := 2; Einicio.Left := Linicio.Left + (length(Linicio.Caption) * 7) + 2; Efim.Left := Lfim.Left + (length(Lfim.Caption) * 7) + 2; // MOSTRA O FORMULARIO // showmodal; // // result.nao_cancelou := ok; if ok then begin // ficou: if LBlista_seleciona.visible then begin result.selecionado_i := LBlista_seleciona.ItemIndex; if numero_do_retorno = -1 then result.selecionado_c := inttostr(LBlista_seleciona.ItemIndex) else result.selecionado_c := LBlista_seleciona.Items[LBlista_seleciona.ItemIndex]; end; if numero_do_retorno > 0 then result.selecionado_c := STM.F_pegastring(result.selecionado_c, numero_do_retorno, separador); if mostra_selecao then if LBlista_seleciona.Visible then PRO.F_opcao(' Opo selecionada:' + result.selecionado_c + ' '); if Linicio.Visible then begin result.periodo_v1 := Einicio.Text; result.periodo_v2 := Efim.Text; if mostra_selecao then PRO.F_opcao('Periodo selecionado:', Linicio.Caption + result.periodo_v1, Lfim.Caption + result.periodo_v2); end; // retora os check box checked result.CB_1_checked := CB1_seleciona.Checked; result.CB_2_checked := CB2_seleciona.Checked; result.CB_3_checked := CB3_seleciona.Checked; result.CB_4_checked := CB4_seleciona.Checked; result.CB_5_checked := CB5_seleciona.Checked;

Pag. 76/176

result.CB_6_checked := CB6_seleciona.Checked; result.CB_7_checked := CB7_seleciona.Checked; result.CB_8_checked := CB8_seleciona.Checked; result.CB_9_checked := CB9_seleciona.Checked; result.CB_10_checked := CB10_seleciona.Checked; result.CB_11_checked := CB11_seleciona.Checked; result.CB_12_checked := CB12_seleciona.Checked; result.CB_13_checked := CB13_seleciona.Checked; result.CB_14_checked := CB14_seleciona.Checked; result.CB_15_checked := CB15_seleciona.Checked; result.CB_16_checked := CB16_seleciona.Checked; if LCBB1_seleciona.Visible then begin result.CBB1_selecionado_c := CBB1_seleciona.Text; result.CBB1_selecionado_i := CBB1_seleciona.ItemIndex; end; if LCBB2_seleciona.Visible then begin result.CBB2_selecionado_c := CBB2_seleciona.Text; result.CBB2_selecionado_i := CBB2_seleciona.ItemIndex; end; end; Destroy; end; if (formulario = nil) then begin if length(VG_formatual) > 0 then USU.P_reshowform(VG_formatual); end else begin formulario.Enabled := true; formulario.show; end; end;

Pag. 77/176

2.10- Manipulando arquivos tipo INI Vamos agora iniciar a manipulao de arquivos do tipo INI.Para isso vamos criar um novo formulrio :

No evento ON ACTIVATE do formulrio, vamos zerar as variveis : Edit1.text:=''; Edit2.text:=''; Edit3.text:=''; Edit4.text:=''; Note que com estes comandos, sempre que o formulrio de incluso for acessado, todos os campos de edio sero apagados. Isto pode ser mudado se estes comandos forem colocados no evento ONCREATE, ou seja, somente na criao do formulrio ( primeiro acesso ) que os campos edit sero apagados. Isto ser muito usado quando voc quiser que um formulrio seja acessado somente quando o sistema iniciado, e no sempre que o formulrio for acessado ( digitar os dados do usurio, por exemplo ). Vamos incluir tambm, no mdulo principal, o boto para acessar a configurao :

Pag. 78/176

Vamos agora incluir os comandos para, quando clicarmos o boto LE, o arquivo TESTE.INI ser lido e suas informaes colocadas nos campos de edio. quando clicarmos o boto GRAVA, no arquivo TESTE.INI sero gravadas as informaes existentes nos campos de edio. Para o boto LE, vamos incluir os comandos : ini:=Tinifile.create('teste.ini'); // cria o arquivo se no existir, ou abre se existir Edit1.text:=ini.readstring('ENDERECOS',END1,' '); // l o arquivo aberto e lanado na varivel ini, a partir do grupo ENDERECOS, l o campo END1, se no existir, retorna ( terceiro parmetro ). O resultado joga no Edit1.text ( campo texto do Edit1 ). ini.free; // fecha o arquivo. No esquea de incluir na declarao USES o comando INIFILES, que inclui na compilao e linkagem a biblioteca dos comandos referente a manipulao dos arquivos tipo INI. Na declarao VAR inclua ini : TInifile Para o boto grava, inclua os comandos : ini:=Tinifile.create('teste.ini'); // abre o arquivo ini.writestring('ENDERECOS',END1,Edit1.text); // escreve no grupo ENDERECOS, campo END1, o conteudo do Edit1.text. ini.free; // fecha o arquivo Repita os comandos readstring e writestring para Edit2, Edit3, e Edit4. Use o Edit do DOS para verificar como ficou o arquivo. Voc poder facilmente identificar o formato do arquivo INI: [ENDERECOS] END1=<contedo digitado no edit1> END2=<contedo digitado no edit2> END3=<contedo digitado no edit3> END4=<contedo digitado no edit4> Pag. 79/176

2.11- Arquivos textos Monte a tela a seguir:

No boto l coloque a programao para leitura do arquivo: Memo1.Lines.LoadFromFile(Earquivo.text); No Boto grava, coloque o comando: Memo1.Lines.SaveToFile(Earquivo.text); Caso deseje trabalhar com a tela que abre o diretorio para a seleo do arquivo, use o componente OPENDIALOG da palheta DIALOGS:

Pag. 80/176

Agora, no evendo ONDOUBLECLICK do EDIT, coloque a programao que ativa a janela: OpenDialog1.InitialDir:='C:\'; if OpenDialog1.Execute then begin Earquivo.Text:=OpenDialog1.FileName; end; Pronto. Seu editor de arquivo texto est pronto. Para ler o arquivo linha a llinha escreva, no boto l, a funo: var TXT: TextFile; a: string; begin memo1.Clear; pb.Position := 0; AssignFile(TXT, Earquivo.Text); Reset(TXT); while not eof(TXT) do begin Readln(TXT, a); Memo1.Lines.Add(a); pb.Position := pb.Position + 1; if pb.Position = 100 then pb.Position := 0; pb.Update; pb.Repaint; end; CloseFile(TXT); end;

Pag. 81/176

2.12 Agenda de telefones: Para firmar o conceito de manipulao de arquivos tipo INI, associando a novos eventos em componentes, vamos desenvolver uma aplicao completa. Vamos criar uma agenda de telefones, arquivada em arquivo tipo INI, com o seguinte formato: [<telefone>] Nome=<nome> Endereo=<endereo> Cidade=<cidade> Estado=<sigla do estado> Aniversario=<data> Note que entre <> representamos a existncia de um dado. Cada sesso ser os dados de uma pessoa arquivada na agenda, representada pelo seu telefone. Para essa aplicao fremos uma tela inicial, que conter a lista de telefones e nomes, permitindo uma pesquisa, e esta tela acessar um segundo formulrio que permitir incluir, alterar, excluir ou consultar os dados. Veja a tela inicial:

A linha de PESQUISA so EDIT, nomeados Efones e Enomes, respectivamente. Os botes INCLUI, ALTERA, EXCLUI e CONSULTA acessam a tela de dados que ser descrita a seguir. A coluna de TELEFONES e NOMES so LISTBOX, nomeados LBfones e LBnomes, respectivamente. Aqui iro aparecer todos os telefones e nomes existentes no arquivo tipo ini, que receber o nome de agenda.ini, sendo que sua trilha de buca completa e nome est em ARQUIVO. O boto L permite trocar o nome do arquivo, e l-lo novamente. Para que o arquivo tambm seja carregado na entrada da aplicao, j no evento ONSHOW do formulrio Pag. 82/176

chamaremos a funo le_ini, que far a leitura do arquivo, colocando os dados dentro dos LISTBOX. A seguir apresentamos a funo: procedure Tform_principal.F_le_ini(arquivo: string); var ini: Tinifile; i: integer; begin LBfones.Clear; Lbnomes.Clear; ini := Tinifile.create(arquivo); // cria o arquivo se no existir, ou abre se existir ini.ReadSections(LBfones.Items); for i := 0 to LBfones.Items.Count - 1 do LBnomes.Items.Add(ini.ReadString(LBfones.Items[i], 'Nome', '?')); end; A seguir apresentamos a sua chamada a partir do evento ONSHOW. F_le_ini(Eagenda.text); O boto saida fecha a aplicao com o comando CLOSE; O boto inclui acessa o formulrio de dados. Para identificar que estaremos em modo de incluso, usaremos o CAPTION do formulrio para recever esta informao. Veja a programao de cada boto, dentro do formulrio principal: procedure Tform_principal.BBincluiClick(Sender: TObject); begin form_dados_ag.Caption := 'INCLUSO:'; form_dados_ag.ShowModal; F_le_ini(Eagenda.Text); end; procedure Tform_principal_ag.BBalteraClick(Sender: TObject); begin if form_principal_ag.itemindex = -1 then showmessage('selecione um telefone...') else begin form_dados_ag.Caption := 'ALTERAO:'; form_dados_ag.ShowModal; F_le_ini(Eagenda.Text); end; end; procedure Tform_principal_ag.BBexcluiClick(Sender: TObject); begin if form_principal_ag.itemindex = -1 then showmessage('selecione um telefone...') Pag. 83/176

else begin form_dados_ag.Caption := 'EXCLUSO:'; form_dados_ag.ShowModal; F_le_ini(Eagenda.Text); end; end; procedure Tform_principal_ag.BBconsultaClick(Sender: TObject); begin if form_principal_ag.itemindex = -1 then showmessage('selecione um telefone...') else begin form_dados_ag.Caption := 'CONSULTA:'; form_dados_ag.ShowModal; end; end; No evento ONSHOW do formulrio de dados da agenda, colocaremos os comandos para cada tipo de chamada, como a seguir: if form_dados_ag.Caption = 'INCLUSO:' then begin // programao para a tela de dados em modo de incluso end; if form_dados_ag.Caption = 'ALTERAO:' then begin // programao para a tela de dados em modo de alterao end; if form_dados_ag.Caption = 'EXCLUSO:' then begin // programao para a tela de dados em modo de excluso end; if form_dados_ag.Caption = 'CONSULTA:' then begin // programao para a tela de dados em modo de consulta end; Para definir efetivamente a programao do evento ONSHOW, utilizaremos a tela de dados com o formato a seguir:

Pag. 84/176

Agora podemos complementar a programao do ONSHOW: procedure Tform_dados_ag.FormShow(Sender: TObject); var ini: Tinifile; begin Efone.Enabled := true; Enome.Enabled := true; Eendereco.Enabled := true; Ecidade.Enabled := true; Euf.Enabled := true; Eaniversario.Enabled := true; BBconfirma.Visible := true; if not (form_dados_ag.Caption = 'INCLUSO:') then begin ini := Tinifile.create(form_principal_ag.Eagenda.Text); // cria o arquivo se no existir, ou abre se existir Efone.Text := form_principal_ag.LBfones.Items[form_principal_ag.LBfones.itemindex]; Enome.Text := ini.ReadString(Efone.Text, 'Nome', '?'); Eendereco.Text := ini.ReadString(Efone.Text, 'Endereo', '?'); Ecidade.Text := ini.ReadString(Efone.Text, 'Cidade', '?'); Euf.Text := ini.ReadString(Efone.Text, 'Estado', '?'); Eaniversario.Text := ini.ReadString(Efone.Text, 'Aniversrio', '?'); ini.free; end; if form_dados_ag.Caption = 'INCLUSO:' then begin // programao para a tela de dados em modo de incluso Efone.Text := ''; Enome.Text := ''; Eendereco.Text := ''; Pag. 85/176

Ecidade.Text := ''; Euf.Text := ''; Eaniversario.Text := ''; Efone.SetFocus; end; if form_dados_ag.Caption = 'ALTERAO:' then begin // programao para a tela de dados em modo de alterao Efone.Enabled := false; Enome.SetFocus; end; if form_dados_ag.Caption = 'EXCLUSO:' then begin // programao para a tela de dados em modo de excluso Efone.Enabled := false; Enome.Enabled := false; Eendereco.Enabled := false; Ecidade.Enabled := false; Euf.Enabled := false; Eaniversario.Enabled := false; BBconfirma.SetFocus; end; if form_dados_ag.Caption = 'CONSULTA:' then begin // programao para a tela de dados em modo de consulta Efone.Enabled := false; Enome.Enabled := false; Eendereco.Enabled := false; Ecidade.Enabled := false; Euf.Enabled := false; Eaniversario.Enabled := false; BBconfirma.Visible := false; BBsaida.SetFocus; end; end; E concluir a programao do boto CONFIRMA: procedure Tform_dados_ag.BBconfirmaClick(Sender: TObject); var ini: Tinifile; begin ini := Tinifile.create(form_principal_ag.Eagenda.Text); // cria o arquivo se no existir, ou abre se existir if form_dados_ag.Caption = 'EXCLUSO:' then begin // exclui a sesso Pag. 86/176

ini.EraseSection(Efone.Text); Showmessage('Telefone excluido com sucesso.'); close; end else begin // grava a sesso ini.WriteString(Efone.Text, 'Nome', Enome.Text); ini.WriteString(Efone.Text, 'Endereo', Eendereco.Text); ini.WriteString(Efone.Text, 'Cidade', Ecidade.Text); ini.WriteString(Efone.Text, 'Estado', Euf.Text); ini.WriteString(Efone.Text, 'Aniversrio', Eaniversario.Text); close; end; ini.free; end; Como resultado final, teriamos o agenda;ini com o seguinte formato: [(11)2666-3030] Nome=JOAO DA SILVA Endereo=ENDEREO DELE Cidade=CIDADE DELE Estado=SP Aniversrio=12/12/2000 [(11)2266-5770] Nome=OUTRO ELEMENTO Endereo=END. OUTO Cidade=CID.OUTRO Estado=RJ Aniversrio= Aniversrio=12/12/2000 [(11)2277-5770] Nome=ELEMENTO Endereo=END. Cidade=CID. Estado=RJ Aniversrio=1/1

Pag. 87/176

2.13- Agenda usando XML Vamos agora melhorar a nossa agenda: vamos utilizar um arquivo em formato XML, e componentes que facilitam a manipulao desta tabela. Inicialmente precisamos criar um arquivo em formato XML. Um arquivo em formato XML montado da mesma forma que arquivos HTML uma linguagem de marcao. Veja o exemplo comentado a seguir: <?xml version="1.0" standalone="yes"?> - indica que XML <DATAPACKET Version="2.0"> - inicio das informaes <METADATA> - abre o METADATA (definio dos campos) <FIELDS> - inicio da definio dos campos <FIELD attrname="telefone" fieldtype="string" WIDTH="13"/> - campo, nome, tipo, tamanho <FIELD attrname="nome" fieldtype="string" WIDTH="50"/> <FIELD attrname="endereco" fieldtype="string" WIDTH="60"/> <FIELD attrname="cidade" fieldtype="string" WIDTH="20"/> <FIELD attrname="estado" fieldtype="string" WIDTH="2"/> <FIELD attrname="aniversario" fieldtype="string" WIDTH="10"/> </FIELDS> - fim da definio dos campos </METADATA> - fim do metadata <ROWDATA> - inicio dos registros <ROW - registro telefone="(11)2626-1212" campos e seus conteudos nome="Marcos da Silva" endereco="rua de baixo" cidade="So Paulo" estado="SP" aniversario="12/12/1970" /> - fim do registro </ROWDATA> - fim dos registros </DATAPACKET> - fim dos dados A partir deste arquivo em formato XML, possivel criar uma aplicao utilizando um componente denominado CLIENT DATA SET. Este componente encontrado na palheta DATA ACCESS. Para utiliz-lo, clique no componente e em seguida no formulrio. Veja o componente a seguir:

O prximo passo LIG-LO ao arquivo descrito acima. Para isso, usando o bloco de notas digite o arquivo acima (sem os comentrios em vermelho) e salve-o como AGENDA.XML. Em seguida, na propriedade FILE NAME, clique no boto como indicado na figura a seguir:

Pag. 88/176

Em seguida, localize e selecione o arquivo AGENDA.XML criado anteriormente, conforme a figura a seguir:

Pag. 89/176

Feito isso, mude a propriedade ACTIVE para true. Se o DELPHI acusar algum erro, porque o formato de seu XML contm erros. No sendo apresentado nenhum erro, poderemos ligar a nossa tabela a outros componentes. Para isso, use o componente DATASOURCE da palheta DATA ACCESS, mudando a propriedade DATA SET dele para o nome do CLIENT DATA SET anterior. Se voc no mudou o nome DEFAULT deste componente, seu nome ser ClientDataSet1, conforme a figura a seguir:

Agora ser possivel ligar a nossa tabela aos demais componentes. Podemos ento ligar a um DBGRID, que permite visuaizar os dados e um DBNAVIGATOR que permite navegar pela tabela. Nossa aplicao ficou assim:

Pag. 90/176

importante entender a ligao entre os componentes: Ligamos o ClientDataSet1 ao DataSource1 pela propriedade DATASET do DataSource1:

Ligamos o DataSource1 ao DBGrid1 pela propriedade DataSource do DBGrid1.

Ligamos o DataSource1 ao DBNavigator1 pela propriedade DataSource do DBNavigator1:

Veja que facilidade: Nossa aplicao est completa. Voc poder editar e navegar nos dados, e o DBNavigator, atravs de seus botes, permitir incluir, excluir, alterar e ver todos os dados de sua tabela.

Pag. 91/176

possivel manipular diretamente os dados do CLIENTDATASET. Desta forma, no necessrio usar o DataSorce, Dbgrid e Dbnavigator, o programador pode fazer a sua propria aplicao executando comandos para manipular os dados da tabela. A seguir apresentamos uma tabela de mtodos para a manipulao do arquivo, seu formato de chamada ser <nome do clientdataset>.<mtodo> : First move o ponteiro para o primeiro registro Last move o ponteiro para o ltimo registro Prior - move o ponteiro para o registro anterior Next - move o ponteiro para o prximo registro Edit Edita um registro Append inclui um registro no final do arquivo Insert inclui um registro antes do registro corrente Delete Exclui um registro Post Efetiva a alterao na tabela. Outro comando muito importante o apresentado a seguir: <nome do clientdataset>.fieldbyname(<nome do campo>).AsString; Este comando retorna o contedo de qualquer campo, como string, existente no registro onde o ponteiro da tabela est parado. Veja a seguir um exemplo de como efetuar incluso de registros:
<nome do clientdataset>.append; // inclui registro no final da tabela <nome do clientdataset>fieldbyname(<nome do campo>).AsString:=<varivel>; // coloca o valor <nome da tabela>.post; // atualiza a tabela;

Ateno: no esquea de colocar, antes do nome do CLIENTDATASET, o nome do formulrio onde a tabela se encontra, caso no esteja do formulrio da UNIT onde est colocado o comando em questo. <Nome do FORM>.<nome do clientdataset>fieldbyname(<nome do campo>).AsString; Veja um exemplo, considerando que seu ClientDataSet tem como NAME CDSagenda, e sua tabela XML possui um campo telefone: CDSagenda.First; // posiciona no primeiro registro while not CDSagenda.Eof do // faz enquanto no chegou no fim de arquivo begin showmessage(CDSagenda.FieldByName('telefone').AsString); // mostra o telefone CDSagenda.Next; // vai para o proximo registro end; CDSagenda.Edit; // edita o registro corrente, no caso o ultimo CDSagenda.FieldByName('telefone').AsString := '999999999'; // coloca novo conteudo CDSagenda.Post; // efetiva a alterao.

Pag. 92/176

2.13.1- Criando o XML Para criar o seu XML, sem que voc tenha criado previamente um arquivo para depois conectar com o CLIENTDATASET, possivel, atravs deste mesmo componente criar a sua tabela e depois grav-la. Para isso, pegue o CliENTDATASET, coloque no formulrio e clique com o boto direito sobre ele:

Selecione, conforme indicado na figura, a opo Fields Editor, o Delphi abrir a tela de edio de campos do CLIENTDATASET, Clique com o boto direito e selecione NEW FIELD, conforme indicado na figura a seguir:

Pag. 93/176

Crie agora os campos desejados, repetindo esta operao para todos os campos. A tela de definio de cada campo mostrada a seguir:

Pag. 94/176

Terminada a criao dos campos, volte ao CLIENTDATASET para criar a instncia da sua tabela, usando novamente o boto direito, selecionando a opo como indicado a seguir:

Note que seu CLIENTDATASET est ativ, e a instncia foi criada, mas ele ainda est apenas na memria do seu computador. Para criar efetivamente o arquivo, use novamente o botao direito do mouse, escolhendo a opo indicada:

Agora o DELPHI abrir um DIALOGBOX para que voc escolha o local onde o arquivo ser salvo. No esquea de colocar a trilha completa e nome do arquivo na propriedade FileName do seu CLIENTDATASET, conforme a figura:

Pag. 95/176

Pronto, seu arquivo XML foi criado e pode ser usado normalmente.

Pag. 96/176

2.14- Bancos de dados e tabelas Vamos agora trabalhar com pequenos bancos de dados. Os bancos de dados, como descritos anteriormente, so compostos de tabelas. Para aprender a manipular estas tabelas utilizando o DELPHI vamos criar uma aplicao simples, capaz de manipular uma tabela simples, uma tabela de clientes. Para um bom desenvolvimento, sempre que tabelas forem envolvidas numa aplicao, o primeiro passo definir a estrutura da tabela (ou tabelas). Em seguida, como estamos desenvolvendo uma aplicao visual, iremos descrever (ou definir) as telas (ou formulrios). A partir dai passamos a programao procedural (ou manual, caso exista). Para a nossa aplicao vamos criar a tabela descrita a seguir: NOME DA TABELA : AQCL Arquivo de clientes Campo CODCL NOMCL ENDCL DATCL LDCCL Finalidade Armazenar o cdigo do cliente Nome do cliente Endereo Data de alterao/cadastramento Limite de crdito tipo A A A D N tamanho 14 50 50 10 ( automtico nn/nn/nnnn ) limite do tipo.

Como prximo passo, vamos criar esta tabela no DELPHI. Para isso acessaremos a opo TOOLS-DATABASE DESKTOP. Esta opo permitir que criemos a tabela. Acesse agora a opo FILE NEW TABLE OK estaremos usando o padro paradox, que nativo do DELPHI). O sistema apresentar uma tela para que possamos criar nossa tabela. importante observar que caso a tabela possua um ndice principal, devemos dar um DOUBLE CLICK na coluna KEY. Para criar um ndice secundrio, usamos a opo TABLE PROPERTIES SECONDARY INDEXES DEFINE. Uma vez criada a tabela podemos comear a criar a aplicao que ir manipula-la. Como exemplo inicial, iremos desenvolver um formulrio que seja o mais simples e objetivo. Para isto, j no formulrio principal na nossa aplicao iremos executar os passos a seguir: 1Na barra DATA ACCESS (caso voc esteja utilizando o DELPHI 6 ser na barra BDE) selecione TABLE. Inclua no formulrio conforme a seguir:

Pag. 97/176

Este componente permitir que a aplicao localize e abra a tabela. Para isso, usando o OBJECT INSPECTOR selecione PROPERTIES DATABASE NAME e coloque aqui a trilha completa para a localizao do arquivo, terminado com barra. Veja que no exemplo anterior, nossa tabela foi criada na trilha \Windows\Temp\ Em seguida, na propriedade TABLE NAME coloque o nome da tabela ( AQCL no nosso exemplo). ATENO, se quando voc clicar na seta a direita no aparecer a tabela que voc deseja abrir, porque a trilha est incorreta ou voc ainda no criou a tabela. Na propriedade NAME coloque o nome deste componente ( por exemplo TAQCL). Em seguida clique, usando o boto direito, sobre o componente TABLE colocado no formulrio. Ser apresentado uma lista de opes como a seguir. Selecione a opo FIELDS EDITOR, ser apresentada uma nova tela:

Clique novamente com o boto direito e o DELPHI apresentar uma nova lista de opes. Clique em ADD ALL FIELDS. Sero inclusos todos os campos da tabela na aplicao. Vamos agora incluir um componente que o responsvel por ligar a tabela aos demais componentes de acesso de banco de dados. Este componente a ser includo o DATA SOURCE. Aps inclu-lo v at a propriedade DATASET e inclua o nome do componente TABLE ( no nosso exemplo TAQCL ) , na propriedade NAME o nome da tabela iniciado por DS ( por exemplo DSAQCL ). Note que todos os nomes que damos aos componentes criados tm a finalidade de Pag. 98/176

facilitar a sua identificao. Veja sua apresentao a seguir:

Vamos agora incluir o componente que permitir manipular a tabela propriamente dita. Este componente o DBGRID, e est na palheta DATA CONTROLS:

Aps coloca-lo no formulrio, mude sua propriedade DATA SOURCE, colocando o nome do componente que acessa a nossa tabela (no nosso caso DSAQCL). O DBGRID conter todos os dados da nossa tabela. No esquea de desativar a edio direta dos campos, em OPTIONS EDIT FALSE. Ative a sua tabela mudando a propriedade ACTIVE do TABLE ( TAQCL) para TRUE. Note que no DBGGRID iro aparecer os campos da sua tabela. Caso voc deseja alterar o ttulo da coluna de um campo no DBGRID, use o boto direito sobre o DBGRID, entre no COLUMNS EDITOR, clique com o boto direito novamente, e escolha a opo ADD ALL FIELDS. Ser apresentada a tela de edio das colunas conforme apresentado a seguir:

Pag. 99/176

Selecione agora a coluna da qual deseja alterar o titulo, e no OBJECT INSPECTOR clique no sinal de + a esquerda a propriedade TITLE conforme a seguir:

Note que este procedimento altera o ttulo do DBGRID que voc est manipulando. Caso deseje alterar de forma que a nomenclatura se repita em todos os DBGRIDs da aplicao, mude diretamente a propriedade DISPLAY LABEL do componente TABLE (TAQCL no nosso caso). Altere tambm os HINTs, que so as explicaes apresentadas pela aplicao quando o usurio parar com o mouse sobre o compoenentes. Precisamos agora de um componente que permite manipular os dados desta tabela, este componente o DBNAVIGATOR. Inclua este componente e na sua propriedade DATASOURCE coloque DSAQCL, conforme a seguir :

Pag. 100/176

O ltimo passo abrir o arquivo. Para isso, no evento FORM ACTIVE do nosso formulrio inclua o comando TAQCL.ACTIVE:=TRUE (estamos alterando uma propriedade) ou TAQCL.OPEN (estamos usando um mtodo que altera a propriedade ACTIVE). interessante incluir um boto de sada da aplicao (um boto com o comando close no evento ON CLICK). Caso seja de seu interesse tratar o evento de cada boto do DBNAVIGATOR de acordo com suas necessidades, basta que no evento ONCLICK no DBNAVIGATOR voc identifique qual foi o boto apertado e incluir a programao. Por exemplo, caso eu queira colocar uma mensagem avisando que o sistema ir incluir um registro quando o boto de incluso for clicado, pasta colocar, no evento ONCLICK do DBNAVIGATOR a programao a seguir : If button=nbInsert then showmessage(vou incluir um registro); Note que a varivel button, fornecida no evento ONCLICK do DBNAVIGATOR da classe TNavigateBtn = (nbFirst, nbPrior, nbNext, nbLast, nbInsert, nbDelete, nbEdit, nbPost, nbCancel, nbRefresh). Os botes da DBNAVIGATOR recebem o nome conforme a seqncia abaixo: Button Valor no evento ONCLICK First Prior Next Last Insert Delete Edit Post Cancel Refresh nbFirst nbPrior nbNext nbLast nbInsert nbDelete nbEdit nbPost nbCancel nbRefresh Como exerccio complementar, recomendamos que o DBNAVIGATOR seja substitudo por botes e telas complementares. Para isto vamos aprender a seguir os comandos de manipulao direta de tabelas: Pag. 101/176

Para acessar o contedo de um campo: <nome da tabela><nome do campo>.<value> Ex: x:=aqclnomcl.value // a varivel x receber o contedo do campo nomcl da tabela aqcl, onde o cursor est. A seguir apresentamos uma tabela de mtodos para a manipulao do arquivo, seu formato de chamada ser <nome da tabela>.<mtodo> : First move o ponteiro para o primeiro registro Last move o ponteiro para o ltimo registro Prior - move o ponteiro para o registro anterior Next - move o ponteiro para o prximo registro Edit Edita um registro Append inclui um registro no final do arquivo Insert inclui um registro antes do registro corrente Delete Exclui um registro Post Efetiva a alterao na tabela. Veja a seguir um exemplo de como efetuar incluso de registros: <nome da tabela>.append; // inclui registro no final da tabela <nome da tabela><nome docampo>.value:=<varivel>; // coloca o valor no campo <nome da tabela>.post; // atualiza a tabela; Outro comando muito importante o apresentado a seguir: <nome da tabela>.filedbyname(<nome do campo>).AsString; Este comando retorna o contedo de qualquer campo, como string, existente no registro onde o ponteiro da tabela est parado. Se existir um DBGRID aberto, este comando retornar o contedo do campo do registro selecionado atualmente, indicado por uma seta do lado esquerdo. Ateno: no esquea de colocar, antes do nome da tabela, o nome do formulrio onde a tabela se encontra, caso no esteja do formulrio da UNIT onde est colocado o comando em questo. <Nome do FORM>.<nome da tabela>.filedbyname(<nome do campo>).AsString;

Pag. 102/176

2.15- Gerando relatrio Uma forma rpida de criar um relatrio no DELPHI utilizar o QUICK REPORT. Para isso deve-se abrir um novo formulrio, sendo necessrio um formulrio para cada relatrio, adicionando-se a este formulrio um componente TABLE:

Caso deseje, aproveite a abertura da tabela j feita a partir de outro formulrio. Inclua agora o QUICK REPORT (primeiro componente da barra Qreport), conforme apresentado a seguir:

Pag. 103/176

Muda-se o DATA SET para o nome da tabela aberta (<formulrio>.<tabela> caso a tabela esteja em outro formulrio). Em seguida inclui-se um Q.R.BAND que ser utilizado como ttulo, e para isso inclumos o Q.R.LABEL. Este ttulo ser impresso somente na primeira pgina do relatrio. Veja a seguir:

.Em seguida inclumos outro Q.R.BAND, mudando o BAND TYPE para RBCOLUMN HEADER, que permite definir o nome das colunas que devem ser impressas. Acerte tambm o nome da coluna, incluindo dois QRLABELs, alterando seus CAPTIONs para Cdigo e Nome, conforme a seguir: Pag. 104/176

Note que esta QRBAND se repetir em todas as pginas do relatrio. Inclua agora mais um QRBAND, mudando o BAND TYPE para RBDETAIL. Inclua neste QRBAND os Q.R.DBTEXTs, atravs do qual definimos os campos a serem impressos, conforme a seguir:

Atravs do DATASET e do FIELD do QRBTEXT, definimos o campo da tabela que ser impresso, conforme o OBJECT INSPECTOR a seguir:

Pag. 105/176

Aps estes ajustes, seu Quick report ficaram como segue:

Agora, para ativar o seu relatrio, inclua um boto no seu formulrio principal, e no seu evento ON CLICK, use o comando: <nome do formulrio>.<nome do quick report>.preview;

Pag. 106/176

3- O INTERBASE (FIREBIRD)
O INTERBASE nada mais que um banco de dados completo, SQL, e free, ou seja, pode ser instalado sem custo nenhum em qualquer mquina. 3.1- Conceitos bsicos Baixe da internet o programa de instalao do FireBird. Salve este arquivo no diretrio principal e em seguida, usando o windows explorer, clique sobre ele e o banco de dados ser descompactado. Basta agora instala-lo. Usando o WINDOWS explorer, Acesse a pasta banco e depois na firebird. D um duplo clique no nico arquivo deste diretrio. Ser apresentada a tela de instalao do firebird. Confirme toda a instalao. Siga as instrues e o FIREBIRD ser instalado no seu micro. Para ativar o seu servidor, clique no boto iniciar, escolha a opo programas, depois firebird, e novamente firebird. No canto inferior direito ir aparecer o cone do firebird, indicando que o mesmo est funcionando. Baixe da internet o ibaccess e instale-o em seu computador. Execute-o e a tela inicial do Ibacsses ser apresentada como na figura a seguir:

Pag. 107/176

Na tela principal, acesse a opo Options / Configure database. Ser apresentada a tela a seguir:

Clique no boto NEW. Ser apresentada a tela a seguir:

Aps definir o ALIAS do seu banco de dados, clique em OK e ser apresentada a tela a seguir:

Pag. 108/176

Preencha como acima. Clique OK. O Ibaccess retornar a tela anterior. Clique em OK novamente e a configurao do seu banco de dados foi concluda. Para banco de dados loca, no esquea do localhost. O Ibacsses ir confirmar a criao do seu banco de dados com a tela a seguir:

Basta agora cri-lo. Para isso, acesse a opo file / new database e ser apresentada a tela de criao do banco de dados. Veja a tela que ser apresentada: Pag. 109/176

No canto superior esquerdo, no campo databases, clique na seta e escolha o ALIAS do seu banco de dados. Clique em seguida no boto create e o seu banco de dados ser criado. Caso ocorra erro, verifique se as configuraes foram feitas corretamente. obrigatrio que o seu banco de dados (firebird) esteja instalado no seu computador e rodando.

Pag. 110/176

Aps a criao do banco de dados, o interbase automaticamente ir abri-lo, mostrando todas suas propriedades e atributos. A tela apresentada a mesma que ser apresentada se voc j possuir o banco de dados, e abri-lo com a opo File Open Database:

Ao abrir o banco de dados, a tela apresentada ser:

Pag. 111/176

Vale lembrar que caso voc tenha um servidor rodando com FIREBIRD REMOTO, basta selecionar a opo remote connection e o Ibaccess ir abrir um campo para a definio do nmero IP onde est o servidor. Para determinar o nmero IP do ser servidor, v para a janela DOS e digite WINIPCFG. Anote o nmero IP.,Para acessar o seu bando de dados a partir do DELPHI, voc pode usar componente do prprio interbase, que ser disponibilizado assim que voc instalar o INTERBASE no seu micro de desenvolvimento, onde se encontra o DELPHI. Vamos agora apresentar vrias formas de acessar seu banco de dados. importante ressaltar que este conexo funciona com INTERBASE, ou com o FIREBIRD at a verso 1.0. Para FIREBIRD acima de verso 1.0, recomenda-se utilizar os componentes do DBEXPRESS. A primeira forma usando os componentes da palheta INTERBASE:

Para acessar uma tabela do seu banco de dados, use a estrutura a seguir:

A seguir apresentamos a finalidade de cada componente. IBDATABASE: faz a conexo com o banco de dados. Para isso clique na propriedade PARAMS e ajuste conforme as definies do seu banco de dados. A seguir apresentamos um exemplo:

Pag. 112/176

Na propriedade DATABASENAME coloque a trilha completa e o nome do banco de dados conforme o mesmo foi criado. Para o exemplo anterior, use localhost:c:\jony\cefet\banco.gdb Na propriedade PARAMS, clique no boto de reticncias e digite: user_name=SYSDBA password=masterkey D um duplo clique na propriedade CONNECTED e a mesma dever mudar para TRUE. Caso no mude, o DELPHI indicar o erro ocorrido. IBTRANSACTION: Serve para efetivar as transaes do seu banco de dados IBSQL: Serve para enviar comandos SQL diretamente para o servidor. IBTABLE: Serve para tratar sua tabela SQL com os mesmos comandos que uma tabela PARADOX IBQUERY: permite enviar comando SQL para seu banco de dados. Estes comandos sero efetivados atravs do IBTRANSACTION Outra forma de acessar seu banco de dados atravs do DBEXPRESS e o DATAACCESS:

Este grupos de componentes foi criado para se ter uma maior portabilidade da sua aplicao, permitindo que a mesma seja acessada de forma transparente, independentemente do banco de dados utilizado. Alm disso, o DBEXPRESS transfere para local (a prpria estao de trabalho) toda a manipulao do banco de dados, gerenciando as atualizaos de forma independente. Isto descarrega trabalho do servidor, aumenta a segurana e a portabilidade da aplicao. Para utilizar o DBEXPRESS, use-o conforme a tela a seguir: Pag. 113/176

SQLCONECTION: faz a conexo com o banco de dados. SQLDATASET: faz o acesso ao banco de dados de forma unidirecional, no permitindo conflito e sobre escrita de registro. Os dados so lidos e passados ao provedor local. DATASETPROVIDER: provedor local: gerencia as alteraes CLIENTDATASET: acesso bidirecional: permite alterar e manipular toda a tabela existente no provedor local, solicitando atravs dele as atualizaes no banco de dados central. 3.2- o SQL A seguir apresentamos os comandos bsicos para a manipulao de BANCO DE DADOS SQL: Comando para consultar registros de uma tabela SELECT <CAMPO,CAMPO,CAMPO> FROM <TABELA> [WHERE <CONDICAO>] Comando para criar tabela CREATE TABLE <TABELA> (<CAMPO> <TIPO>, <CAMPO> <TIPO> ...) Tipo: date, float, varchar(tamanho), decimal(casas,decimais), integer Comando para a incluso de registros INSERT INTO <TABELA> (<campo1>, <campo2> ...) values (<valor campo1>, <valor campo2> ...) ex.: INSERT INTO CLIENTES (CODIGO,NOME, FUNDACAO) values (1231123,'joo da silva','05/15/2005') Comando para a alterao de registros Pag. 114/176

UPDATE <TABELA> SET <CAMPO>=<CONTEUDO>, .... [WHERE <CONDIO>] Comando para excluso de tabelas DROP TABLE <TABELA> Comando para a excluso de registros DELETE FROM <TABELA> [WHERE <CONDICAO>]

Pag. 115/176

3.3- Os componentes da palheta DBExpress Esta parte da apostila destina-se aqueles que tem algum interesse em aprender a conectar-se com um banco Firebird. Caso voc seja um iniciante no acesso banco de dados ou no Delphi/Kylix em geral, no se preocupe, pois nesta apostila ser apresentado o bsico de acesso dados. No Delphi 6 e 7, e no Kylix 2 e 3 Enterprise os componentes DBExpress j vem originalmente instalados. Com a paleta j devidamente instalada, ns temos os seguintes componentes(iguais tanto no Delphi, quanto no Kylix): SQLConnection; SQLDataSet; SQLQuery; SQLStoredProc; SQLTable; SQLMonitor e SQLClienteDataSet. Temos uma exceo em relao ao Delphi 7, pois neste, o componente SQLClientDataSet foi substitudo pelo , mas nada que no possa ser contornado. No final desta parte da apostila, ser explicado sobre o SimpleDataSet. Primeiramente sero apresentados os componentes DBExpress e em seguida montaremos um exemplo de acesso. A seguir detalhamos cada um dos componentes DBExpress.

Pag. 116/176

3.3.1- O SQLConnection

Este o componente responsvel pela conexo com o arquivo fsico do banco de dados (*.gdb). atravs dele, que obtemos o acesso aos dados, mas no acesso direto ao contedo das tabelas, pois isto feito utilizando-se os outros componentes. Vou listar aqui, as principais propriedades do SQLConnection: Propriedade Connected Significado Define se o componente est conectado ao banco. Ateno: para que a conexo ocorra corretamente, necessrio que o servidor Firebird ou Interbase esteja rodando, ou que o banco cliente esteja instalado, caso contrrio, na tentativa de conexo, o componente retornar a seguinte exceo: unavailable database. Define o nome da conexo a ser utilizada, no nosso caso IBConnection. Define qual ser o driver utilizado para acessar o banco, no nosso caso Interbase. Define se o componente vai requerer o nome do usurio e a senha no nomento da conexo. Essa propriedade nos mostra uma lista de sub-propriedades do componente, e dente elas, destacamos: Params.Database: Define o caminho(path) do arquivo de banco de dados. Informa-se aqui o IP do host de onde estiver o banco, caso a aplicao seja em rede. Params.SQLDialect: Define qual dialeto ser utilizado no acesso ao banco. Dialeto o conjunto de caracteres aceito pelo banco. Utilizaremos sempre o Dialeto 3, pois aceita acentos. Params.User_Name: Define qual ser o nome do usurio. Params.Password: Define a senha do usurio. Estes parmetros podem ser tambm acessados, dando-se 2 cliques rpidos em cima do componente SQLConnection. * Para se definir os valores dos parmetros em modo de execuo, utlize a sintaxe: SQLConnection1.Params.NomeDoParametro := Valor;

Connection Name DriverName LoginPrompt Params*

Pag. 117/176

3.3.2- O SQLDataSet

Um DataSet uma estrutura onde so armazenadas listas de registros do banco. O SQLDataSet nos permite mostrar o resultado de uma consulta ou de uma StoredProcedure, executar StoredProcedures que no retornem dados, ou obter os parmetros disponveis no banco(tabelas, StoredProcedures, campos de uma tabela). O SQLDataSet um DataSet unidirecional, ou seja, ele no armazena em memria muitos registros simultneos, e por causa disto, voc s pode navegar usando os mtodos First e Next. Ele no suporta atualizao de dados na memria, atualizaes devem ser feitas utilizando-se a sintaxze SQL diretas no servidor. As principais propriedades deste componente so: Propriedade Active CommandText CommandType DataSource SQLConnetion 3.3.3- O SQLQuery Significado Define se o componente est ativado, e executando o comando passado em CommandText, visto logo abaixo. Define o comando em linguagem SQL a ser passado. Podem ser passadas consultas, incluses e etc.. Define o tipo do comando que foi passado em CommandText. Seus valores so ctQuery, ctStoredProc e ctTable. Define qual ser o objeto TDataSource que ser conectado ao SQLDataSet. Define qual ser o componete do tipo TSQLConnection que prover acesso ao banco.

O SQLQuery executa comandos SQL no banco de dados, retornando resultados de consultas, incluses, excluses e etc.. O SQLQuery tambm unidirecional, s suportando a execuo de comandos SQL. Suas principais propriedades so: Propriedade Active SQL SQLConnetion Significado Define se o SQLQuery est ativado. onde devemos informar qual comando SQL dever ser executado pela Query. Define qual ser o componente do tipo TSQLConnection que prover acesso ao banco.

Pag. 118/176

3.3.4- O SQLStoredProc

O SQLStoredProc um componente especfico para a execuo de stored procedures existentes no banco. Pode armazenar o resultado de uma stored procedure que retorne um cursor(posio). Tambm um componente unidirecional. As execues das stored procedures so em sintaxe SQL. Principais propriedades: Propriedade Active SQLConnetion StoredProcName 3.3.5- O SQLTable Significado Define se o SQLStoredProc est ativado. Define qual ser o componente do tipo TSQLConnection que prover acesso ao banco. Define o nome da stored procedure a ser executada e seus parmetros, se existirem.

O SQLTable representa uma tabela do banco de dados. O TSQLTable traz todas as colunas e linhas da tabela especificada, mas tambm um componente unidirecional, no permitindo a movimentao entre os registros. Trabalha com uma nica tabela de cada vez, podendo realizar alteraes, incluses etc.. Principais propriedades: Propriedade Active SQLConnetion TableName Significado Define se o SQLTable est conectado tabela especificada. Define qual ser o componete do tipo TSQLConnection que prover acesso ao banco. onde definimos qual o nome da tabela a ser acessada.

Pag. 119/176

3.3.6- O SimpleDataSet

O SimpleDataSet foi introduzido no lugar do SQLClientDataSet no Delphi 7. Ele tem a mesma funo bsica do SQLClientDataSet, ou seja, fazer cache de dados e permitir alteraes fora do servidor. Principais propriedades: Propriedade Active Significado Define se o componente est conectado ao SQLConnection, e portanto com as informaes atualizadas. Ele pode trabalhar desconectado, pois faz cache dos dados em memria. Porm, os dados armazenados no sero os mais atuais. Define qual ser o componete que prover acesso ao banco de dados. Esta propriedade refere-se a classe DataSet interna do SimpleDataSet. Suas sub-propriedades so: DataSet.Active: define se o dataset interno est ativo. DataSet.CommandText: define qual ser o comando SQL passado ao dataset. DataSet.CommantType: define qual o comando passado em CommandText. Seus valores so ctQuery, ctStoredProc e ctTable. Atente que so os mesmos conceitos do j vistos no SQLClientDataSet.

Connection DataSet

Pag. 120/176

4- Uma aplicao completa com o DBExpress


4.1- Criando o banco de dados Agora que j conhecemos quais so os componentes da tecnologia DBExpress e suas funes, vamos montar um exemplo utilizando o Delphi 6 e o Firebird verso 1(compilao 1.0.2.908). O exemplo poder ser criado no Kylix ou Delphi 7, pois so os mesmos componentes, e a mesma tecnologia de acesso. Para este exemplo utilizaremos um banco de dados com uma nica tabela chamada Comandos(onde guardaremos os comandos e funes pascal). Para criar o banco com esta tabela, primeiro crie um novo arquivo do tipo texto(ex.: Banco.txt), contendo os seguintes comandos SQL: create database 'Testedb.gdb'; connect 'Testedb.gdb'; create table Comandos(Sintaxe varchar(30) not null, Funcao varchar(50), constraint Sint_Chave primary key(Sintaxe)); Salve o arquivo, e com o Firebird/Interbase j instalado, execute o programa Isql.exe, que se encontra na pasta \bin da instalao do servidor em um promtp do MS-Dos(lembre-se que o servidor tem de estar rodando c:\Firebird\bin\ ibguard.exe): C:\Firebird\Bin\>isql u SYSDBA p masterkey Quando aparecer o prompt do Isql, digite: SQL> input c:\pasta\Banco.txt; [Enter] Responta Y pergunta que aparecer, e o banco ser criado. D exit; para sair do Isql, e mova o banco recm criado(Testedb.gdb) para a pasta onde voc for criar nosso exemplo no Delphi, para ficar mais simples e feche o prompt do MS-Dos nosso trabalho com ele j terminou. Agora que nosso banco de dados j est criado, podemos iniciar a criao do exemplo pelo Delphi.

Pag. 121/176

4.2- Criando uma aplicao Criando a aplicao Menu File New CLX Application. Vamos criar uma CLX Application para que no ocorram problemas na abertura deste exemplo pelo Kylix. Monte um formulrio como o da imagem:

No componente SQLConnection, defina os seguintes valores para as propriedades: ConnectionName: IBConnection DriverName: Interbase LoginPrompt: False Pag. 122/176

Os valores das outras propriedades automaticamente se preenchero ao se informar as duas primeiras. Clique no boto de reticncias da propriedade Params, e no item DataBase informe o caminho do nosso arquivo Testedb.gdb. Aponte a propriedade SQLConnection dos componentes SQLDataSet1 e SQLQuery para o SQLConnetion1. Utilizaremos o SQLDataSet para realizar as incluses, alteraes e excluses e o SQLQuery para realizar as consultas. oportuno neste momento, falarmos um pouco sobre as transaes do Firebird/Interbase. Transaes so mtodos adotados nos bancos de dados Cliente/Servidor para garantir a integridade de todos os dados alterados no banco. Vou exemplificar: Voc precisa corrigir uma folha de pagamento de uma empresa, onde os registros precisam passar por muitas validaes e devem ser confirmados ou abandonados todos de uma vez, fazendo sucessivas alteraes em duas ou mais tabelas. E se no meio do processo ocorre algum erro? Algumas tabelas tero seus dados gravados, e outras no, tornando os resultados da operao no confiveis, com informaes incorretas. neste ponto que entram as transaes. Quando se inicia uma transao no banco, o servidor faz cache em memria de todos os registros das tabelas que esto sendo atualizados/apagados. Os dados s so permanentemente gravados no banco, quando a transao se completa com sucesso(com o comando Commit). Caso algum erro venha a ocorrer no meio da transao, todos os dados so abandonados, retornando as tabelas ao modo como estavam antes, sem perda de dados, corrupo, ou erros nas tabelas. O recurso de transao no existe em bancos Desktop(Paradox por exemplo), apenas em bancos Cliente/Servidor, e tem a funo principal de manter a integridade e seguraa dos dados, principalmente onde existem muitos clientes acessando as mesmas informaes ao mesmo tempo. Neste meu exemplo, estarei utilizando o conceito de transao no apenas para incluir, alterar ou excluir dados da tabela, mas tambm para realizar as consultas. Quando voc abre uma transao para realizar uma consulta, voc sempre tem certeza que os dados retornados so os mais atuais possveis, independente se outros clientes esto alterando ou excluindo o registro que voc est pesquisando. Para finalizar uma transao gravando os dados no banco, utilizamos o comando Commit, e para desfazer as alteraes realizadas pela transao, sem gravar as informaes, utilizamos o comando Rollback.

Pag. 123/176

Para podermos utilizar corretamente as transaes em nosso exemplo, precisamos declarar uma varivel, no incio da nossa unit: var Form1: TForm1; Transacao: TTransactionDesc; implementation {$R *.xfm} A TtransactionDesc uma estrutura(record) que define a transao. Um ponteiro dessa estrutura passado cada vez que se inicia, finaliza ou se cancela uma transao. Utilizaremos transaes em todas as nossas aes no banco de dados. E essa exatamente a inteno nos bancos Cliente/Servidor. D um duplo clique no boto Incluir Comando, e no editor de cdigos, digite: procedure TForm1.BtIncluirClick(Sender: TObject); begin try Transacao.TransactionID := 1; Transacao.IsolationLevel := xilREPEATABLEREAD; SQLConnection1.StartTransaction(Transacao); SQLDataSet1.Close; SQLDataSet1.CommandType := ctQuery; SQLDataSet1.CommandText := 'insert into Comandos(Sintaxe, Funcao) values(:Sint, :Func)'; SQLDataSet1.ParamByName('Sint').AsString := EdSintaxe.Text; SQLDataSet1.ParamByName('Func').AsString := EdFuncao.Text; SQLDataSet1.ExecSQL; SQLConnection1.Commit(Transacao); except on Exc:Exception do begin ShowMessage('Ocorreu um erro na tentativa de incluso do registro: ' + Exc.Message); SQLConnection1.Rollback(Transacao); end; end; end; Definimos um nmero para a transao que for ser iniciada(TransactionID := 1). Este nmero de transao deve ser nico, no tendo outras transaes utilizando o mesmo. Isto necessrio para que cada transao possa ser executada em uma determinada ordem pelo banco, sem que ocorram conflitos.

Pag. 124/176

Logo abaixo, definimos o IsolationLevel para a transao. O IsolationLevel determina como a transao interagir com outras transaes simultneas que estejam trabalhando com as mesmas tabelas. Para informaes mais detalhadas sobre os nveis de isolao, consulte o help do delphi. Iniciamos a transao com o comando: SQLConnetion1.StartTransaction(Transacao); Enviamos o comando SQL para o SQLDataSet1. As palavras iniciadas com : (dois pontos) so parmetros, onde passamos seu valor pela propriedade ParamByName(nome).AsTipo := Valor; Por final executamos o comando com SQLDataSet1.ExecSQL e finalizamos a transao com SQLConnetion.Commit(Transacao). Caso algum erro ocorra(comando SQL invlido ou conexo com o banco problemtica), o cdigo vai para a parte except, e encerramos a transao com SQLConnetion.Rollback(Transacao), sem gravar os dados no banco. D um duplo clique no boto Alterar Comando, e no editor de cdigos, digite: procedure TForm1.BtAlterarClick(Sender: TObject); begin try Transacao.TransactionID := 1; Transacao.IsolationLevel := xilREPEATABLEREAD; SQLConnection1.StartTransaction(Transacao); SQLDataSet1.Close; SQLDataSet1.CommandType := ctQuery; SQLDataSet1.CommandText := 'update Comandos set Sintaxe = :Sint, Funcao = :Func where Sintaxe = :Sint'; SQLDataSet1.ParamByName('Sint').AsString := EdSintaxe.Text; SQLDataSet1.ParamByName('Func').AsString := EdFuncao.Text; SQLDataSet1.ExecSQL; SQLConnection1.Commit(Transacao); except on Exc:Exception do begin ShowMessage('Ocorreu um erro na tentativa de alterao do registro: ' + Exc.Message); SQLConnection1.Rollback(Transacao); end; end; end;

Pag. 125/176

D um duplo clique no boto Excluir Comando, e no editor de cdigos, digite: procedure TForm1.BtExcluirClick(Sender: TObject); begin try Transacao.TransactionID := 1; Transacao.IsolationLevel := xilREPEATABLEREAD; SQLConnection1.StartTransaction(Transacao); SQLDataSet1.Close; SQLDataSet1.CommandType := ctQuery; SQLDataSet1.CommandText := 'delete from Comandos where Sintaxe = :Sint'; SQLDataSet1.ParamByName('Sint').AsString := EdSintaxe.Text; SQLDataSet1.ExecSQL; SQLConnection1.Commit(Transacao); except on Exc:Exception do begin ShowMessage('Ocorreu um erro na tentativa de excluso do registro: ' + Exc.Message); SQLConnection1.Rollback(Transacao); end; end; end; D um duplo clique no boto Procurar, e no editor de cdigos, digite: procedure TForm1.BtProcurarClick(Sender: TObject); var Consulta: string; begin if Trim(EdBusca.Text) <> '' then begin Consulta := 'select Sintaxe, Funcao from comandos where '; //No campo: if RadioCampo.ItemIndex = 0 then Consulta := Consulta + 'Sintaxe ' else Consulta := Consulta + 'Funcao '; //Que: if RadioTipo.ItemIndex = 0 then begin Consulta := Consulta + 'starting with ''' + EdBusca.Text + ''''; end else if RadioTipo.ItemIndex = 1 then Consulta := Consulta + 'like ''%' + EdBusca.Text + '%''' else Pag. 126/176

Consulta := Consulta + 'like ''%' + EdBusca.Text + ''''; try Transacao.TransactionID := 1; Transacao.IsolationLevel := xilREPEATABLEREAD; SQLConnection1.StartTransaction(Transacao); SQLQuery1.Close; SQLQuery1.SQL.Clear; SQLQuery1.SQL.Append(Consulta); SQLQuery1.Open; SQLConnection1.Commit(Transacao); except on Exc:Exception do begin ShowMessage('Ocorreu um erro na consulta: ' + Exc.Message); SQLConnection1.Rollback(Transacao); end; end; CarregaLista; end; end; Como foi apresentado, use o SQLQuery para realizar as consultas. A propriedade SQL do SQLQuery uma stringlist, que contm os comandos a serem executados. Limpamos o contedo da lista SQL do SQLQuery com SQL.Clear, adicionamos o comando referente consulta, e a executamos com o comando Open. Preencha varivel Consulta conforme o usurio escolhe os filtros nos RadioGroups. Para maiores informaes sobre sintaxe SQL para filtro, leia minha apostila sobre Firebird. Aps realizarmos a consulta, executamos a procedure CarregaLista, que vai preencher o ListView com o ResultSet retornado pelo banco, cujo cdigo o dado a seguir: procedure TForm1.CarregaLista; begin SQLQuery1.First; ListView1.Items.Clear; while true do begin ListView1.Items.Add; ListView1.Items.Item[ ListView1.Items.Count - 1 ].Caption SQLQuery1.Fields.Fields[0].AsString; ListView1.Items.Item[ ListView1.Items.Count 1 ].SubItems.Add(SQLQuery1.Fields.Fields[1].AsString); try SQLQuery1.Next; except break; end; end; Pag. 127/176

:= -

end; A procedure funciona da seguinte maneira: Aps realizarmos a consulta com o comando Open do SQLQuery, direcionamos o cursor do DataSet para o primeiro registro(SQLQuery1.First).Enquanto a condio for verdadeira, o while continua, at pegar todos os registros do DataSet e pass-lo para o ListView, um a um, com SQLQuery.Next, passando os valores de Field[0] e Field[1]. Logo que o cursor do DataSet chegar no ltimo registro, o comando SQLQuery.Next resultar em uma exceo, pois no existem mais registros, executando break e saindo do loop. No evento OnDblClick(Duplo clique) do ListView1, digite: procedure TForm1.ListView1DblClick(Sender: TObject); begin EdSintaxe.Text := ListView1.ItemFocused.Caption; EdFuncao.Text := ListView1.ItemFocused.SubItems.Text; end; Isso far com que ao ser dado um duplo clique em algum dos valores mostrados, o contedo seja transferido para os edits de edio, para poderem ser alterados. D um duplco clique no formulrio e digite no editor de cdigos: procedure TForm1.FormCreate(Sender: TObject); begin try SQLConnection1.Connected := true; except ShowMessage('Erro ao tentar conectar-se ao banco.'); end; end; Assim, quando o form for criado, a aplicao tentar se conectar ao banco. E no evento OnClose do form, digite: procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin SQLConnection1.Connected := false; //Para que a conexo seja finalizada ao se fechar o form. end; Agora, j temos um formulrio bsico para entrada de dados, e alteraes das informaes do banco. S utilizamos 3 componentes de acesso dados.

4.3- Criando uma DataSet navegvel Pag. 128/176

Neste nosso exemplo, ns no utilizamos nenhum DataSet navegvel, visto que os componentes DBExpress so unidirecionais, e no permitem tal fato. Para tanto utilizamos o conjunto SQLQuery + ListView para poder trazer tela a lista de registros. Mas voc pode encontrar situaes onde um DataSet navegvel e de fcil manuteno seja necessrio. Para podermos ter tal recurso, utilizamos o SQLClientDataSet, que pode armazenar um DataSet visualizvel e navegvel atravs de um DBGrid. Ento vamos aprender como fazer isso. Primeiro utilizando o SQLClientDataSet do Delphi 6 e Kylix, e depois utilizando o SimpleDataSet, disponvel no Delphi 7. Utilizando o SQLClientDataSet Monte um formulrio como o da figura (CLX Application):

Configure o SQLConnection da mesma maneira que no exemplo anterior. No SQLClientDataSet aponte a propriedade DBConnention para o SQLConnetion1. Preencha a propriedade CommandText com select * from COMANDOS, ou clique no boto das reticncias para preencher o campo. Escolha ctQuery para a propriedade CommandType. Na propriedade DataSet do DataSource aponte para o SQLClientDataSet1. Conecte o DBGrid e o DBNavigator ao DataSource, e ative as conexes. Caso existam Pag. 129/176

registros na tabela Comandos, eles aparecero no DBGrid. Rode a aplicao e voc pode utilizar os botes do DBNavigator para alterar os dados. Temos ento um DataSet navegvel e atualizvel. O SQLClientDataSet mantm em memria todos os registros recuperados da tabela ou da juno de tabelas qual estiver conectado, permitindo a alterao. E ele no um componente unidireional, permitindo que o cursor navegue entre os registros. Com o SQLClientDataSet, voc pode trabalhar em um ambiente Cliente/Servidor ou em um ambiente Desktop, pois voc pode definir o filtro aplicado tabela por parmetros SQL, ou pela propriedade Filter. Quando voc filtra a tabela por meio de instrues SQL(clusula Where), o banco apenas retorna o resultado da pesquisa, assim como acontece com os outros componentes unidirecionais da tecnologia DBExpress. Mas quando voc escolhe filtrar pela propriedade Filter, toda a tabela trazida para a aplicao, e o filtro sendo aplicado sobre ela, consumindo mais banda da rede e memria. Por isso, em ambientes Cliente/Servidor, prefira realizar o filtro principal diretamente com instrues SQL, e refiltrar utilizando a propriedade Filter. Vamos agora Utilizar o SimpleDataSet (Delphi 7) Para utilizar o SimpleDataSet monte o mesmo form anterior, apenas substituindo o SQLClientDataSet pelo SimpleDataSet. No SimpleDataSet, preencha a propriedade Connection com o SQLConnetion1. Abra o item DataSet, e na propriedade CommandText ponha select * from COMANDOS ou clique no boto de reticncias. Escolha ctQuery para CommanType, e na propriedade DataSource aponte para o DataSource1. Ative o SimpleDataSet, e se o SQLConnetion estiver conectado, e a tabela Comandos contiver registros, eles aparecero no DBGrid. Rode a aplicao e voc poder trabalhar nos registros com o DBNavigator. Nestes exemplos foi omitido muito cdigo que seria referente validao das entradas de dados, como verificar se os edits contm algum texto ou no. Mas este um exemplo bsico de acesso, porm no distante de como deve ser realmente uma aplicao do tipo Cliente/Servidor, por exemplo sem conter um DataSet navegvel, que traria um consumo maior de recursos. O uso da tecnologia DBExpress baseada no fato de que o servidor quem faz tudo na aplicao, ou seja, o cliente apenas mostra os resultados das sentenas SQL, ou no caso de incluses/alteraes no mostra nada, apenas que foi feito. As restries impostas pelo fato de utilizar componentes unidirecionais, no permitindo a navegao entre registros compensada pela velocidade no processamento principalmente. Onde antes seria necessrio a utilizao de computadores mais potentes para os clientes, apenas se melhora a performance do servidor, trazendo muita economia tanto na manuteno quanto na implementao do banco de dados. 4.4- Outras aplicaes do SimpleDataSet Pag. 130/176

Da palheta DBEXPRESS:

Pegue o SQLconnection:

Defina a Connection Name (IBlocal para INTERBASE):

Na propriedade parmetros, coloque a trilha completa do banco de dados, precedido por Pag. 131/176

localhost (cuidado: o banco de dados tem que estar instalado e rodando no micro onde voc est programando):

Deixe a propriedade LOGINPROMPT = FALSE para que, no momento da conexo, o componente NO PEA o usuario. Ative agora a conexo:

Pegue o simpledataset: Pag. 132/176

Acerte a connection:

Avise que o simple data set uma tabela e escolha a tabela. Note que se a connection Pag. 133/176

estiver ativa, o SimpleDataSet mostrar sozinho as tabelas existentes no banco de dados (com o command type = ctTable)

Para acessar os dados preciso do datasource:

Agora vamos conecta-lo ao Simpledataset Pag. 134/176

Para ver os dados, inclua um dbgrid:

Conecte-o ao datasource e depois ative novamente o simpladataset: Pag. 135/176

Para escolher apenas algumas colunas, alterando sua apresentao, clique com o boto direito sobre o dbgrid, entre no columns editor e adicione os campos que desejar (defina Field, Tittle.caption, etc)

Para criar em tempo de execuo: Pag. 136/176

em USES inclua SimpleDS e depois crie o simple data set. para criar como propriedade do formulrio, inclua em private ou public o comando: V_SDS_aqbai: TsimpleDataset; Para criar como varivel de sistema, inclua em VAR: V_SDS_aqbai: TSimpleDataset; Dentro do evento ou no onshown ( para usar em todo formulrio), inclua o comando V_SDS_aqbai := TSimpleDataset.Create(Self); V_SDS_aqbai.Connection := CConnection; V_SDS_aqbai.DataSet.CommandType:=ctTable V_SDS_aqbai.DataSet.CommandText:=<nome de uma tabela do banco> V_SDS_aqbai.DataSet.Active:=true; Para acessar o conteudo de um campo da tabela aberta: Teste:= V_SDS_aqbai.FieldByName(<nome do campo>).AsString Para usar como query (comando SQL): V_SDS_aqbai.DataSet.CommandType:=ctQuery V_SDS_aqbai.DataSet.CommandText:=<comando SQL> V_SDS_aqbai.DataSet.Active:=true; Criando uma funo que usa o QUERY, e executa um comando SQL: Pegue o SQLconnection e cofigure como descrito anteriormente. Na diretiva PUBLIC, do seu Form1, defina a funo: function F_comando(conexao_QUERY: TSQLconnection; comando: Ansistring):boolean; Na sua aplicao, inclua a funo definida: function Tform1.F_comando(// executa comando SQL sozinho, incluindo o commit conexao_QUERY: TSQLconnection; // conexo com o banco de dados comando: Ansistring):boolean; var local_query: TSQLQuery; begin result:=true; local_query := TSQLquery.Create(nil); local_query.SQLConnection := conexao_QUERY; try local_query.Close; Pag. 137/176

local_query.SQL.Clear; local_query.SQL.Add(comando); local_query.ExecSQL(true); local_query.Close; local_query.SQL.Clear; local_query.SQL.Add('COMMIT WORK;'); local_query.ExecSQL(true); local_query.Close; except on e: exception do begin result:=false; showmessage(e.message); end; end; FreeAndNil(local_query); end; Coloque um boto e um edit no formulrio, com o comando: if F_comando(Cconnection,Edit1.text) then showmessage('tabela AQCEP criada com sucesso') else showmessage('erro no comando:''+Edit1.text);

Digite no edit o comando a seguir, clicando em seguida no boto: 'CREATE TABLE AQCEP (CEP VARCHAR(9) NOT VARCHAR(2)' Vamos exemplificar, usando outros parametros. Suponha que na tabela criada pelo comando: Edit1.text:='CREATE TABLE AGENDA (TELEFONE VARCHAR(15), NOME VARCHAR(50), NASC DATE);' Vamos gravar Efone.text como telefone, Enome.text como nome e Enasc.text como nascimento, o comando fica, supondo que Enasc.text j esteja no formando mes/dia/ano: Edit1.text:= 'INSERT INTO AGENDA (TELEFONE,NOME,NASC) values ('+ CHR(39)+'Efone.text'+CHR(39)+','+ CHR(39)+Enome.text'+CHR(39)+','+ CHR(39)+'Enasc.text'+CHR(39)+');' A funo CHR(39) retorna ' , pois os campos STRING precisam estar entre ' '. NULL, LOG VARCHAR(50), EST

5- Criando um componente em tempo de execuo


Pag. 138/176

Este recurso pouco utilizado pois, para o programador sem muita experincia, os componentes criados desta forma no podem ser visualizados durante o processo de edio, dificultando a organizao do LAYOUT de telas. Apenas para efeito de exemplo, vamos apresentar como criar um boto em tempo de execuo. Vamos criar um novo boto sempre que o usurio clicar sobre o formulrio. Vamos incluir tambm um segundo boto para mostrar que possvel criar um boto em tempo de execuo que possua um evento diferente dos j existentes. Inicialmente crie o formulrio abaixo:

Acerte sua UNIT conforme a seguir: unit principal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormActivate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure cliquebotao(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; botao:TButton; n_conta:integer; implementation Pag. 139/176

uses segunda; {$R *.dfm} procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button=mbRight then begin n_conta:=n_conta+1; botao:=TButton.create(Self); // cria o boto botao.Parent:=self; // passa para o boto, como herana, todas propriedades padres botao.Top:=Y; botao.Left:=X; botao.caption:=inttostr(n_conta); botao.Name:='BT'+botao.caption; botao.OnClick:=cliquebotao; // define o evento ONCLICK end; end; procedure TForm1.FormActivate(Sender: TObject); begin n_conta:=0; end; procedure TForm1.Button1Click(Sender: TObject); begin f_segunda.showmodal; end; procedure TForm1.cliquebotao(Sender: TObject); // evento ligado ao boto criado begin showmessage('voce clicou no botao criado'); end; end.

6- Rotinas teis
Pag. 140/176

IMPORTANTE: FUNES POSTERIORES PODEM NECESSITAR FUNES ANTERIORES Deixa no string somente os caracteres informados function Tcvs.F_deixacaracter(variavel: string; deixa: string): string; var i: integer; begin result := ''; for i := 1 to length(variavel) do if Ansipos(copy(variavel, i, 1), deixa) > 0 then result := result + copy(variavel, i, 1); end; Transforma caracter em inteiro, sem dar erro de exceo, podendo considerar letra como representao de numero sequecial. function Tcvs.F_cartoint(variavel: string; variavel_numero_letra: boolean = true // se true, considera que a variavel um numero, // se false, a variavel de um digito s. se for A,B,C .. ser convertida para 10,11,12.. etc. ): integer; // converte caracter para inteiro, ignorando caracteres invlidos var sinal: integer; begin // se converso de inteiro, PRECISA tirar tudo depois da virgula. if Ansipos(',', variavel) > 0 then variavel := copy(variavel, 1, Ansipos(',', variavel) - 1); if ansipos('-', variavel) > 0 then sinal := -1 else sinal := 1; result := 0; if variavel_numero_letra then begin variavel := CVS.F_deixacaracter(variavel, '0123456789'); if length(variavel) > 0 then result := strtoint(variavel); result := result * sinal; end else begin variavel := copy(variavel, 1, 1); if Ansipos(variavel, '0123456789') > 0 then result := strtoint(variavel) else result := CVS.F_asc(variavel, 65) - 65 + 10; end; // showmessage(inttostr(result)); end; Transforma um string em um numero real, sem erro de exceo Pag. 141/176

function Tcvs.F_strtoreal(variavel: string): real; var sinal: real; begin // showmessage('variavel i:'+variavel); if ansipos('-', variavel) > 0 then sinal := -1 else sinal := 1; variavel := CVS.F_deixacaracter(variavel, '0123456789,'); try Result := strtofloat(variavel); except on E: exception do // com log begin if length(VG_arqlog) > 0 then TXT.P_Log(VG_arqlog, 'Tcvs.F_strtoreal:' + E.Message, true, '', true, true, '_erro_'); Result := 0; end; end; result := result * sinal; // showmessage('variavel f:'+floattostr(result)); end;

Muda o formato da data:

Pag. 142/176

function Tdet.F_muda_formato_data( variavel: string; // variavel de acordo com o formato informato nada_mes_tudo: integer; // para faz_desfaz = true a variavel de entrada ser:
// 0 para ddmmaaaa ou dd/mm/aaaa, 1 para mmddaaaa ou mm/dd/aaaa ou 2 para aaaammdd ou aaaa/mm/dd // para faz_desfaz = false a variavel de entrada sempre ser dd/mm/aaaa

faz_desfaz: boolean = true; // default fazer barra: string = '/' // a barra divisria, se no for informada, sempre poe, se informar, pe o informado ): string; // se faz=true, retorna em formato dd/mm/aaaa ; // se faz=false, retorna ddmmaaaa ou dd/mm/aaaa para nada_mes_tudo = 0;
// mmddaaaa ou mm/dd/aaaa para nada_mes_tudo = 1 ou aaaammdd ou aaaa/mm/dd para nada_mes_tudo = 2

var c_dia, c_mes, c_ano: string; begin variavel := CVS.F_deixacaracter(variavel, '0123456789'); // pode no ter colocado barra nenhuma if faz_desfaz then begin case nada_mes_tudo of 0: begin c_dia := copy(variavel, 1, 2); c_mes := copy(variavel, 3, 2); c_ano := copy(variavel, 5, 4); end; 1: begin c_mes := copy(variavel, 1, 2); c_dia := copy(variavel, 3, 2); c_ano := copy(variavel, 5, 4); end; 2: begin c_ano := copy(variavel, 1, 4); c_mes := copy(variavel, 5, 2); c_dia := copy(variavel, 7, 2); end; end; result := c_dia + barra + c_mes + barra + c_ano; end else begin c_dia := copy(variavel, 1, 2); c_mes := copy(variavel, 3, 2); c_ano := copy(variavel, 5, 4); case nada_mes_tudo of 0: result := c_dia + barra + c_mes + barra + c_ano; 1: result := c_mes + barra + c_dia + barra + c_ano; 2: result := c_ano + barra + c_mes + barra + c_dia; end; end; end; Verificao de CPF: Pag. 143/176

function Tcvs.F_testacpf(cpf: string): boolean; var n1, n2, n3, n4, n5, n6, n7, n8, n9: integer; d1, d2: integer; digitado, calculado: string; begin // Joo Carlos - 27/01/2005 - v1.75 - inicio da documentao das alteraes das funes cpf := trim(cpf); if cpf = '00000000000' then cpf := ''; if length(cpf) = 11 then begin n1 := CVS.F_cartoint(cpf[1]); n2 := CVS.F_cartoint(cpf[2]); n3 := CVS.F_cartoint(cpf[3]); n4 := CVS.F_cartoint(cpf[4]); n5 := CVS.F_cartoint(cpf[5]); n6 := CVS.F_cartoint(cpf[6]); n7 := CVS.F_cartoint(cpf[7]); n8 := CVS.F_cartoint(cpf[8]); n9 := CVS.F_cartoint(cpf[9]); d1 := n9 * 2 + n8 * 3 + n7 * 4 + n6 * 5 + n5 * 6 + n4 * 7 + n3 * 8 + n2 * 9 + n1 * 10; d1 := 11 - (d1 mod 11); if d1 >= 10 then d1 := 0; d2 := d1 * 2 + n9 * 3 + n8 * 4 + n7 * 5 + n6 * 6 + n5 * 7 + n4 * 8 + n3 * 9 + n2 * 10 + n1 * 11; d2 := 11 - (d2 mod 11); if d2 >= 10 then d2 := 0; calculado := inttostr(d1) + inttostr(d2); digitado := cpf[10] + cpf[11]; if calculado = digitado then result := true else result := false; end else result := false; end;

Verificao de CNPJ:

Pag. 144/176

function Tcvs.F_testacnpj(cnpj: string): Boolean; var d1, d4, X, nCount, fator, resto, digito1, digito2: Integer; Check: string; begin // Joo Carlos - 27/01/2005 - v1.75 - inicio da documentao das alteraes das funes cnpj := trim(cnpj); if cnpj = '00000000000000' then cnpj := ''; if length(cnpj) = 14 then begin d1 := 0; d4 := 0; X := 1; for nCount := 1 to Length(cnpj) - 2 do begin if X < 5 then fator := 6 - X else fator := 14 - X; d1 := d1 + CVS.F_cartoint(Copy(cnpj, nCount, 1)) * fator; if X < 6 then fator := 7 - X else fator := 15 - X; d4 := d4 + CVS.F_cartoint(Copy(cnpj, nCount, 1)) * fator; X := X + 1; end; resto := (d1 mod 11); if resto < 2 then digito1 := 0 else digito1 := 11 - resto; d4 := d4 + 2 * digito1; resto := (d4 mod 11); if resto < 2 then digito2 := 0 else digito2 := 11 - resto; Check := IntToStr(Digito1) + IntToStr(Digito2); if Check <> copy(cnpj, succ(length(cnpj) - 2), 2) then Result := False else Result := True; end else result := false; end; Maior valor de uma lista de valores em um ListBox function TForm1.f_maior_valor(lista: TlistBox): real; var i: integer; begin result := strtofloat('0' + lista.Items[0]); for i := 0 to lista.Items.Count - 1 do if strtofloat(lista.Items[i]) > result then result := strtofloat('0' + lista.Items[i]); end; Produto total de uma lista de valores em um ListBox

Pag. 145/176

function TForm1.f_produto_total(lista: TlistBox): real; var i: integer; begin result := 1; for i := 0 to lista.Items.Count - 1 do result := result * strtofloat('0' + lista.Items[i]); end; Calculo do MDC (Maior divisor comum), a partir de um lista valores em um list box function TForm1.F_MDC(lista: TlistBox): real; var i: integer; j: real; resultado: string; maior_valor: real; begin maior_valor:= f_maior_valor(lista); j := 1; while j <= maior_valor do begin resultado := ''; for i := 0 to lista.Items.Count - 1 do if int(strtofloat('0' + lista.Items[i]) / j) = (strtofloat('0' + lista.Items[i]) / j) then resultado := resultado + 'x'; if length(resultado) = lista.Items.Count then result := j; j := j + 1; end; end;

Calculo do MMC (Menor multiplo comum), a partir de um lista valores em um list box Pag. 146/176

function TForm1.F_MMC(maior_valor: real; produto_total: real; lista: TlistBox): real; var i: integer; j: real; resultado: string; maior_valor,produto_total: real; begin maior_valor:= f_maior_valor(lista); produto_total:=f_produto_total(lista); j := 1; while j <= produto_total do begin resultado := ''; result := maior_valor * j; for i := 0 to lista.Items.Count - 1 do if int(result / strtofloat('0' + lista.Items[i])) = (result / strtofloat('0' + lista.Items[i])) then resultado := resultado + 'x'; if length(resultado) = lista.Items.Count then j := Vmmax; j := j + 1; end; end;

Trata a data para formato e valor vlido Pag. 147/176

function Tdet.F_tratadata( variavel: string; // variavel string em formato de data a ser tratada avisa: boolean; // avisa se der erro na converso retorna_fornecida: boolean; // se true, retorna o que foi fornecido em data_fornecida, se falso, retorna 01/01/2000 data_fornecida: string = 'atual'; // pode ser usado tambm para identificar que houve erro, usando data fornecida ='?' formulario: Tform = nil): string; // retorna o string da data tratada var dia, mes, ano: integer; c_dia, c_mes, c_ano: string; data_uso: string; begin try data_uso := datetostr(strtodate(data_fornecida)); except data_uso := datetostr(date); end; result := ''; // se tem barra e so tem um digito para o dia if Ansipos('/', variavel) > 0 then begin if copy(variavel, 2, 1) = '/' then variavel := '0' + variavel; if copy(variavel, 5, 1) = '/' then variavel := copy(variavel, 1, 3) + '0' + copy(variavel, 4, 6); end; variavel := CVS.F_deixacaracter(variavel, '0123456789'); // pode no ter colocado barra nenhuma ou ter s barra if length(trim(variavel)) = 0 then begin if retorna_fornecida then result := data_fornecida else result := '01/01/2000'; end else begin // zero na frente para no dar erro dia := strtoint('0' + copy(variavel, 1, 2)); if dia = 0 then if retorna_fornecida then dia := DayOf(strtodate(data_uso)) else dia := 1; c_dia := inttostr(dia); if dia < 10 then c_dia := '0' + c_dia; Pag. 148/176

mes := strtoint('0' + copy(variavel, 3, 2)); if mes = 0 then if retorna_fornecida then mes := MonthOf(strtodate(data_uso)) else mes := 1; c_mes := inttostr(mes); if mes < 10 then c_mes := '0' + c_mes; ano := strtoint('0' + copy(variavel, 5, 4)); if ano = 0 then if retorna_fornecida then ano := YearOf(strtodate(data_uso)) else ano := 2000; c_ano := inttostr(ano); if ano < 10 then c_ano := '200' + c_ano else if ano < 100 then c_ano := '20' + c_ano else if ano < 1000 then c_ano := '2' + c_ano; variavel := c_dia + '/' + c_mes + '/' + c_ano; try result := datetostr(strtodate(variavel)); except on E: exception do // com log begin if retorna_fornecida then result := data_fornecida else result := '01/01/2000'; if avisa then showmessage('Data invlida.'+#10+ 'Use os formatos dd/, dd/mm, dd/mm/aaaa, dd, ddmm, ddmmaaaa,'+#10+ 'd/, d/m, d/m/aa, ou deixe em branco.'); end; end; end; end;

Conta quantos strings existem dentro de um string, separador por um separador

Pag. 149/176

function Tstm.F_contanumero(variavel: Ansistring; separador: string = '|'): integer; var pegaPartPals: Ansistring; contanumpal: integer; begin // se ele est fazio, conta como zero, se tem pelo menos o separador, conta como 1 contanumpal := 0; if length(variavel) > 0 then begin // separador tem que existir if length(separador) = 0 then separador := '|' else if length(separador) > 1 then separador := copy(separador, 1, 1); // tem que terminar com separador if not (copy(variavel, length(variavel), 1) = separador) then variavel := variavel + separador; pegaPartPals := variavel; contanumpal := 0; while length(pegaPartPals) > 0 do begin contanumpal := contanumpal + 1; if Ansipos(separador, pegaPartPals) + 1 > length(pegaPartPals) then pegaPartPals := '' else begin pegaPartPals := copy(pegaPartPals, Ansipos(separador, pegaPartPals) + 1, length(pegaPartPals)); end; end; end; Result := contanumpal; // showmessage(inttostr(result)); end;

pega um string dentro de um string, separados por um separador

Pag. 150/176

function Tstm.F_pegastring(variavel: Ansistring; posicao: integer; separador: string '|';retorno_nao_encontrou:string=''): string; var numordem: integer; achou: string; begin // pe separador no final, se no existir if length(separador) = 0 then separador := '|'; if not (copy(variavel, length(variavel), 1) = separador) then variavel := variavel + separador; numordem := 0; achou := 'N'; // variavel:=Trim(variavel); Result := retorno_nao_encontrou; while achou = 'N' do begin Result := copy(variavel, 1, Ansipos(separador, variavel) - 1); numordem := numordem + 1; if numordem = posicao then achou := 'S' else variavel := copy(variavel, Ansipos(separador, variavel) + 1, length(variavel)); if length(variavel) = 0 then begin Result := ''; numordem := 0; achou := 'S'; end; end; end;

Substitui um string, dentro de um string com strings separados por um separador Pag. 151/176

function Tstm.F_subststring( variavel: Ansistring; // variavel a ser alterada posicao: integer; // posicao a substituir separador: string; // separador utilizado substpor: string; // o que ser colocado na posio com_separador: boolean = true // se para por separador, se false e substpor ='' equivale a excluir a posio selecionada ): string; // variavel modificada var i: integer; begin if length(separador) = 0 then separador := '|'; if not (copy(variavel, length(variavel), 1) = separador) then variavel := variavel + separador; result := ''; for i := 1 to F_contanumero(variavel, separador) do if i = posicao then begin if com_separador then result := result + substpor + separador else result := result + substpor; end else result := result + F_pegastring(variavel, i, separador) + separador; end;

Acha a posio de um string, dentro de um string com strings separador por um separador

Pag. 152/176

function Tstm.F_achanumero(dostring: string; nostring: Ansistring; separador: string = '|'): integer; var pegaPartPals: Ansistring; achanumpal: integer; begin // PRO.F_opcao('estou no acha numero','','','OK','',nil,false); // Joo Carlos - 27/01/2005 - v1.75 - inicio da documentao das alteraes das funes // Joo Carlos - 07/01/2005 - v1.91 - proteo, se o separador no for definido, usa PIPE como default if length(separador) = 0 then separador := '|'; if not (copy(nostring, length(nostring), 1) = separador) then nostring := nostring + separador; pegaPartPals := nostring; dostring := dostring; achanumpal := 0; result := 0; // se no achou, retorna zero if (length(dostring) > 0) and (length(nostring) > 0) then begin if (Ansipos(dostring + separador, nostring) > 0) then begin while length(pegaPartPals) > 0 do begin // PRO.F_opcao('pegapartpals+' '+inttostr(ansipos(x,y))); achanumpal := achanumpal + 1; if (Ansipos(dostring + separador, pegapartpals) = 1) and (dostring + separador = copy(pegaPartPals, 1, length(dostring + separador))) then begin result := achanumpal; pegaPartPals := ''; end; if length(pegaPartPals) > Ansipos(separador, pegaPartPals) then pegaPartPals := copy(pegaPartPals, Ansipos(separador, pegaPartPals) + 1, length(pegaPartPals)) else pegaPartPals := ''; end; end; end; end; Deixa um string no formato indicado, com arredondamento ou no

Pag. 153/176

function Tcvs.F_formata_arredonda(variavel: string; tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora: string; // coloquei um formato padro para, se for data, no ter que passar nada, // se for caracter , como 9 no siginifica nada, dever ser fornecido xxx.xxx.xxx,xx converto para tudo x // vai retornar normal. // agora tem o parametro padro: veja no comeo da funo // p - preo, q - quantidade, t - total, retirados dos formatos e arredondamentos // possivel fornecer um detalhe da formatao, usando o ; o detalhe s tem funo se o tipo for Z ou z, que formatao em extenso, separando em mais de uma linha // no caso de Z ou z, pode fornecer Z;numero_de_linhas_a_pular;espaos_no_inicio_de_cada_nova_linha; se no considera 1;0; // 1.95.20.n // fornea f para, quando o valor numrico for megativo, retorna o formado cheio de * formato_padrao: string = 'padro'; // formato a ser utilizado {D Para data, converte para o formato padro, para converso de dado parcial, use a fun~~ao DET.F_tratadata C Para caracter use: xxxxxxx imprime do jeito que est, serve apenas para cortar o string. YYYYY converte para maiuscula e trunca yyyyy converte para minscula e trunca Yx:xx-x - acrescenta todos caracteres que no forem x, Y ou y Ex.: a1231 fica A1:23-1 F,p,q,v - sendo que p,q,v pega dos formatos padro depois se comporta sempre como F PQV, sem espacos, pqv, com espaos 9 preenche com espaos os digitos que no completar 0 preenche com zeros o que faltar # preenche com cerquilha o que faltar x no preenche com nada - usado em edio use . para milhar e , para decimal NO MISTURE FORMATOS, nem use outros simbolos N - igual ao F, s que tira tudo depois da , do numero n - converte direto pra inteiro, ignora formatao // // PARA OS TIPOS A SEGUIR, CHAMA A FUNO CVS.F_extenso // Neste caso, o tipo pode ter mais de um digito X Faz extenso do valor Y Faz extenso do valor em maiusculo (aceita usar junto com outros) Pag. 154/176

y Faz extenso do valor em minusculo (aceita usar junto com outros) m DATA: Faz s mes em extenso d DATA: faz dia e mes em extenso da data a DATA: faz ano e mes em extenso t DATA: faz tudo em extenso } arredondamento: string = '0'; // arredondamento formatos_e_arredondamentos: string = ''; // campo contendo os formatos e arredondamentos configurados no sistema, separados pelo separador, normalmente ; // os parametros a seguir s servem para formatao numrica tira_ponto: boolean = false; tira_virgula: boolean = false; avisa: boolean = true; completa: boolean = false; // se completa o formato at o tamanho do string moeda: string = 'real'; moedas: string = 'reais'; centavo: string = 'centavo'; centavos: string = 'centavos' ): string; // retorna a variavel formatada var i, digitos, decimais: integer; detalhe_tipo: string; digitos_resultado, decimais_resultado: integer; v_arredondamento: real; resultado_modificado, parte_inteira, sinal, formato_modificado: string; // durante a funo muda o formato, mas preciso do original no final erro_over_flow: boolean; formato_inteiro, preenche_inteiro_com, formato_decimal, preenche_decimal_com, v_antes: string; begin if Ansipos(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 'fFNnPQVpqv') > 0 then if length(variavel) < 1 then variavel := '0'; // se for formato n, faz direto e j sai if (tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'n') then begin Pag. 155/176

try result := inttostr(CVS.F_ftoi(CVS.F_strtoreal(variavel))); except result := floattostr(strtofloat(variavel)); end; exit; end; // if formato_padrao = 'padro' then begin case Ansipos(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 'CFfNDPQVpqv') of 1: formato_padrao := CVS.F_repete('x', length(variavel)); 2: formato_padrao := '9.' + CVS.F_repete('999.', (length(variavel) div 4)) + '999,99'; 3: formato_padrao := '9.' + CVS.F_repete('999.', (length(variavel) div 4)) + '999,99'; 4: formato_padrao := CVS.F_repete('9', length(variavel)); 5: formato_padrao := 'padro'; 6: begin formato_padrao := STM.F_pegastring(formatos_e_arredondamentos, 1, ';'); arredondamento := STM.F_pegastring(formatos_e_arredondamentos, 4, ';'); end; 7: begin formato_padrao := STM.F_pegastring(formatos_e_arredondamentos, 2, ';'); arredondamento := STM.F_pegastring(formatos_e_arredondamentos, 5, ';'); end; 8: begin formato_padrao := STM.F_pegastring(formatos_e_arredondamentos, 3, ';'); arredondamento := STM.F_pegastring(formatos_e_arredondamentos, 6, ';'); end; 9: begin arredondamento := STM.F_pegastring(formatos_e_arredondamentos, 4, ';'); formato_padrao := STM.F_pegastring(formatos_e_arredondamentos, 7, ';'); end; 10: begin arredondamento := STM.F_pegastring(formatos_e_arredondamentos, 5, ';'); formato_padrao := STM.F_pegastring(formatos_e_arredondamentos, 8, ';'); end; Pag. 156/176

11: begin arredondamento := STM.F_pegastring(formatos_e_arredondamentos, 6, ';'); formato_padrao := STM.F_pegastring(formatos_e_arredondamentos, 9, ';'); end; else formato_padrao := CVS.F_repete('x', length(variavel)) end; end else if completa then if length(variavel) > length(formato_padrao) then if Ansipos(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 'fFPQVpqv') > 0 then formato_padrao := '9.' + CVS.F_repete('999.', ((length(variavel) - length(formato_padrao)) div 4)) + formato_padrao else formato_padrao := CVS.F_repete('x', length(variavel) - length(formato_padrao)) + formato_padrao; // showmessage(formato_padrao); // showmessage(arredondamento); if Ansipos(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 'PQVpqv') > 0 then tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora := 'F'; if tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'f' then begin tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora := 'F'; if CVS.F_strtoreal(variavel) < 0 then begin result := CVS.F_repete('*', length(formato_padrao)); exit; end; end; result := ''; v_antes := variavel; erro_over_flow := false; // showmessage('entrei'); // formatao tipo N igual a F, s tira a parte fracionria (depois da virgula) if (tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'N') then if AnsiPos(',', variavel) > 0 then variavel := copy(variavel, 1, AnsiPos(',', variavel) - 1); // showmessage(formatos_e_aredondamentos); //showmessage('estava:' + variavel); Pag. 157/176

if (tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'F') or (tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'N') then begin sinal := ''; if AnsiPos('-', variavel) > 0 then begin sinal := '-'; variavel := CVS.F_tiracaracter(variavel, '-'); end; // showmessage(formato_padrao); // showmessage(arredondamento); // formato sem ponto, fora tirar o ponto if ansipos('.', formato_padrao) = 0 then tira_ponto := true; // para calcular os digitos, ignora o ponto formato_modificado := CVS.F_deixacaracter(formato_padrao, 'x#09,'); // showmessage(formato_modificado); variavel := CVS.F_deixacaracter(variavel, '0123456789,'); if ansipos(',', formato_modificado) = 0 then begin digitos := length(formato_modificado); decimais := 0; // formato no tem virgula, fora tirar a virgula tira_virgula := true; // vai rerificar se tem que completar inteiros preenche_inteiro_com := ''; if Ansipos('x', formato_padrao) = 0 then // no x, vai completar com algo if Ansipos('0', formato_padrao) > 0 then preenche_inteiro_com := '0' else if Ansipos('#', formato_padrao) > 0 then preenche_inteiro_com := '#' else preenche_inteiro_com := ' '; preenche_decimal_com := ''; end else begin digitos := length(copy(formato_modificado, 1, Ansipos(',', formato_modificado) - 1)); decimais := length(formato_modificado) - digitos - 1; // vai rerificar se tem que completar inteiros formato_inteiro := copy(formato_padrao, 1, Ansipos(',', formato_padrao) - 1); preenche_inteiro_com := ''; if Ansipos('x', formato_inteiro) = 0 then // no x, vai completar com algo Pag. 158/176

if Ansipos('0', formato_inteiro) > 0 then preenche_inteiro_com := '0' else if Ansipos('#', formato_inteiro) > 0 then preenche_inteiro_com := '#' else preenche_inteiro_com := ' '; // vai rerificar se tem que completar decimais formato_decimal := copy(formato_padrao, Ansipos(',', formato_padrao) + 1, length(formato_padrao)); preenche_decimal_com := ''; if Ansipos('x', formato_decimal) = 0 then // no x, vai completar com algo if Ansipos('0', formato_decimal) > 0 then preenche_decimal_com := '0' else if Ansipos('#', formato_decimal) > 0 then preenche_decimal_com := '#' else preenche_decimal_com := ' '; end; // // verifica se o valor digitado estoura o formato, se sim, vai truncar para no retornar em notao exponencial. // // showmessage(inttostr(digitos)); if ansipos(',', variavel) = 0 then begin if length(variavel) > digitos then begin variavel := copy(variavel, 1 + length(variavel) - digitos, length(variavel)); erro_over_flow := true; end; end else begin parte_inteira := copy(variavel, 1, ansipos(',', variavel) - 1); if length(parte_inteira) > digitos then begin parte_inteira := copy(parte_inteira, 1 + length(parte_inteira) - digitos, length(parte_inteira)); variavel := parte_inteira + copy(variavel, ansipos(',', variavel), length(variavel)); erro_over_flow := true; end; end; // // esta funo j arredonda, se tem decimais, // tiro a arredondamento se pede para arredondar Pag. 159/176

// isto serve para truncar. // showmessage(inttostr(decimais)); V_arredondamento := 0; if (decimais > 0) and (not (CVS.F_strtoreal(variavel) = 0)) then v_arredondamento := CVS.F_strtoreal(arredondamento); if Abs(CVS.F_strtoreal(variavel)) < V_arredondamento then result := '0' else begin result := floattostrf(CVS.F_strtoreal(variavel) + v_arredondamento, FFnumber, 18, 7); // showmessage('RESULTADO INT:'+result); if decimais > 0 then result := copy(result, 1, Ansipos(',', result)) + copy(result, Ansipos(',', result) + 1, decimais) else result := copy(result, 1, Ansipos(',', result) - 1); end; // showmessage('RESULTADO pos:'+result); // showmessage('s/d:'+result); // vai completar, se tiver que completar // para isso precisa calcular quantos digitos ficaram // se era negativo, tira sinal, pois vai colocar de novo. if AnsiPos('-', result) > 0 then result := CVS.F_tiracaracter(result, '-'); resultado_modificado := CVS.F_tiracaracter(result, '.'); if ansipos(',', resultado_modificado) = 0 then begin digitos_resultado := length(resultado_modificado); decimais_resultado := 0; end else begin digitos_resultado := length(copy(resultado_modificado, 1, Ansipos(',', resultado_modificado) 1)); decimais_resultado := length(resultado_modificado) - digitos_resultado - 1; end; // // showmessage('d.r.:'+inttostr(digitos_resultado)); Pag. 160/176

// se tem que preencher inteiro if length(preenche_inteiro_com) > 0 then // preenchendo a esquerda (inteiros), se for preciso result := CVS.F_repete(preenche_inteiro_com, digitos - digitos_resultado) + result; // preenchendo a direita (fracionrios), se for preciso // showmessage(result); // se tem que preencher decimal if length(preenche_decimal_com) > 0 then begin if (Ansipos(',', result) = 0) and ((decimais - decimais_resultado) > 0) then result := result + ','; result := result + CVS.F_repete(preenche_decimal_com, decimais - decimais_resultado); end; // tira ponto e virgula se necessrio if tira_ponto then result := CVS.F_tiracaracter(result, '.'); if tira_virgula then result := CVS.F_tiracaracter(result, ','); if length(result) > length(formato_padrao) then begin if avisa then PRO.F_opcao('Resultado formatado:' + result + '(' + inttostr(length(result)) + ')', 'maior que o formato:' + formato_padrao + '(' + inttostr(length(formato_padrao)) + ')', 'Acerte a configurao de Formatos Numricos'); result := copy(result, length(result) - length(formato_padrao) + 1, length(result)); if length(VG_arqlog) > 0 then TXT.P_Log(VG_arqlog, 'F_tratagravaSQL-2:Resultado formatado maior que o formato', true, '', true, true, '_erro_'); end; if erro_over_flow then begin if avisa then PRO.F_opcao('OVERFLOW', 'varivel informada maior que o formato', 'antes:' + v_antes + ', Modificada:' + variavel + ', depois:' + result + ', formato:' + formato_padrao); result := '!' + result; if length(VG_arqlog) > 0 then TXT.P_Log(VG_arqlog, 'F_tratagravaSQL-2:varivel informado maior que formato', true, '', true, true, '_erro_'); end; result := sinal + result; end Pag. 161/176

else begin if (tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'C') then begin // formatao do tipo caracter // faz pelo formato, a partir do primeiro // despresa se a variavel tiver a mais. // arredondamento no serve para nada. for i := 1 to length(formato_padrao) do begin if copy(formato_padrao, i, 1) = 'y' then begin result := result + lowercase(copy(variavel, 1, 1)); variavel := copy(variavel, 2, length(variavel)); end else begin if copy(formato_padrao, i, 1) = 'Y' then begin result := result + uppercase(copy(variavel, 1, 1)); variavel := copy(variavel, 2, length(variavel)); end else begin if copy(formato_padrao, i, 1) = 'x' then begin result := result + copy(variavel, 1, 1); variavel := copy(variavel, 2, length(variavel)); end else result := result + copy(formato_padrao, i, 1); end; end; end; end else begin // formatao tipo data, se no for formato padro, despresa o formato, faz converso direta if (tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora = 'D') then begin if formato_padrao = 'padro' then result := DET.F_tratadata(variavel, false, true) Pag. 162/176

else begin try result := datetostr(strtodate(variavel)); except // sem log // PRO.F_opcao(''data invalida'); result := ' / / '; end; end; end else // extenso outro tipo ignora. begin // se tiver ; porque tem detalhe detalhe_tipo := ''; if Ansipos(';', tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora) > 0 then begin detalhe_tipo := copy(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, Ansipos(';', tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora), length(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora)); tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora := copy(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 1, 1); end else if Ansipos(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 'Zz') > 0 then detalhe_tipo := ';1;0;'; if Ansipos(tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora, 'ZzXYymdat') > 0 then result := CVS.F_extenso(variavel, moeda, moedas, centavo, centavos, tipo_CFfNnDPQVpqvZzXYymdat_outro_ignora + detalhe_tipo) else result := variavel; end; end; end; // showmessage(result); end; Calculo do extenso de um numero ou data function Tcvs.F_extenso( Pag. 163/176

variavel: string; // se tiver /, porque data moeda: string; // moeda usada no singula, se for data, ignora moedas: string; // moeda usada no plural, se for data, ignora centavo: string; // centavo usada no singula, se for data, ignora centavos: string; // centavo usada no plural, se for data, ignora tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma: string // X, extenso normal, // Z - separa em duas linhas, se der mais de 45 caracteres, sendo que acha o primeiro espao depois da 45a. posio // use Z para sem compresso e z para com compresso (Z = 45, z = 68) // no caso de Z ou z, pode fornecer Z;numero_de_linhas_a_pular;espaos_no_inicio_de_cada_nova_linha; se no considera 1;0; // d - se for data, faz dia em extenso tambm, // a - se for data, faz ano em extenso tambm // para tipo data, o mes sempre em extenso // t - data, faz dia e ano em extenso // Y para tudo maisculo, y para minusculo. o Y ou y podem ser usados junto com outros, ex.: dY = data, dia e mes extenso, maiisculo ): string; var aux_result, unidades, dezenas, centenas: string; detalhe_tipo: string; dia, mes, ano, c, d, u, i: integer; begin // verifica se data detalhe_tipo := ''; if Ansipos(';', tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma) > 0 then begin detalhe_tipo := copy(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, Ansipos(';', tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma) + 1, length(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma)); tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma := copy(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 1, 1); end else if Ansipos(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'Zz') > 0 then detalhe_tipo := '1;0;'; if length(CVS.F_deixacaracter(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'mdat')) > 0 then begin variavel := DET.F_tratadata(variavel, false, true); dia := DayOf(strtodate(variavel)); Pag. 164/176

mes := MonthOf(strtodate(variavel)); ano := YearOf(strtodate(variavel)); // se faz extenso do dia if length(CVS.F_deixacaracter(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'dt')) > 0 then result := CVS.F_extenso(inttostr(dia), '', '', '', '', 'X') else result := inttostr(dia); result := result + ' de '; case mes of 1: result := result + 'janeiro'; 2: result := result + 'fevereiro'; 3: result := result + 'maro'; 4: result := result + 'abril'; 5: result := result + 'maio'; 6: result := result + 'junho'; 7: result := result + 'julho'; 8: result := result + 'agosto'; 9: result := result + 'setembro'; 10: result := result + 'outubro'; 11: result := result + 'novembro'; 12: result := result + 'dezembro'; end; result := result + ' de '; if length(CVS.F_deixacaracter(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'at')) > 0 then result := result + CVS.F_extenso(inttostr(ano), '', '', '', '', 'X') else result := result + inttostr(ano); end else begin variavel := CVS.F_formata_arredonda(variavel, 'F', '000000000000,00'); unidades := 'um|dois|trs|quatro|cinco|seis|sete|oito|nove|dez|onze|doze|treze|catorze|quinze| dezesseis|dezessete|dezoito|dezenove|'; dezenas := 'dez|vinte|trinta|quarenta|cinquenta|sessenta|setenta|oitenta|noventa|cem|'; centenas := 'cento|duzentos|trezentos|quatrocentos|quinhentos|seiscentos|setecentos| oitocentos|novecentos|'; // showmessage(variavel); // tem que ser fornecido no formato: 000000000000,00 result := ''; // faz o extenso da variavel e coloca o resultado na result c := CVS.F_cartoint(copy(variavel, 1, 1)); Pag. 165/176

d := CVS.F_cartoint(copy(variavel, 2, 1)); u := CVS.F_cartoint(copy(variavel, 3, 1)); if c > 1 then begin result := result + STM.F_pegastring(centenas, c, '|'); if d + u > 0 then result := result + ' e '; end else if c = 1 then if d + u > 0 then result := result + ' cento e ' else result := result + ' cem '; if d > 1 then begin result := result + STM.F_pegastring(dezenas, d, '|'); if u > 0 then result := result + ' e ' + STM.F_pegastring(unidades, u, '|'); end else begin u := CVS.F_cartoint(copy(variavel, 2, 2)); if u > 0 then result := result + STM.F_pegastring(unidades, u, '|'); end; if c * 100 + d * 10 + u > 1 then result := result + ' bilhes' else if u = 1 then result := result + ' bilho'; if (CVS.F_cartoint(copy(variavel, 1, 3)) > 0) and (CVS.F_cartoint(copy(variavel, 4, 9)) > 0) then result := result + ','; if (CVS.F_cartoint(copy(variavel, 1, 3)) > 0) and (CVS.F_cartoint(copy(variavel, 4, 9)) = 0) then result := result + ' de '; // c := CVS.F_cartoint(copy(variavel, 4, 1)); d := CVS.F_cartoint(copy(variavel, 5, 1)); u := CVS.F_cartoint(copy(variavel, 6, 1)); if c > 1 then begin result := result + STM.F_pegastring(centenas, c, '|'); if d + u > 0 then result := result + ' e '; end else if c = 1 then begin if d + u > 0 then result := result + ' cento e ' else result := result + ' cem '; Pag. 166/176

end else if d + u > 0 then if length(result) > 0 then result := result + ' e '; if d > 1 then begin result := result + STM.F_pegastring(dezenas, d, '|'); if u > 0 then result := result + ' e ' + STM.F_pegastring(unidades, u, '|'); end else begin u := CVS.F_cartoint(copy(variavel, 5, 2)); if u > 0 then result := result + STM.F_pegastring(unidades, u, '|'); end; if c * 100 + d * 10 + u > 1 then result := result + ' milhes' else if u = 1 then result := result + ' milho'; if (CVS.F_cartoint(copy(variavel, 4, 3)) > 0) and (CVS.F_cartoint(copy(variavel, 7, 6)) > 0) then result := result + ','; if (CVS.F_cartoint(copy(variavel, 4, 3)) > 0) and (CVS.F_cartoint(copy(variavel, 7, 6)) = 0) then result := result + ' de '; // c := CVS.F_cartoint(copy(variavel, 7, 1)); d := CVS.F_cartoint(copy(variavel, 8, 1)); u := CVS.F_cartoint(copy(variavel, 9, 1)); if c > 1 then begin result := result + STM.F_pegastring(centenas, c, '|'); if d + u > 0 then result := result + ' e '; end else if c = 1 then begin if d + u > 0 then result := result + ' cento e ' else result := result + ' cem '; end else if d + u > 0 then if length(result) > 0 then result := result + ' e '; if d > 1 then Pag. 167/176

begin result := result + STM.F_pegastring(dezenas, d, '|'); if u > 0 then result := result + ' e ' + STM.F_pegastring(unidades, u, '|'); end else begin u := CVS.F_cartoint(copy(variavel, 8, 2)); if u > 0 then result := result + STM.F_pegastring(unidades, u, '|'); end; if c * 100 + d * 10 + u > 0 then result := result + ' mil'; if (CVS.F_cartoint(copy(variavel, 7, 3)) > 0) and (CVS.F_cartoint(copy(variavel, 10, 3)) > 0) then result := result + ','; // c := CVS.F_cartoint(copy(variavel, 10, 1)); d := CVS.F_cartoint(copy(variavel, 11, 1)); u := CVS.F_cartoint(copy(variavel, 12, 1)); if c > 1 then begin result := result + STM.F_pegastring(centenas, c, '|'); if d + u > 0 then result := result + ' e '; end else if c = 1 then begin if d + u > 0 then result := result + ' cento e ' else result := result + ' cem '; end else if d + u > 0 then if length(result) > 0 then result := result + ' e '; if d > 1 then begin result := result + STM.F_pegastring(dezenas, d, '|'); if u > 0 then result := result + ' e ' + STM.F_pegastring(unidades, u, '|'); end else begin u := CVS.F_cartoint(copy(variavel, 11, 2)); if u > 0 then result := result + STM.F_pegastring(unidades, u, '|'); end; Pag. 168/176

if length(result) > 0 then if CVS.F_strtoreal(copy(variavel, 1, 12)) > 1 then result := result + ' ' + moedas else result := result + ' ' + moeda; if CVS.F_strtoreal(copy(variavel, 14, 2)) > 0 then result := result + ' e '; d := CVS.F_cartoint(copy(variavel, 14, 1)); u := CVS.F_cartoint(copy(variavel, 15, 1)); if d > 1 then begin result := result + STM.F_pegastring(dezenas, d, '|'); if u > 0 then result := result + ' e ' + STM.F_pegastring(unidades, u, '|'); end else begin u := CVS.F_cartoint(copy(variavel, 14, 2)); if u > 0 then result := result + STM.F_pegastring(unidades, u, '|'); end; if d + u > 0 then if d + u > 1 then result := result + ' ' + centavos else result := result + ' ' + centavo; end; // 1_95_4 - 7/6/6 - arrumrei para poder usar y com Z tb J.C. case Ansipos(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'Zz') of 1: begin aux_result := copy(result, 46, length(result)) + ' '; // para garantir que vai ter espao result := copy(result, 1, 45); end; 2: begin aux_result := copy(result, 74, length(result)) + ' '; // para garantir que vai ter espao result := copy(result, 1, 73); end; end; case Ansipos(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'Yy') of 1: result := UpperCase(result); 2: result := LowerCase(result); end; if Ansipos(tipo_Z_z_X_Y_y_m_d_a_t_mais_dot_coma, 'Zz') > 0 then begin result := result + copy(aux_result, 1, Ansipos(' ', aux_result) - 1); for i := 1 to CVS.F_cartoint(STM.F_pegastring(detalhe_tipo, 1, ';')) do Pag. 169/176

result := result + CHR(10) + CHR(13) + CVS.F_repete(' ', CVS.F_cartoint(STM.F_pegastring(detalhe_tipo, 2, ';'))); result := result + copy(aux_result, Ansipos(' ', aux_result) + 1, length(aux_result)); end; // showmessage(result); end;

7- Artificios de programao

Pag. 170/176

Neste tpco apresentaremos alguns artificios de programao, destinados a otimizar a programao e resolver alguns problemas. 7.1- Verificando qualquer coisa antes de eventos em componentes Para executar qualquer coisa antes de um evento de um componente, necessrio forcar a aplicao a executar ANTES do evento do componente, os eventos do formulrio. Para isso mude a propriedade KEYPREVIEW do formulrio e coloque a programao no ONKEYDOWN do formulario. 7.2- Travando a aplicao As vezes necessitamos parar o processamento em um pondo, at que o operador tome uma deciso. Veja o exemplo a seguir: em uma tela, com um boto Brelatorioparacompra, no seu evento on click, colocamos: procedure Tform_fornecimento.BrelatorioparacompraClick(Sender: Tobject); begin Ecodite.Text := ''; itens_escolhidos := ''; Pdetalhes.visible:=true; CBitens.Caption := 'Escolhe tens'; CBfabricantes.Caption := 'Escolhe fabricantes'; CBitens.Checked := false; CBfabricantes.Checked := false; CBfornecedores.Visible := true; CBdados.Visible := true; CBitens.SetFocus; while Pdetalhes.Visible do Application.ProcessMessages; if not (Ecodite.Text = 'cancelou') then begin Note que a aplicao tornara o painel Pdetalhes visivel, e s saira do while acima,pssando a execuar o que est rm vermelho, se o painel ficar invisivel. Considerando o painel Pdetalhes como sendo:

Coloque no boto cancela: Ecodite.Text := 'cancelou'; Pag. 171/176

Pdetalhes.visible := false; e no boto confirma: Pdetalhes.visible := false; Pronto. A Aplicao somente continuar se o operador clicar no boto cancela ou confirma. Caso seja no boto confirma, no entrar no IF indicado em vermelho na programao anterior. 7.3- Determinando o ponto flutuante do seu sistema operacional: Crie a funo: function Tform_principal.Fpt:char; begin if ansipos(',', floattostr(0.1))=0 then result:= '.' else result := ','; end; 7.4- Cancelando evento se o operador quiser sair Vamos supor que, em um determinado formulrio, estamos em um componente que possui processamento no seu evento ONExit e desejamos NO EXECUTAR este processo se o operador criacar no boto BBsaida. Veja como fica a programao: procedure Tform1.Edit1eExit(Sender: TObject); begin // se clicou no boto saida, fora sair. // SEMPRE DEVE SER O PRIMEIRO COMANDO if ActiveControl= BBsaida then exit; // ABNDONA O EVENTO with sender as Tedit do color := clBase; if V_status = 'incluir' then begin 7.5- Criptografando dados veja a funo exemplo: Pag. 172/176

function Tcvs.F_criptografa( senha: string; // string a criptografar/descriptografar faz_desfaz: boolean = true; // se criptografa gerador: integer = 0 // serve para mudar o processo de criptografia. se -1, usa o MD5 ): string; var i: integer; x: string; MD5Digest: TMD5Digest; a: integer; v_senha: string; begin // Joo Carlos - 27/01/2005 - v1.75 - inicio da documentao das alteraes das funes if length(senha) > 0 then // 04/12/2004 - por Helder Frederico: se a senha estiver vazio, retorna vazio begin if faz_desfaz then // MD5 - SEMPRE USE FAZ begin if gerador = -1 then begin StringHashMD5(MD5Digest, senha); v_senha := ''; for a := 0 to 15 do begin v_senha := v_senha + inttostr(MD5Digest[a]); end; result := v_senha; end else begin result := ''; // o gerador da senha a unidade do codigo decimal do ultimo caracter + 20 if gerador = 0 then begin x := inttostr(20 + CVS.F_asc(copy(senha, length(senha), 1), 65)); gerador := strtoint(copy(x, length(x), 1)); end; // PRO.F_opcao(''valor de j da criptografia:'+inttostr(j)); // preciso do untimo caracter intacto, pois a criptografia depende dele result := copy(senha, length(senha), 1); Pag. 173/176

for i := 1 to length(senha) - 1 do begin // caracteres reservados no criptografa, MUDA PARA CARACTER RESERVADO QEU NO PODE TER NA SENHA if CVS.F_contem(CHR(39), chr(CVS.F_asc(copy(senha, i, 1), 65) + (i * gerador) + length(senha))) then result := result + '*' else if CVS.F_contem('|', chr(CVS.F_asc(copy(senha, i, 1), 65) + (i * gerador) + length(senha))) then result := result + '+' else result := result + chr(CVS.F_asc(copy(senha, i, 1), 65) + (i * gerador) + length(senha)); end; end; end else begin if gerador = 0 then begin x := inttostr(20 + CVS.F_asc(copy(senha, 1, 1), 65)); gerador := strtoint(copy(x, length(x), 1)); end; // PRO.F_opcao(''valor de j da des-criptografia:'+inttostr(j)); result := ''; for i := 2 to length(senha) do begin if copy(senha, i, 1) = '*' then result := result + chr(CVS.F_asc(CHR(39), 65) - ((i - 1) * gerador) - length(senha)) else if copy(senha, i, 1) = '+' then result := result + chr(CVS.F_asc('|', 65) - ((i - 1) * gerador) - length(senha)) else result := result + chr(CVS.F_asc(copy(senha, i, 1), 65) - ((i - 1) * gerador) length(senha)); end; result := result + copy(senha, 1, 1); end; end else result := ''; // PRO.F_opcao(''resultado:'+result); Pag. 174/176

end; 7.6- Mudando a cor das linhas do DBGrid: use <cor> como sendo: $00RRGGBB sendo RR: quanto de vermelho, de 00 a FF sendo GG: quanto de verde, de 00 a FF sendo BB: quanto de azul, de 00 a FF No evento OnDrawColumnCell, coloque: // COR DAR DEMAIS CELULAS DBGrid.Canvas.Brush.Color := <cor> DBGgrid.DefaultDrawColumnCell(Rect, DataCol, Column, State); // COD DAS CELULAS SELECIONADAS if (gdSelected in State) then begin DBGaqven.Canvas.Brush.Color := <cor>; DBGaqven.Canvas.Pen.Color := <cor>; DBGaqven.DefaultDrawColumnCell(Rect, DataCol, Column, State); end;

Uso de variveis especiais procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin // Buttom pode assumir: mbLeft, mbRight, mbMiddle // if Button=mbLeft then showmessage('pertei o left'); // Shift set of (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble); { if shift=[ssAlt,ssLeft] then showmessage(' o ALT'); if shift=[ssShift,ssLeft] then showmessage(' o SHIFT'); if shift=[ssCtrl,ssLeft] then showmessage(' o CTRL'); }

Pag. 175/176

end; 7.7- Lista de erros de compilao Erros Comuns: Undeclared identifier: 'Buttom' Variavel no declarada Could not compile used unit 'Unit1.pas' A UNIT no pode ser compilada (tem erro) Missing operator or semicolon Erro de operador, ou falta ponto e virgula Type of expression must be BOOLEAN A expresso tem que ser lgica Statement expected but end of file found Expresso esperada, mas fim de arquivo encontrado Incompatible types Tipos incompatveis Incompatible types: 'Integer' and 'Tcaption' - Tipos incompatveis: inteiro e Tcaption (string)

Pag. 176/176