Você está na página 1de 71

1

1. Introdução ao Ambiente Delphi

A figura abaixo mostra a tela inicial do Delphi 7 e nos dá uma visão geral de seu ambiente de
desenvolvimento, composto de múltiplas janelas individuais que permitem executar diversas tarefas, que
serão explicadas mais adiante. Seus principais elementos são:
• Form Designer
• Code Editor

• Object Inspector
• Object Tree View
• Palheta de componentes
• Menu principal
• Barra de ferramentas

2
1.1 O Form Designer
O Form Designer é a janela vazia que aparece na figura abaixo:

3
É sobre esta janela que a interface gráfica da aplicação é desenvolvida, acrescendo-se os
componentes com os quais o usuário irá interagir.
Podemos configurar algumas propriedades do form designer através do menu Tools >
Environment Options > Designer mostrado próxima ilustração:

4
No grupo “Grid Options” podemos escolher se o grid será ou não exibido (Display Grid) bem como
o seu tamanho (Grid Size).

(* nota: o grid de tamanho 4x4 como o da figura é uma boa opção, pois permite uma boa visão do
alinhamento dos componentes sem ser demasiadamente pequeno *)

O grupo “Module creation options” permite escolher se o Delphi irá criar automaticamente ou não
novos formulários adicionados ao projeto (Auto create forms & data modules). Com esta opção
desmarcada, apenas o formulário configurado como “Main Form” será criado automaticamente.
No menu Project > Options > Forms mostrado abaixo, podemos perceber o efeito desta opção:

5
No exemplo, temos uma aplicação com 3 formulários, mas apenas aquele configurado como “Main
Form” aparece na lista “Auto create forms”, enquanto que os outros são configurados apenas como
disponíveis em “Available forms”, devendo ser criados em tempo de execução. Se a opção auto create
forms & data modules estiver marcada, todos os formulários do projeto aparecerão na lista Auto create
forms.

(* nota: a princípio, não desmarque o auto create forms & data modules para evitar problemas. Se não
desejar que os forms sejam criados automaticamente, vá à tela acima e retire-os da lista dos forms que
são criados automaticamente. Aliás, jamais deixe que o Delphi crie todos os formulários. Deixe para criá-
los apenas quando forem necessários e destrua-os quando terminar de usar. Assim, o programa se torna
mais leve e não consumirá recursos e memória sem necessidade! *)

Voltando às Environment Options, resta-nos comentar o grupo “Options” que tem algumas funções
interessantes. Em “Show component captions” definimos se o designer irá ou não mostrar os nomes de
componentes não visuais – marque!!! Veja abaixo como fica fácil identificar os componentes!

6
Em “Show designer hints” habilitamos as informações que surgem quando o mouse é posicionado
sobre um componente. “Show extended control hints” permite exibir informações mais abrangentes sobre
um controle, como tab order, top, left, etc. Veja estas opções em ação abaixo, onde na primeira figura
temos a opção “extended control hints” ativa e na segunda desabilitada:

Mesmo estando inicialmente vazio, o formulário padrão fornecido pelo Form Designer já possui
todas as funcionalidades básicas de uma janela, como minimização, maximização, restauração,
fechamento e redimensionamento, sem que seja necessária nenhuma programação.

7
Uma aplicação tipicamente possui um formulário principal e vários outros chamados a partir dele,
que executam funções diferentes dentro do sistema.
Cada formulário criado no Delphi é acompanhado de sua respectiva Unit, que é o seu código-fonte.
Veremos agora a janela responsável pela edição do código-fonte das Units, o Code Editor.

1.2 O Code Editor


Como foi mencionado anteriormente, o Code Editor (que aparece na próxima figura) é onde
inserimos o código-fonte de nossas aplicações:

Na janela maior, que é o editor propriamente dito, podemos abrir várias Units ao mesmo tempo,
como na figura, para trabalharmos com o código de diversos formulários simultaneamente. Assim como o
Form Designer, o Code Editor também pode ser personalizado, bastando acessar o menu Tools > Editor

8
Options. Não mencionaremos todas as configurações possíveis aqui, porque muitas delas já estão ótimas
como estão e devem ser deixadas em paz, e também para não nos aprofundarmos sem necessidade em
assuntos menos importantes. Abaixo, vemos a palheta Color das propriedades do editor, onde
configuramos as cores dos elementos do código-fonte:

(* nota: o Delphi 7, por default, configura Strings, comentários e números com a mesma cor – a Navy.
Usar cores diferentes, não importam quais, para estes elementos torna o código mais fácil de ler,
destacando cada tipo diferente de elemento. Assim, não se corre o risco de comentários serem
confundidos com strings, strings numéricas se confundirem com números verdadeiros, etc. *)

Em “Code Insight” configuramos os recursos que permitem completar código, exibir parâmetros de
funções em forma de hint, etc., bem como o tempo (delay) após o qual elas aparecem para o
programador. Deixe todas habilitadas, pois são uma mão na roda!

9
Na palheta “Source Options”, não há necessidade de alterar nada. Tudo está perfeito como está!

Mas nela encontramos o interessantíssimo recurso “Edit Code Templates”. Os templates nada
mais são do que os modelos de comandos, declarações de procedimentos e funções, declaração de
classes, etc., que podem ser incluídas no código. Assim o programador pode economizar algumas

10
tecladas! Podemos facilmente editar ou adicionar novos templates através da tela que aparece na próxima
ilustração:

Com o botão “Add” podemos incluir um novo template, dando-lhe um “Shortcut name” e uma
descrição. O shortcut é usado para encontrar o template durante a edição. Na caixa “Code” nós inserimos
o código que irá aparecer ao usarmos o template. A barra vertical pode ser adicionada ao template para
mostrar ao editor onde ele deverá posicionar o cursor quando o template for inserido no código fonte. Os
templates ficam no arquivo:
“C:\Arquivos de programas\Borland\Delphi7\Bin\DELPHI32.DCI”
Podemos os DCI’s que nós criarmos para que sejam usados em Delphis alheios ou importar DCI’s de
outros delphis para usar no nosso!

1.3 Object Inspector


O Object Inspector é a janela responsável pelo controle das propriedades e eventos de todos os
componentes da aplicação. Ele permite também encontrar componentes de um formulário facilmente
através da lista na parte superior, que exibe todos os componentes do formulário ordenados
alfabeticamente pelos seus nomes. O Object Inspector pode ser visto na imagem seguinte:

11
A palheta Properties nos dá acesso a todas as propriedades de visibilidade published do
componente atualmente selecionado para que possamos modificá-las em tempo de design. A forma de
edição de uma propriedade está relacionada ao seu tipo. Algumas tem seus valores alterados digitando-se
diretamente na linha correspondente; outras exibem uma lista de valores possíveis, dos quais um deve ser
escolhido; outras podem se expandir – as que tem um ‘+’ antes do nome – e por fim, existem aquelas que
possuem um editor separado – as que possuem uma ‘...’ na linha de edição.
A palheta Events nos permite criar um corpo vazio de método para implementarmos o código que
será executado ao ocorrer o evento selecionado. Para tanto, basta darmos um duplo - clique na linha
correspondente ao evento ou então um Ctrl + Enter. Podemos ainda selecionar na lista outros eventos
compatíveis com aquele que estamos para criar. Assim, podemos reutilizar outros eventos ao invés de
implementar o mesmo código várias vezes. Um evento é compatível com outros desde que possuam os
mesmos parâmetros – com os mesmos tipos de dados, mesma ordem e mesma quantidade – ou seja se
suas assinaturas forem as mesmas.
O Object Inspector pode ser customizado pelo usuário no menu Tools > Environment options >
Object Inspector, mostrado abaixo:

12
À esquerda podemos mudar as cores dos elementos do Object Inspector e à direita temos
algumas opções de exibição. Por default, a única desabilitada é ‘Show read only properties’, que define se
as propriedades somente leitura, que não podem ser modificadas, apenas lidas, vão aparecer. Não são
necessárias maiores explicações sobre estas configurações.
Estas opções também podem ser acessadas ao clicar com o botão direito no Object Inspector.
Este procedimento permite também acessar outras configurações que não aparecem no método descrito
acima, como o menu ‘Arrange’. Esta opção disponível desde o Delphi 5 muda a forma de exibição das
propriedades e eventos. O default é Arrange > By Name, o arranjo tradicional. A opção Arrange > By
Category, agrupa propriedades e eventos por categoria, o que pode facilitar a programação em alguns
casos, como ajuste de tamanho e posição de componentes no Form Designer. Normalmente as
propriedades que ajustam tamanho e posição ficam distantes quando exibidas por nome, mas se as
agruparmos, elas ficam juntas. Veja o aspecto das propriedades agrupadas por categoria:

13
1.4 Object Tree View
O Object Tree View é a janelinha localizada por default logo acima do Object Inspector. Ele nos dá
uma visão hierárquica dos componentes do formulário, com visão em árvore. Através dele podemos ver
em qual container – Panel, GroupBox, ScrollBox, o próprio Form, etc., chamados em Delphi de ‘Parents’
dos componentes dos componentes neles contidos – cada componente está contido, podendo inclusive
transferi-lo de um parent para outro. Para isto, basta arrastá-lo para cima do ícone do novo parent e ele
será mudado para lá sem perder o valor de suas propriedades. Pode-se inclusive deletar um componente
pelo Object Tree View. Outra facilidade oferecida por ele diz respeito a localização de componentes. Às
vezes, de acordo com nosso layout, alguns componentes podem ficar de difícil acesso pelo Form
Designer, tanto visualmente quanto pelo mouse. O Object Tree View pode nos ajudar a encontrá-los
nestes casos. Veja uma ilustração do Tree View logo abaixo:

14
1.5 A Palheta de Componentes
A palheta de componentes é uma barra de ferramentas onde se encontram todos os componentes
que o desenvolvedor irá utilizar ao programar. Ela está dividida em várias palhetas onde os componentes
são agrupados. Como o Delphi 7 possui inúmeras diferentes palhetas e elas serão vistas gradualmente na
medida em que trabalhamos, teremos aqui apenas uma visão geral. Aí em baixo está uma visão da
palheta de componentes do Delphi 7. Na ilustração ela foi destacada da barra de ferramentas principal
apenas para melhorar sua visualização:

Algumas palhetas de componentes importantes são:

• Standard
Nela estão os componentes básicos de uma interface gráfica: Edit, Button, ComboBox,
RadioButton, CheckBox, MainMenu... Sem dúvida, a mais usada
• Additional
Sob certos aspectos é semelhante à Standard, mas possui componentes de interface mais
incrementados como BitBtn, LabeledEdit, SpeedButton, MaskEdit e StaticText. Além disso, é nela
que estão componentes de imagem (Image) e de gráficos (Chart)
• Win32
Nesta palheta podemos encontrar componentes para barra de status, barra de progresso, barra de
ferramentas, calendário, etc. Também temos o PageControl, que nos permite criar um layout de

15
palhetas, como o da palheta de componentes (que aliás, é um PageControl mesmo, já que o
Delphi foi feito em Delphi!!!)
• System
Seus principais componentes são o Timer, que representa um contador de tempo e o MediaPlayer,
para executar arquivos de som e filmes
• DataAccess
Possui componentes que comunicam componentes se acesso a banco de dados com os
componentes da DataControls. Com destaque para o DataSource, ClientDataSet e
DataSetProvider
• DataControls
Possui semelhantes aos da Standard, porém com a capacidade de editar dados diretamente nos
campos de tabelas do banco de dados
• Dialogs
Possui componentes que encapsulam os principais diálogos do Windows como o diálogo de fonte,
de salvar arquivo, de abertura de arquivo, de impressora, entre outros
• dbExpress, ADO, InterBase, BDE
Estas palhetas contém componentes para conexão e acesso a bancos de dados, cada um para um
tipo de conexão diferente

1.6 Project Manager e Project Group


Às vezes, pode acontecer de um único sistema ser composto de vários projetos separados, como
aplicações ou pacotes, que representam vários módulos deste sistema. Assim, surge a necessidade de
uma forma de navegação rápida entre os projetos distintos do sistema.
Mas, como o Delphi abre apenas um projeto de cada vez, como podemos navegar pelos projetos
sem ter que abrir e fechar projetos a todo instante? A resposta está no Project Group!
O Project Group é um arquivo com extensão .bpg onde o Delphi guarda a informação de todos os
projetos separados que fazem parte de um único sistema maior. E o Project Manager é a janela
responsável por criar e gerenciar os Project Groups, bem como fazer a navegação entre os diversos
projetos agrupados nele. Na figura abaixo, podemos ver como é o Project Manager.

16
Na figura vemos 5 diferentes programas num mesmo Project Group. Cada um deles é um projeto
separado dos demais, mas como eles estão relacionados entre si, agrupa-los num Project Group torna seu
gerenciamento mais fácil.
A raiz da árvore de projetos é o Project Group, o arquivo .bpg. Para criar um novo projeto nele,
basta clicar com o botão direito do mouse e escolher “Add New Project...” O Delphi abrirá a janela New
Itens para que o usuário selecione o tipo de projeto a adicionar. Mas se desejarmos simplesmente
adicionar um projeto já pronto ao grupo, sem segredo! Basta escolher a opção “Add Existing Project...” e
selecioná-lo!

1.7 Salvando um Layout Personalizado


Quando existem vários programadores trabalhando com o mesmo Delphi, podem surgir
divergências quando à disposição e ao tamanho das janelas do ambiente que cada um gosta de usar.
Gosto não se discute, mas chegar ao trabalho e ver que algum colega bagunçou todo o seu
ambiente é realmente irritante! Para solucionar estes pequenos problemas, o Delphi permite desde a
versão 5 que cada usuário ajeite as janelas como bem entender e salve o resultado. Assim, cada usuário
pode ter o seu layout de volta sempre que desejar! Para isso, basta utilizarmos a barra de ferramentas
abaixo:

Lista de layouts salvos Salva um layout Ativa layout selecionado

17
Os layouts são salvos na pasta Bin do Delphi, em arquivos com extensão .dst. Assim, podemos
fazer um backup deles para que seu layout favorito não se perca!

1.8 Customizando as Barras de Ferramentas do Delphi


Assim como tudo mais, é possível personalizar os botões das barras de ferramentas do Delphi.
Basta ir ao menu View > Toolbars > Customize...

Daí é só arrastar os botões para uma das barras de ferramentas do delphi e ele será adicionado!
(* nota: é interessante colocar alguns botões como o de compilar e os de find, replace e find in files que
são bastante usados e ajudam muito!!!! *)

1.9. Debugando Aplicações


A IDE do Delphi oferece diversas ferramentas para testarmos nossos programas e procurar erros
difíceis de encontrar. Dentre estas inúmeras ferramentas, veremos apenas as mais frequentemente
utilizadas, até por que as outras são meio difíceis de entender, pois mostram threads, processos,
assembler... e outras coisas meio além de nossa compreensão... Assim, estudaremos os Break points, a
Watch List, o Evaluate/Modify e o Inspect.

18
1.9.1. Break Point
Os Break Points são pontos determinados pelo programador onde o programa irá parar de
executar para que se possa analisar o código-fonte em busca de erros. Durante a pausa na execução,
podemos com o cursor do mouse observar valores de variáveis, de propriedades de objetos, etc., além de
podermos iniciar uma execução passo a passo do programa, com os comandos “Trace Into” e “Step Over”.
Abaixo vemos como se parece um Break Point:

Para colocar/retirar um desses, basta clicar na margem cinza da esquerda (onde fica o círculo
vermelho) ou então dar um F5 com o cursor na linha correspondente. Quando o programa for executado, a
execução vai parar quando chegar neste ponto. Para fazer a execução passo a passo, podemos dar um
F7 (trace into) ou F8(step over), que fazem com que apenas a próxima linha seja executada. A diferença
entre os dois é que se numa linha houver chamada para um procedimento ou função, o F7 entra na sub-
rotina, enquanto que o F8 executa a sub-rotina sem entrar nela.
Agora um caso comum: imagine que temos um trecho de código que executa uma repetição de 0 a
100. Mas aí ocorre um erro neste trecho! Então recorremos ao Break Point para descobrir o que há de
errado. Então executamos e fazemos um F8; iteração 1... nada; iteração 2.. nada; 20... nada; 55... nada!
Depois de muita luta descobre-se que o erro ocorre na iteração 100 (a última!), mas não se sabe por que
ele ocorre só nessa iteração. Mas como fazer para que o programa só pare na iteração 100 para
inspecionarmos o código e descobrir o erro? Pois o Break Point possui um editor onde podemos entre

19
outras coisas, definir uma condição de parada! Para tanto, é só clicar com o botão direito no círculo
vermelho e ir ao menu “Break point properties...” para exibir a tela abaixo:

No campo “Condition” basta informar a condição de parada tipo “Contador = 100” (a condição tem
a sintaxe do Delphi mesmo, igual as que se usa nas condições de comandos como if e while). Aí sim ele
só vai parar na 100ª iteração, onde está o erro! As propriedades avançadas não costumam ser utilizadas,
portanto não as abordaremos aqui.

1.9.2. Whatch List


É uma lista de variáveis ou propriedades cujos valores queremos vigiar enquanto o programa
executa. Todas as mudanças que ocorrerem nas variáveis da lista são exibidas na Whatch List.
Para adicionar uma variável à Whatch List, Basta clicar com o botão direito nela e ir ao menu
Debug > Add watch at cursor que aparecerá a telinha:

Os valores das variáveis em Watch Name aparecerão ao lado na coluna Value. Mas as vezes
quando queremos observar valores de propriedades de objetos, a whatch não funciona... Mas isso

20
acontece devido ao fato de que algumas propriedades possuem métodos de acesso internamente (como
veremos mia a frente). Para permitir chamadas à funções na Whatch List, devemos clicar com o botão
direito na variável e acessar o menu “Edit watch”:

Lá é só marcar “Allow Function Calls” e pronto!

1.9.3. Evaluate/Modify
Usado para ver e modificar valores de variáveis e propriedades em tempo de execução. Pode ser
acessado no menu Debug > Evaluate/Modify que aparece ao clicarmos com o botão direito no Code
Editor:

Passamos a ele uma expressão ou variável e em Result obtemos seu valor naquele momento da
execução. Em “New value” podemos atribuir um novo valor para a expressão (desde que seja algo que
possa receber valor! Nada de querer atribuir um novo valor para uma função por exemplo!). Uma

21
característica interessante do Evaluate é que ele dá acesso para outros debuggers como os watches e o
inspect, que será visto a seguir.

1.9.4. Inspect
O inspect é uma janelinha bem parecida com o Object Inspector que nos permite observar todas
as propriedades possíveis de um elemento passado para ele. Se passarmos um componente por exemplo,
podemos ver os valores de todas as suas propriedades, inclusive as posições de memória onde seus
métodos estão alocados! Vejamos um Inspect em ação exibindo os dados de um formulário:

Assim como o Evaluate/Modify, o Inspect permite que os valores sejam alterados. Se clicar nele
com o botão direito, aparece um menu onde podemos configurar algumas características do Inspector,
bem como mudar o valor que se está inspecionando, fazer typecasts, etc.

(* nota: Todos os debuggers vistos devem trabalhar em conjunto com os Break Points, pois não faz muito
sentido analisar um trecho de código ou o estado atual de um componente com o programa em
“movimento”. Até por que ele executa em milésimos de segundo! *)

2. A Estrutura dos Programas Delphi

2.1. VCL x CLX


VCL é a biblioteca padrão utilizada pelo Delphi para o desenvolvimento na plataforma Win32, e
conta com toda a API, os componentes, etc. Mas a partir do Delphi 6, surgiu uma nova API, chamada

22
CLX, que permite fazer um intercâmbio de projetos entre o Delphi e o Kylix. Uma aplicação feita com os
componentes da CLX podem ser portadas de Windows para Linux e vice-versa. Para tanto, basta abrir um
projeto Delphi no Kylix e recompilar, podendo-se fazer o mesmo do sentido inverso. Para criarmos uma
aplicação CLX só precisamos fazer File > New > CLX Application e pronto! Apenas substituímos o
tradicional New Application por New CLX Application! Mas existem algumas diferenças. Pode-se perceber
que a palheta de componentes muda. Isso porque os componentes da CLX não podem ser os mesmos da
VCL, e eles foram totalmente refeitos. Assim, uma CLX Application possui bem menos componentes
disponíveis que a VCL.

2.2. Projetos
Um projeto Delphi, na verdade, é o programa propriamente dito e sua sintaxe é idêntica à do
Pascal. Este programa apenas cria os formulários, onde efetivamente se concentram todas as
funcionalidades da aplicação (mas existem as aplicações console, que não usam formulários, e aí sim as
funcionalidades devem se concentrar no programa!). O projeto é armazenado pelo Delphi em um arquivo
com extensão .dpr e para visualizar seu código fonte, basta ir ao menu Project > View Source:

Perceba que o nome do programa é o nome do projeto, portanto, observe este detalhe ao salvar o
projeto! Vemos que o objeto global Application é que realiza todo o trabalho num programa visual, tanto na
criação dos formulários quanto na execução em si.

23
2.3. As Units
As Units são arquivos que representam uma coleção de tipos, classes, procedimentos, funções,
constantes, etc. que podem ser importadas e utilizadas durante o desenvolvimento. Vamos dar uma
olhada na estrutura de uma Unit vazia:

Em “unit” fica o nome do arquivo correspondente à unit, que também será o nome utilizado ao
importá-la. Após isso, vêem as 4 seções nas quais uma Unit pode ser dividida:

• Interface: é a seção pública da Unit. Tudo que for declarado aqui será visível fora da Unit. Nesta seção
ficam declarados todos os “serviços” oferecidos pela Unit, que depois devem ser implementados na
seção implementation.
• Implementation: esta seção é onde implementamos procedimentos, funções e classes declaradas na
seção interface. Esta seção é privada, ou seja, seus elementos são visíveis apenas dentro da Unit. É
possível fazer declarações de classes, sub-rotinas e outros elementos em implementation da mesma
forma que em interface, mas elas se tornam privadas da Unit.

24
• Initialization: seção usada para inicializar elementos da Unit no momento em que ela é carregada para
ser usada no programa. É possível tanto inicializar variáveis quanto para instanciar objetos ou abrir
arquivos.
• Finalization: seção com função oposta à da initialization, servindo para fazer a finalização de
elementos e liberação de recursos usados por elementos da Unit. Pode-se, por exemplo, destruir
objetos criados ou fechar arquivos abertos em initialization.

Destas 4 seções, as duas primeiras – interface e implementation – são obrigatórias e não podem
ser omitidas. Já as duas últimas – initialization e finalization – são opcionais. As Units são armazenadas
em arquivos com extensão .pas, tanto na VCL quanto na CLX.

2.4. Formulários
Os formulários criados através do Form designer são serializados pelo Delphi em arquivos de texto
com extensão .dfm (VCL) ou .xfm (CLX), e devido a isso, não vemos nenhum código de inicialização para
instanciar componentes ao criar um formulário, como acontece em IDE’s Java.
Esses dados serializados são incorporados ao executável em forma binária durante a compilação
e ao executar o programa, os componentes são criados com base nestas informações serializadas. Isso
acaba por deixar o código fonte de um formulário mais limpo, pois apenas a parte que foi implementada
pelo desenvolvedor fica visível na Unit. Vamos dar uma espiada no conteúdo de um dfm de um Form bem
simples:

25
Todas as propriedades que foram modificadas no Object Inspector são armazenadas neste
formato. Assim, quando o executável instanciar os componentes, ele poderá acessar estes valores e
configura-los conforme foi definido em tempo de projeto!
Podemos acessar o dfm como foi feito acima clicando com o botão direito no formulário e
selecionando View as Text. Para voltar é só fazer o mesmo no dfm, só que neste caso é View as Form.

2.5. Pacotes – Packages


Os pacotes são utilizados em Delphi para criar bibliotecas que podem ser usadas por uma
aplicação, como se fossem um tipo especial de dll, onde se pode armazenar formulários, Units
independentes, entre outras coisas. O próprio Delphi se utiliza dessas bibliotecas o tempo todo. Qualquer
componente instalado na IDE, por exemplo, deve estar armazenado num pacote, que é instalado
posteriormente no Delphi. Os pacotes, assim como os programas e os Project Groups, são considerados
projetos pelo Delphi e são salvos com a extensão .dpk. Ao serem compilados, os pacotes geram dois tipos

26
de arquivos, os dcp e os bpl. Os dcp servem para que um pacote importe outros que ele precise usar. Já
os bpl são as tais bibliotecas tipo dll citadas acima. São eles os arquivos que podem ser usados por
programas Delphi, inclusive o próprio Delphi.
Os pacotes estão fora do escopo do curso, mas devido a sua constante presença no Delphi e
também por serem usados na instalação de componentes, não poderiam deixar de ser ao menos citados
aqui.

2.6. Arquivos Compilados


Vimos acima os arquivos que o Delphi cria ao salvarmos nosso trabalho. Porém, ao compilarmos
estes arquivos, outros são gerados.
As Units dão origem aos arquivos dcu. São estes arquivos que o Delphi lê utilizamos elementos de
uma Unit importada, tanto que comumente nos deparamos com erros do tipo “File not found: UnitX.dcu”, o
que significa que o Delphi não está encontrando o arquivo dcu da Unit que queremos usar.
Já os arquivos dfm (ou xfm) junto com os dpr, geram o executável da nossa aplicação. Existem
outros arquivos gerados durante a compilação como res, cfg, ddp, etc. mas que não são essenciais ao
projeto, podendo ser excluídos sem maiores problemas. O Delphi simplesmente os criará novamente. São
arquivos que guardam configurações do projeto e algumas outras informações.

3. A Delphi Language

Veremos agora a sintaxe da linguagem Delphi, seus principais comandos, declarações e tipos de dados.
Alguns podem se perguntar “mas não é Object Pascal???”. Sim, era mesmo, só que a Borland oficializou o
nome da linguagem como Delphi mesmo há pouco tempo atrás (note inclusive que no help do Delphi 7
aparece “Delphi Language Reference” no cabeçalho ao invés de “Object Pascal Reference”). Mesmo
assim ainda podemos encontrar muito material, mesmo recente, ainda se referindo a ela como Object
Pascal.

3.1. Comentários
O Delphi suporta 3 tipos diferentes de comentário, sendo um de linha e dois de bloco:

// este é um comentário de linha.


{ este é um comentário de bloco.
ele pode se estender por várias linhas }
(* este também é um comentário que pode
se estender por múltiplas linhas *)

27
Podemos usar os tipos diferentes de comentários para propósitos diferentes, como um para
colocar observações no código – o comentário propriamente dito – e outro para desabilitar código fonte ao
invés de deletar.

3.2. Diretivas de Compilação


São tags colocadas para mudar o comportamento do compilador num certo trecho do código. Uma
diretiva de compilação bem conhecida por todos é a {R$ *.dfm} que controla a serialização do formulário
para o arquivo dfm (pelo amor de Deus, não toque nela!!!). Apenas como curiosidade, dê uma olhada no
código de algumas Units padrão do Delphi (dando Ctrl + click no nome delas no uses) como SysUtils por
exemplo e note que elas estão infestadas de diretivas de compilação, muitas delas responsáveis por
configurar a compilação de uma parte do código de acordo com o sistema operacional, se Linux ou
Windows.

3.3. Operadores
A seguir temos um resumo dos principais operadores presentes em Delphi, bem como os tipos de
operando aos quais eles se aplicam, o tipo de dado resultante da operação e a categoria a que eles
pertencem.
Operadores Aritméticos
Operador Operação Tipo operando Resultado Exemplo
+ adição integer, real integer, real X+Y
+ unário sinal positivo integer, real integer, real +X
- subtração integer, real integer, real X–Y
- unário sinal negativo integer, real integer, real -X
* multiplicação integer, real integer, real X*Y
/ divisão real integer, real real X/Y
div divisão inteira integer integer X div Y
mod resto da divisão integer integer X mod Y

Operadores Booleanos
Operador Operação Tipo operando Resultado Exemplo
not negação (não) boolean boolean not X
and conjunção (e) boolean boolean X and Y
or disjunção (ou) boolean boolean X or Y
xor ou exclusivo boolean boolean X xor Y

Operadores Lógicos de Bits (Bitwise)


Operador Operação Tipo operando Resultado Exemplo
not negação de bits integer integer not X
and and de bits integer integer X and Y

28
or ou de bits integer integer X or Y
xor xor do bits integer integer X xor Y
deslocamento de bits à esquerda (shift
shl integer integer X shl 2
left)
deslocamento de bits à direita
shr integer integer X shr Y
(shift right)

Operadores de String
Operador Operação Tipo operando Resultado Exemplo
+ concatenação string string ‘Delphi’ + ‘7’

Operadores de Conjunto (Set)


Operador Operação Tipo operando Resultado Exemplo
+ união set set X+Y
- diferença set set X–Y
* interseção set set X*Y
in pertinência set, ordinal boolean X in Y

Operadores de Classe
Operador Operação Tipo operando Resultado Exemplo
objeto tratado
como sendo
as typecast objeto, classe/interface Sender as TButton
instância da
classe/interface
objeto é instância de
is objeto, classe/interface boolean Sender is TEdit
classe

Operadores Relacionais (Comparação)


Operador Operação Resultado Exemplo
= igualdade boolean X=Y
<> diferença boolean X <> Y
< menor que boolean X<Y
> maior que boolean X>Y
<= menor ou igual boolean X <= Y
>= maior ou igual boolean X >= Y

Vejamos agora os operadores com relação à precedência:

• Primeiro nível (mais alta): not

29
• Segundo Nível: *, /, div, mod, and, shl, shr, as
• Terceiro Nível: +, -, or, xor
• Quarto Nível (mais baixa): <>, =, <, >, <=, >=, in, is

Além destes , existe ainda o operador de atribuição := , também de baixa precedência,


responsável por atribuir o valor de uma expressão ou variável em outra variável.

3.4. Principais Tipos de Dados


Os tipos de dados presentes no Delphi são basicamente os mesmos do Pascal tradicional, porém
com o acréscimo dos tipos de dados classe e interface, para o suporte à programação orientada a objetos.
Os tipos de dados podem ser simples ou estruturados, além de String e outros como Variant e os tipos
procedurais, usados na implementação de eventos. Todo novo tipo de dados criado pelo programador
devem estar dentro de uma seção type na Unit.

(* nota: por convenção, todo nome de tipos de dados criados pelo usuário, como os que vamos fazer mais
a frente, deve começar com “T” de type *)

3.4.1. Tipos de Dados Simples


Os principais tipos de dados simples são Integer (números inteiros), Real (ponto flutuante), Char
(um caracter), Boolean (true ou false), as enumerações e as sub-ranges.

3.4.1.1. Enumerações
Como Integer, Real, Char e Boolean são bem simples, vamos nos deter aos dois últimos. As
enumerações são tipos de dados compostos por uma lista de valores constantes, sendo que uma variável
deste tipo pode assumir apenas um destes valores por vez. Exemplo:

30
Aqui, declaramos o tipo TMoeda na seção type de uma Unit e em seguida uma variável deste tipo
na seção var, chamada Moeda. Depois, a inicializamos com o valor mdDolar na seção opcional
initialization da Unit. A variável Moeda só pode assumir um dos 4 valores definidos para o tipo TMoeda. As
enumerações são amplamente utilizadas no Delphi e podemos ver várias propriedades deste estilo, como
por exemplo, a propriedade Align, presente em vários componentes visuais como o formulário.

3.4.1.2. Sub-range
Os tipos sub-range são criados simplesmente restringindo o conjunto de valores de um tipo
qualquer. Vamos ver um exemplo:

31
Neste caso, criamos o tipo TPorcentagem pela restrição de valores do tipo Integer (que possui um
intervalo de -2147483648 à 2147483647). Assim, uma variável do tipo TPorcentagem só pode receber um
valor que esteja entre 0 e 100.
A criação de um sub-range não se restringe aos números. Pode-se fazer a mesma coisa com
caracteres e até mesmo com enumerações.

3.4.1.3. String
Quanto ao tipo String, ele é tratado pelo Delphi como uma cadeia de caracteres e pode-se acessar
seus elementos como se ele fosse um array, que se inicia na posição 1 e vai até a posição n, além de
também podermos declarar uma variável String com um número limitado de caracteres. O exemplo a
seguir ilustra este tratamento dado às Strings:

32
(* nota: o Delphi fornece várias funções para trabalhar com strings, dentre elas podemos destacar:

Delete(string qualquer, índice inicial, nº. de caracteres) – exclui uma parte de uma string, sendo que a
parte começa em ‘índice inicial’ e tem o tamanho passado em ‘nº. de caracteres’.

Copy(string qualquer, índice inicial, nº. de caracteres) – função que retorna uma cópia de parte de uma
string passada como argumento. O significado dos argumentos é o mesmo de Delete.

Insert(substring, string destino, inicio) – insere a ‘substring’ do 1º argumento dentro da ‘string destino’
começando na posição dada em ‘início’.

Pos(substring, string) – se a ‘substring’ está contida dentro da ‘string’, esta função retorna o índice de
onde a ‘substring’ começa. Agora, se não existir a ‘substring’ dentro da ‘string’, ela retorna zero. *)

33
3.4.2. Tipos Estruturados
Vejamos agora os principais tipos estruturados suportados pelo Delphi. Um tipo estruturado é
aquele que pode conter mais de um valor, além de poder ser construído utilizando-se outros tipos
estruturados, formando níveis de estrutura ilimitados.
Os principais tipos estruturados são sets, arrays, records, files assim como classes, interfaces e
referências de classes.

3.4.2.1. Sets
Os sets são tipos que representam um conjunto de valores, assim como os conjuntos que
aprendemos na matemática, podendo-se realizar operações como união, intersecção e pertinência sobre
eles (veja na tabelinha de operadores e operações de conjuntos). Porém, os sets têm uma limitação em
relação aos outros tipos estruturados; eles só suportam a criação de conjuntos de tipos ordinais. Mas o
que é um tipo ordinal? É um tipo de dados cujos valores possuem uma ordem. Integer é um tipo ordinal (-
2, -1, 0, 1, 2,...), Boolean (False, True), Char também (‘a’, ‘b’, ‘c’,...) por que são usados os códigos ASCII
dos caracteres e as enumerações, cujos valores são tratados internamente como números inteiros (o
compilador do Delphi não entende o ‘mdDolar’ que fizemos acima diretamente como foi declarado, mas
como um número) Bem, vamos ver um set em ação:

34
Podemos ver um set (TMoedas) construído a partir de uma enumeração (TMoeda). Com ele
podemos fazer conjuntos de valores de TMoeda. Este tipo de construção é amplamente usado no Delphi
em propriedades de componentes. Dê uma olhada na propriedade Font de algum componente e procure
por Font.Style. Pois bem, esta propriedade é do tipo TFontStyles que por sua vez é um set de uma
enumeração, o TFontStyle, exatamente como fizemos com as moedas.

3.4.2.2. Arrays
Vamos aos arrays, também conhecidos por aí como vetores. Arrays são listas de elementos do
mesmo tipo de dados, em que cada elemento possui um índice onde é armazenado. Em Delphi, os arrays
podem ser estáticos ou dinâmicos.
Os arrays estáticos são aqueles que possuem nº. fixo de elementos, definido durante a
declaração, que não pode mudar em tempo de execução. Diferentemente de outras linguagens, o Delphi
permite que os índices de um array estático comecem a partir de qualquer número inteiro, mesmo
negativos. Vejamos a declaração de arrays estáticos:

35
Neste exemplo podemos ver a flexibilidade na criação dos índices para um array, bem como as
formas para ler e escrever nos índices.
Só até aí vimos vetores, ou seja arrays unidimensionais. Vamos ver agora como criar matrizes, os
arrays multidimensionais:

Podemos notar duas formas de trabalhar com matrizes, a forma “array de array” e a forma “direta”,
que trata a matriz diretamente como matriz. Podemos usar estas duas formas tanto na declaração como
também durante a leitura e escrita de elementos.
Agora os arrays dinâmicos. Estes são os que podem esticar ou encolher durante a execução do
programa. Outra diferença entre eles e os estáticos, além do dinamismo é claro, é que arrays dinâmicos
SEMPRE começam no índice zero (o que implica que não podemos fazer aquela brincadeira do “array
negativo” com eles!) e devem ser declarados sem índices.

36
Para trabalharmos com arrays dinâmicos, podemos utilizar algumas rotinas do Delphi que
permitem realizar a mudança de tamanho e a obtenção do tamanho e do maior e menor índices. Vamos a
elas:

• SetLength(array, novo tamanho): Esse é o procedimento que faz o array dinâmico (passado ao
parâmetro array) mudar de tamanho (definido no parâmetro novo tamanho).
• Length(array): esta função retorna o tamanho (número de elementos) de do array passado à ela. Esta
função também funciona com Strings!
• Low(array): Retorna o menor índice do array. Só que nos arrays dinâmicos é desnecessária já que
eles sempre começam do zero.
• High(array): Retorna o maior índice do array.

Ao utilizar estas rotinas em conjunto, podemos manipular perfeitamente os arrays dinâmicos,


cabendo aqui uma observação importante: um array dinâmico recém-declarado, vazio, tem os seguintes
valores para as funções acima: Lenght = 0, Low = 0, High = -1 (o maior índice é menor que o menor
índice!). este conhecimento é útil para fazer alguns testes como array vazio por exemplo. Eis um
codigozinho para ilustrar:

37
Neste exemplo, temos um procedure que adiciona um elemento ao array dinâmico no índice
passado como argumento. Se o índice for menor que zero, disparamos uma exceção do tipo EListError
com uma mensagem. Se o índice for maior ou igual ao comprimento (length) do array, devemos fazê-lo
crescer até o tamanho índice + 1 para poder gravar o elemento no índice desejado. Imagine que o array
esteja com 3 elementos (length = 3) e com índices variando entre 0 e 2. Aí mando adicionar um elemento
no índice 10. Para isso, preciso esticar o array até o tamanho 11, para que seus índices variem de 0 a 10.
Dessa forma posso inserir o elemento no índice 10 como foi pedido!
E se quisermos uma matriz dinâmica??? Sem problemas! O processo é bem parecido com as
matrizes estáticas. Veja só:

38
Neste caso, só podemos declarar no estilo “array de array”, já que pra fazer a declaração de matriz
“direta” precisaríamos de índices. Para inicializá-las com SetLength, temos duas alternativas: na primeira,
a mais fácil, acrescentamos mais parâmetros à SetLength de acordo com o nº. de dimensões. A outra,
mais complexa, consiste em criar 1º as linhas, sem as colunas, para depois criar as colunas de cada linha,
uma por uma. Esta abordagem, embora trabalhosa, tem suas vantagens, pois ganhamos a flexibilidade
de criar uma matriz em que cada linha tem um nº. diferente de colunas, o que não é possível da primeira
forma.

3.4.2.3. Records (registros)


Os records são estruturas capazes de guardar elementos de tipos diferentes, onde cada elemento
é chamado de campo. Os records não têm mistério, vamos ao exemplo:

39
Criamos um record com 3 campos, cada um de um tipo diferente e 3 variáveis cujos tipos
correspondem a cada tipo do record. Depois gravamos alguns dados no registro e a seguir os lemos e
atribuímos às variáveis. Os campos de um record são acessados pelo operador “.”.

3.4.2.4. Files
Os files ou arquivos são seqüências de dados de mesmo tipo que podem ser persistidos em disco
– como arquivos! Existem diversas rotinas no Delphi para manipular arquivos, das quais veremos algumas
a seguir:

40
• AssignFile(arquivo, nome do arquivo): Associa uma variável file a um nome de arquivo físico. Aos
aplicar AssignFile, podemos usar a variável para manipular o arquivo físico associado à ela.
• Rewrite: Abre um arquivo, porém limpando todo o conteúdo anterior, se houver.
• Reset: Abre um arquivo e posiciona no início, sem apagar conteúdo anterior.
• FileExists(nome do arquivo): Retorna verdadeiro se o arquivo cujo nome foi passado como
argumento existe.
• Write(arquivo, valores): Escreve no arquivo referenciado por uma variável file os valores passados na
lista de valores. Os valores devem ser do tipo de dado que o arquivo armazena.
• Writeln(arquivo, valores): Faz o mesmo que o write, só que solta uma linha para cada valor.
• Read(arquivo, valores): Lê dados do arquivo referenciado pela variável do tipo file passada ao
parâmetro arquivo e atribui os valores lidos às variáveis passadas na lista de valores. Estas variáveis
devem ser compatíveis com o tipo de dado que o arquivo armazena.
• Readln(arquivo, valores): O mesmo que read, só que após ler um valor, pula para a próxima linha do
arquivo.
• ExtractFileName(caminho): Retorna o nome do arquivo a partir de seu path.
• ExtractFilePath(nome arquivo): Obtém o path do arquivo cujo nome foi passado como argumento.
• ExtractFileExt(nome arquivo): Retorna a extensão de um arquivo.
• ExtractFileDrive(nome arquivo): Retorna o drive onde se localiza um arquivo.
• ExtractFileDir(nome arquivo): Retorna o diretório do arquivo passado como argumento.

3.4.3. Tipos Procedurais


Tipos procedurais são tipos de dados usados para criar referências para procedimentos e funções
além de métodos de classes, desde que eles tenham a mesma assinatura (nº., tipos e ordem dos
parâmetros, valor de retorno...) daquela declarada no tipo.
Através deste tipo de dados, podemos tratar sub-rotinas como valores comuns, podendo atribuí-las
a variáveis, passa-las como argumento para outras sub-rotinas, além de servirem de base para toda a
arquitetura de tratamento de eventos em Delphi.
Os tipos procedurais podem ser divididos em dois grandes grupos: os de referência para sub-
rotinas comuns, pertencentes diretamente à uma Unit e os de referência para métodos de classe. A
diferença entre eles é que as referências de método são implementadas com duas referências, uma para
o método em si e outra para o objeto dono do método. Exemplinhos:

41
Declaramos um tipo TFuncaoRealX, cuja assinatura é de uma função que retorna um valor Real e
que possui um único parâmetro também real. Isso quer dizer que as variáveis deste tipo podem referenciar
qualquer função que tenha essa mesma assinatura, como a função Quadrado do exemplo. Aí, atribuímos
a função Quadrado à variável FuncaoRealX para depois a executarmos através da referência, atribuindo
seu valor à variável Q.
Vamos ver agora um caso onde usaremos uma referência de métodos. o funcionamento é o
mesmo, a diferença é que precisamos adicionar a diretiva “of object” à declaração:

42
Declaramos o tipo procedural com a mesma assinatura de antes, porém com a diretiva “of object”
para indicar que ele é uma referência para métodos de classe. Em seguida, ainda na seção type da Unit,
declaramos uma classe, a TPotencia2, que herda de TObject. A função quadrado agora se tornou um
método da classe TPotencia2 ao invés de pertencer diretamente à Unit como antes.
Na seção var, adicionamos uma referência para um objeto potencia2, chamada P2 e na seção
implementation, temos a implementação do método TPotencia2.Quadrado, declarado dentro da classe
TPotencia2 na seção interface.
Na seção initialization, instanciamos o objeto P2 e a partir daí o processo é igual ao de antes, com
a diferença de estarmos executando um método pertencente a um objeto!

43
Como foi dito anteriormente, o Delphi se utiliza exatamente deste esquema para implementar o
tratamento de eventos. Eventos em Delphi nada mais são que referências a tipos procedurais, sendo que
o mais famoso de todos é o TNotifyEvent, cuja assinatura é:

procedure(Sender: TObject) of object

Familiar? Acredito que sim, pois esta é a assinatura da maioria dos eventos do Delphi, que
recebem apenas o objeto que realizou a ação como argumento.
vamos a um exemplo bem simples. Imagine que estamos no Form Designer e que nossa tela tem
apenas um botão (TButton). Quando vamos ao Object Inspector e clicamos 2 vezes no evento OnClick, o
Delphi cria um procedure com a assinatura do TNotifyEvent e o chama de
TForm1.Button1Click. Isso quer dizer que este procedure é um método da classe TForm1 que estamos
programando, ou seja, ele pertence ao formulário e não ao botão como muitos pensam. Mas como o
Button1 sabe que aquele método do formulário é o seu OnClick para executa-lo? Aí entra a magia dos
tipos procedurais! Aquele OnClick em que a gente clica para criar o evento na verdade é uma propriedade,
assim como Caption, Font, etc., do tipo TNotifyEvent. Assim, ela pode apontar para qualquer método que
tenha a estrutura do TNotifyEvent, assim como o nosso Button1Click!
Ao clicar 2 vezes no Object Inspector, automaticamente a referência OnClick do Button1 é
configurada para apontar para o método Button1Click do Form1 que o Delphi criou. Assim, quando o
programa roda, o botão executa o método indiretamente através da referência ao ser clicado, exatamente
como fizemos com a função Quadrado!

3.4.4. Variants
O tipo Variant é aquele cujas variáveis podem guardar valores de qualquer outro tipo de dado,
desde que não sejam tipos estruturados, ponteiros ou referências, ou seja, pode-se armazenar qualquer
valor de tipo simples numa variável Variant (String, Integer, Boolean, Char...), além de aceitar também
interfaces.
Tipicamente os Variants são usados para manipular dados cujos tipos variam durante a execução
ou não podem ser determinados durante a compilação.
Mas não devemos abusar dos Variants! Eles trazem flexibilidade, porém consomem mais memória
e têm acesso mais lento que variáveis de tipos estáticos! Portanto, só devem ser usadas quando forem
realmente necessárias.
Existem alguns valores especiais que o tipo Variant pode assumir. São eles o null e o
unassigned. Na verdade, os dois representam que o Variant está “vazio”, mas a diferença surge quando
tentamos atribuir um Variant a uma variável de tipo estático. Por exemplo, imagine que temos uma variável
String chamada S e uma Variant chamada V. Agora suponha que V está com valor null, ou seja vazia. O

44
que acontece se fizermos S := V? se você respondeu que S = ‘’ errou!!! Isso dá pau! Sempre que uma
Variant null é atribuída a uma variável comum ocorre uma exceção! Mas, se fizermos a mesma coisa com
V = unassigned, aí sim temos S = ‘’. E isso vale para os outros tipos. Se fizermos Int := V, onde V = null e
Int é um Integer, dá pau! Mas se V = unassigned, Int = 0!

3.4.5. Classes
As classes são estruturas que servem de modelo abstrato para a que possamos criar objetos, ou
instâncias concretas a partir dela. O Delphi trata suas classes com um tipo de dados estruturado qualquer,
tanto que elas também devem ser declaradas na seção type das Units.
Uma classe Delphi é composta basicamente de campos (fields), métodos e propriedades, cujo
acesso pode ser restringido como private, protected, public ou ainda published. Vamos ver e discutir a
estrutura típica de uma classe:

Declaramos a classe TClasse1 na seção type da Unit. a parte “class(TObject)” é onde dizemos
qual é a superclasse de nossa nova classe, ou seja, de quem ela herda (ou como dizem em Java, quem
ela estende), bem como as interfaces que ela implementa, se houverem. nossa classe de exemplo herda

45
de TObject, que é a classe raiz de toda a hierarquia de classes em Delphi. Esta parte dos parênteses não
é obrigatória. Se for omitida, o Delphi assume que estamos herdando de TObject.
Podemos ver também os quatro níveis de acesso que uma classe pode possuir:

• Private: Apenas os membros da própria classe podem acessá-los.


• Protected: Apenas os membros da própria classe e os das classes filhas podem acessá-los.
• Public: Qualquer um pode acessar.
• Published: Mesmo nível de acesso do public, porém com um diferencial. Membros published podem
ser manipulados em tempo de projeto. Todas as propriedades de componentes que aparecem no
Object Inspector são published, e é por isso que elas aparecem lá e podem ser alteradas durante o
projeto. mas os membros published vistos no Object Inspector são privilégio de descendentes da
classe TComponent, ou seja, só os componentes podem ser editados no Object Inspector. Isso
acontece porque um TComponent pode ser instalado na IDE do Delphi, enquanto que objetos de
classes anteriores não. Assim, em nossa classe de exemplo, a seção published não tem nenhum
efeito, sendo equivalente à public.

(* nota: esse esquema de controle de acesso só é válido para membros de Units diferentes. Se duas
classes estão na mesma Unit, elas têm acesso a todos os membros uma da outra e passam a ser “friend
classes”. Mas isso não é ruim? Depende. Às vezes podemos querer que várias classes e sub-rotinas
trabalhem em conjunto para alcançar seus objetivos. Assim, pode ser indispensável que elas possam ter
acesso total aos dados das outras. Mas se você não quer que isso ocorra, basta criar uma única classe
por Unit. *)

Vejamos agora quais são os membros de uma classe:

• Campos: São basicamente variáveis comuns pertencentes à classe onde cada objeto instanciado
contém uma cópia de cada campo. Por convenção, todo campo deve ter seu nome iniciado com a letra
“F” (significando field). representam os dados que o objeto deve armazenar. Na classe do exemplo
temos FCampo1 e FCampo2.
• Métodos: São procedures e functions pertencentes à classe. Eles representam as operações que o
objeto é capaz de realizar, ou seja, seus serviços. No exemplo são representados pela função Metodo1
e pelo procedimento Metodo2. Podem existir também métodos que existem especialmente para fazer
validações nos dados que são atribuídos a um campo antes que eles sejam efetivamente atribuídos ou
ainda modificar o dado lido do campo antes de chegar ao cliente do objeto. São eles a função
GetCampo2 (tratamento de leitura) e o procedimento SetCampo2 (tratamento de escrita). Pra quem

46
está familiarizado com Java, isso se parece com os famosos métodos de acesso set e get da
linguagem da Sun. Mas não se devem usar métodos de acesso em Delphi como se usa em Java. Em
Delphi eles são usados apenas para tratamento, enquanto que em Java eles também fornecem acesso
a campos, implementando o encapsulamento dos mesmos. Para fornecer acesso e implementar o
encapsulamento em Delphi, use propriedades.
• Propriedades: São estruturas responsáveis por fornecer acesso a campos do objeto e pelo
encapsulamento dos mesmos, podendo ocultar inclusive, os métodos de validação dos campos! Como
exemplos de propriedades temos a Propriedade1 e Propriedade2, sendo que a Propriedade1 acessa
diretamente os dados do FCampo1, enquanto que Propriedade2 acessa os dados do FCampo2 através
dos métodos de validação GetCampo2 e SetCampo2. As propriedades possuem as partes read e write,
que dizem a ela o que deve ser lido e o que deve ser escrito no membro que ela encapsula. Mas
podem existir propriedades somente de leitura (read-only) e somente de escrita (write-only), bastando
omitir uma destas partes.
• Construtores: São tipos especiais de métodos responsáveis pela criação dos objetos da classe e pela
inicialização dos seus campos. Por convenção, construtores Delphi são sempre chamados de Create
ou algo como “CreateAlgumaCoisa” ou então “CreateFazendoAlgumaCoisa”... mas sempre tendo o
Create como base. Quando criamos uma classe, os construtores da superclasse são herdados, mas
podem ser escondidos se declararmos outro construtor no mesmo nível de acesso, mesmo que tenha
assinatura diferente do original.
• Destruidores: São métodos responsáveis pela liberação dos recursos alocados por um objeto durante
sua existência. Como não existe um garbage collector no Delphi 7, todo objeto instanciado deve ser
manualmente liberado pelo destruidor. por convenção, os destruidores são chamados de Destroy ou
algo que tenha Destroy como base. Também existe um destruidor herdado definido na classe TObject,
que pode ser sobrescrito, usando a diretiva override. Atenção agora: o Create deve ser ocultado, mas o
Destroy deve ser sobrescrito com override. Isso porque Destroy é um método virtual, enquanto que
Create é estático (vamos deixar esse papo de estático e virtual para quando chegarmos a OO, certo?).

3.4.6. Referências de Classe (metaclasses)


Como o nome já diz, são referências para uma classe, e são usadas quando queremos invocar
métodos de classe ou construtores virtuais de um objeto cuja classe pode não ser conhecida em tempo de
compilação. o maior exemplo disso é o método Application.CreateForm do objeto global Application. Ele
recebe como argumentos uma referência para uma classe de formulário e a referência que vai receber a
nova instância de formulário. Este primeiro parâmetro é do tipo TFormClass que é uma referência para a
classe TForm, a classe raiz de todos os formulários. Assim, ao criar um novo formulário, o objeto

47
Application não precisa saber o tipo exato do formulário, porque ele será fornecido através da referência
TFormClass, através da qual ele será criado. Vamos ilustrar mostrando o dpr de uma nova aplicação:

Na Unit1 temos a declaração da classe TForm1, que herda de TForm e a variável Form1 do tipo
TForm1. No programa principal podemos ver o método Application.CreateForm em ação. Ele é capaz de
criar qualquer tipo de formulário graças ao TFormClass. Veja que passamos a própria classe TForm1
como argumento, assim como podemos passar qualquer classe descendente de TForm! Ao criar o objeto
TForm1, a referência será guardada na variável Form1 passada no 2º argumento.
A declaração de uma metaclasse é da forma TClasse = class of type, onde type é a classe cujo
tipo queremos referenciar. no caso do TFormClass temos: TFormClass = class of TForm.

3.4.7. Interfaces
Interfaces são como uma espécie de classe abstrata que fornece apenas declarações de métodos
para serem implementados por uma classe. Aí dizemos que a classe implementa a interface e é obrigada
a implementar todos os métodos que ela fornece.
No Delphi, a interface raiz é a “IInterface” (foi convencionado que todo nome de interface deve
começar com “I”), que possui 3 métodos: QueryInterface, _AddRef e _Release. Assim, toda interface
criada deve ser derivada de IInterface e assim terão estes 3 métodos. mas então, se eu criar uma interface
personalizada e implementa-la numa classe, vou precisar implementar estes métodos esquisitos? Não
necessariamente! Acontece que estes métodos já estão implementados numa classe chamada
TInterfacedObject. Assim, basta herdar sua classe de TInterfacedObject e implementar apenas a interface
personalizada, sem se preocupar com os 3 métodos esquisitos (afinal, herdaremos a implementação

48
padrão). Mas afinal, o que estes métodos fazem? Eles têm a ver com o controle do tempo de vida de
objetos referenciados por variáveis de interface. Estes objetos não precisam ser destruídos como os
objetos comuns, pois são controlados por contagem de referências. E quem controla isso são as
implementações destes métodos na TInterfacedObject.
Existem algumas restrições nas interfaces em relação às classes:

• Interfaces não podem ter campos, apenas métodos e propriedades.


• Já que não há campos, os parâmetros para as diretivas read e write das propriedades só podem ser
métodos.
• Interfaces não podem ter construtores nem destruidores. Afinal, não devem ser instanciadas.

• Métodos de interfaces não podem ter diretivas como virtual, dynamic, override e abstract. Como não
podem implementar seus próprios métodos, estas diretivas não fazem sentido nas interfaces (também
deixamos estas diretivas mais pra frente).
• Não podem haver seções private, public, etc. numa interface.

Em Delphi, as interfaces podem opcionalmente possuir um identificador global, chamado


GUID, representado por uma string da forma: ['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'], onde cada x é
um nº. hexadecimal, localizado imediatamente antes da declaração dos membros.
Mas pra que serve esse troço? Pra poder usar o typecast as entre um objeto e uma interface.
Lembra do método QueryInterface, que toda interface tem? Pois bem, ao fazer o teste “as” entre um objeto
e uma interface, o GUID da interface é passado ao método QueryInterface do objeto (desde que o objeto
implemente alguma interface) e ele vai dizer se o objeto implementa a interface em questão. Caso
implemente, o typecast é realizado; caso contrário, ocorre uma exceção.
Se você se assustou com o tamanho do GUID, ou ficou pensando em como fazer para saber se
ele é único ou não, fique tranqüilo! O Delphi gera os GUIDs pra você! Basta dar um Ctrl + Shift + G dentro
da declaração da interface e pronto! E lá vem o exemplo:

49
Primeiro criamos a interface “ITeste” que herda diretamente de Iinterface, a interface raiz do
Delphi. Ele possui um método “Método” e uma propriedade “Valor”, que possui seus dois “métodos de
acesso” SetValor e GetValor, que são necessários pois as interfaces não podem ter campos, apenas
métodos e propriedades que acessam métodos. O nº. esquisito logo abaixo da declaração é o tal do
GUID, que identifica a interface de forma única no ambiente Delphi e foi gerado automaticamente com o
comando Ctrl + Shift + G. Assim, podemos realizar typecasts com referências desta interface.
Abaixo, criamos uma classe chamada TTeste que implementa a interface ITeste. Repare que
herdamos TTeste de TinterfacedObject, ao invés de TObject para podermos herdar a implementação
padrão daqueles 3 métodos que vêem de Iinterface. Logo após informarmos que a superclasse será
TInterfacedObject, informamos que TTeste implementa ITeste separando por vírgula. O esquema é

50
sempre este: primeiro a superclasse e depois a lista das interfaces implementadas, tudo separado por
vírgulas (lembrando que não há herança múltipla no Delphi! Coloque apenas uma classe e depois quantas
interfaces quiser!). Dentro da classe, implementamos os métodos fornecidos pela interface, escolhendo a
visibilidade que bem entendermos para eles.

3.5. Comandos da Delphi Language


Depois de vermos operadores e tipos de dados, nada como estudar os comandos e estruturas de
controle do Delphi! Então vamos!

3.5.1. Comandos de Decisão


A Delphi Language possui como comandos de decisão o if, if..else e case, case..else. Os
comandos if e if..else possuem a seguinte sintaxe:

// if com uma única instrução


if <condições> then
código;

// if com várias instruções


if <condições>
then begin
código1;
código2;
end;

// if..else com uma única instrução cada


if <condições> then
código
else
código;

// if..else com várias instruções cada


if <condições>
then begin
código1;
código2;
código3;
end
else begin
código1;
código2;
end;

Vale observar que em Delphi não podemos pôr ponto-e-vírgula antes do else, pois ele considera a
construção if..else um único comando. Outra observação interessante diz respeito à precedência de
operadores dentro das condições. se fizermos a seguinte condição:
if a = b and c > d

51
o Delphi irá executar primeiro o “b and c”, devido à precedência dos operadores booleanos sobre os
relacionais. Para solucionar este probleminha é só agruparmos as condições que desejamos que sejam
verificadas primeiro com parênteses, assim:
if (a = b) and (c > d)

e pronto! As condições dos parênteses serão avaliadas primeiro e depois seus resultados serão operados
com o and.
Como o if permite apenas uma seleção, existe o comando case para dar suporte à seleção
múltipla. A sintaxes possíveis do case são as seguintes:

// case simples
case <expressão> of
valor1: comando1;
valor2: comando2;
valor3: comando3;
end;

// case simples com lista de valores


case <expressão> of
valor1, valor2: comando1;
valor3, valor4: comando2;
valor5: comando3;
end;

// case simples com várias instruções por valor


case <expressão> of
valor1:
begin
comando1;
comando2;
end;
valor2:
begin
comando1;
comando2;
end;
end;

// case com else


case <expressão> of
valor1: comando1;
valor2: comando2;
else
comando3;
comando4;
end;

A Expressão avaliada no comando case, ao contrário do que ocorre no if, não é exclusivamente
booleana, admitindo também uma expressão de tipo ordinal (lembre que tipos ordinais são aqueles cujos
valores têm uma ordem). Isso significa que a expressão avaliada pode assumir valores Integer, Char,
enumeração... entre outros (inclusive, Boolean é um tipo ordinal, assim podemos até dizer que a

52
expressão é sempre uma expressão de valor ordinal!). Mais uma coisa: note que o else do case não
necessita de begin..end como o do if. Ele é tratado como um bloco.

3.5.2. Comandos de Repetição


Em Delphi temos três estruturas de repetição: for (repetição por contador), while (repetição com
teste no início) e repeat (repetição com teste no final). Vejamos as sintaxes:

// for simples – contagem progressiva


for variável := valor_inicial to valor_final do
comando;

// for simples – contagem regressiva


for variável := valor_final downto valor_inicial do
comando;

// for composto – contagem progressiva


for variável := valor_inicial to valor_final
do begin
comando1;
comando2;
end;

// for composto – contagem regressiva


for variável := valor_inicial downto valor_final
do begin
comando1;
comando2;
end;

O comando for utiliza uma variável inteira simples e local como contador, que é inicializada e
incrementada pelo próprio comando. A contagem pode ser progressiva ou regressiva, bastando alterar do
para downto e vice-versa.

// while simples
while <condições> do
comando;

// while com múltiplas instruções


while <condições>
do begin
comando1;
comando2;
end;

O comando while avalia uma expressão booleana e executa os comando se ela for verdadeira.
Mas se for falsa, a repetição não é executada nenhuma vez, daí ele ser um comando com teste no início.

53
// repeat
repeat
comando1;
comando2;
comando3;
until
<condições>

O repeat é o comando de repetição com teste no final. Como conseqüência, seus comandos são
sempre executados pelo menos uma vez! Este é também um comando exótico em relação aos outros
dois, primeiro por causa da sintaxe, que não exige begin..end para múltiplas instruções (o repeat é um
bloco) e por causa do significado de seu teste de parada. O while executa sua repetição enquanto as
condições fornecidas forem verdadeiras. Já o repeat executa seus comandos até a condição se tornar
verdadeira!
Todos os comandos de repetição podem ser interrompidos quando for conveniente para o
programador através de duas instruções: o break e o continue. O break é usado quando se deseja sair
totalmente do corpo do comando de repetição e seguir a vida, enquanto que o continue apenas sai da
iteração atual, pulando para a próxima iteração, sem sair do comando de repetição.

3.5.3. Tratamento de Exceções


Existem dois comandos utilizados para fazer tratamento de exceções em Delphi: o try..except e o
try..finally.
O bloco try..except tem as seguintes possibilidades:

// try..finally com exceção qualquer


try
comando1;
comando2;
except
comando3;
comando4;
end;

// try..except capturando exceções específicas


try
comando1;
comando2;
except
on exceção1 do
comando3;
on exceção2
do begin
comando4;
comando5;
end;
end;

54
// try..except re-disparando uma exceção
try
comando1;
comando2;
except
on exceção1 do
raise;
end;

O bloco try..except é utilizado para executar uma lista de comandos e capturar as exceções que
acontecerem nestes comandos para que sejam tratadas, possibilitando que o programa se recupere e
continue a executar. No 1º caso, vimos um try..except que executa seu bloco de tratamento except para
qualquer que seja a exceção disparada. No segundo exemplo, vemos um bloco que captura exceções
específicas e dá tratamento individualizado a cada uma delas (que é o jeito ideal de se fazer o tratamento).
Por fim temos o tratamento de exceção do tipo “batata-quente”, onde um determinado tipo de exceção não
vai ser tratado localmente, e sim pela rotina que está um nível acima, ou seja, aquela que chamou esta
onde está o try..except. O comando raise se encarrega de re-disparar a exceção capturada para que seja
tratada em outro lugar. Aliás, a instrução raise pode ser usada em qualquer lugar do código, não apenas
no bloco except, para disparar exceções quando alguma condição não for especificada. Exemplo:

if not <condição> then


raise Exception.Create(‘Condição inválida!’);

Este código dispara uma exceção do tipo Exception (a “mãe” de todas as exceções Delphi) sempre
que <condição> for falsa.
Quanto ao bloco try..finally, seu uso é indicado principalmente para garantir que um determinado
recurso alocado pelo programa seja liberado, aconteça o que acontecer. Por exemplo, se você instancia
um objeto, ele deve ser liberado manualmente (não temos garbage collector), mas se houver uma exceção
antes que o código de liberação seja executado, o objeto continuará vagando pela memória, ocupando
espaço e gastando recursos da máquina! Mas se o protegermos o código que utiliza o objeto com o bloco
try e colocarmos o código de liberação no finally, ele garantirá que o objeto será liberado de qualquer jeito,
com ou sem exceções! Outro uso pode ser o fechamento de arquivos, ou fazer o cursor voltar ao normal
(pro caso de o mudarmos e ocorrer uma exceção que o manteria modificado, como ficar eternamente com
a ampulhetinha...). A sintaxe de um bloco try..finally é:

try
comando1;
comando2;
finally
comando3;
comando4;
end;

55
3.5.4. O Comando with
Quando trabalhamos com objetos ou registros, usamos o operador ponto para acessar seus
campos ou propriedades. Mas, se a lista de propriedades que temos que manipular for muito grande,
acessa-las repetindo sempre o nome do objeto torna-se meio trabalhoso, mesmo dispondo de code
completions e Ctrl + C. É aí que entra o comando with! Ele permite colocar em evidência a parte dos
nomes dos objetos e assim escrevemos somente as propriedades finais. Vamos vê-lo em ação:

// trecho de código sem with


Form1.Font.Style := [fsBold];
Form1.Font.Color := clNavy;
Form1.Font.Name := 'MS Sans Serif';
Form1.Font.Size := 10;

// o mesmo código com with


with Form1.Font
do begin
Style := [fsBold];
Color := clNavy;
Name := 'MS Sans Serif';
Size := 10;
end;

Prático, não? Colocamos a parte “Form1.Font” em evidência e assim digitamos apenas a parte
variável do código! Mas não devemos ficar muito entusiasmados com este comando, pois junto com a
praticidade vêm os problemas...
O primeiro problema que torna o uso do with não recomendado é a questão da legibilidade. Dê
uma olhada no código abaixo:

with Memo1
do begin
Line := Perform(EM_LINEFROMCHAR, SelStart, 0);
Column := SelStart - Perform(EM_LINEINDEX, Line, 0);
Label1.Caption := IntToStr(Line + 1);
Label2.Caption := IntToStr(Column + 1);
end;

Agora responda: o que é “SelStart”? Uma variável? Uma função? Uma propriedade do Memo1? O que são
“Line” e “Colunm”?
Esse é o problema; o with torna o código fonte mais confuso para o leitor, pois fica difícil de
determinar a quem pertencem os elementos referenciados, apesar de poupar o trabalho do escritor...
Mas o pior defeito do comando with é esconder os valores das expressões dos debuggers do
Delphi. Portanto, se usar with você não poderá ver os valores das variáveis ao parar a execução do
programa com Break Point. E também não adianta apelar para Whatches ou Evaluate/Modify... nada
consegue acessar estes valores!

56
Por isso, os prejuízos que conseguimos com este comando acabam se tornando maiores que seus
benefícios e seu uso é desencorajado.

3.6. Variáveis e Constantes


Vejamos como são as declarações de variáveis e constantes no Delphi. Primeiramente, devemos
saber que todas as variáveis devem ser declaradas dentro de uma seção var e as constantes dentro de
uma seção const. A sintaxe geral de uma declaração de variáveis ou constantes é:

// declaração de variáveis
var
// simples
Numero: Integer;
// lista
Palavra1, Palavra2, Palavra3: String;
// inicializando na declaração
OutroNumero: Integer = 0;

// declaração de constantes
const
// true constants
ConstanteInteira = 10;
ConstanteString = ‘Texto constante’;
ContanteExpressao = 30 + (25 mod 2);

// typed constants
MaisUmNumero: Integer = 100;
OutraString: String = ‘Nada Não!’;
Nums: array[0..9] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');

Podemos declarar variáveis de três deferentes modos, sem complicação: o simples, a listagem de
variáveis de mesmo tipo e a declaração com inicialização, conforme os exemplos acima, mas a declaração
com inicialização só funciona em variáveis globais (nas locais dá erro de compilação!) e não é permitida a
inicialização em lista (inicializar várias variáveis ao mesmo tempo com o mesmo valor).
Quanto às constantes, existem dois tipos: as “true constants” e as “typed constants”. As true são
constantes declaradas sem o tipo, que fica implícito no valor atribuído a elas e não suportam valores de
tipos estruturados. Já as typed possuem o tipo definido explicitamente, podendo ser de tipos estruturados
(como o array constante “Nums” do exemplo).
Os valores atribuídos a qualquer constante podem ser tanto valores simples e diretos quanto
expressões mais elaboradas.

3.7. Procedimentos e Funções


Os procedimentos e as funções são as sub-rotinas do Delphi, e tanto podem ser métodos de
classes ou interfaces como também podem pertencer apenas à Unit. A diferença entre estes dois tipos de
sub-rotinas é que as funções têm um valor de retorno, enquanto que os procedimentos não.

57
3.7.1. Declarando Procedimentos e Funções
Os formatos gerais de declarações de procedimentos e funções são os seguintes:

// declaração geral de procedimento


procedure Nome_do_procedimento(Lista_de_parametros); Diretivas;
Declarações_locais;
begin
Instruções;
end;

// declaração geral de função


function Nome_da_função(Lista_de_parametros): Tipo_de_retorno; Diretivas;
Declarações_locais;
begin
Instruções;
Retorno_do_valor;
end;

Nas declarações acima, “Declarações_locais” são as variáveis, constantes, tipos de dados (sim,
pode-se declarar tipos de dados locais!) e outras sub-rotinas locais (podemos declarar funções e
procedimentos dentro de outras funções e procedimentos!). “Diretivas” são diretivas(oh!) que possuem
diversas funcionalidades como convenções de chamada, declarações externas... etc. que não serão
abordadas aqui (quem quiser se aprofundar pode consultar o help do Delphi que é muito bom!), por quase
nunca serem usadas em situações comuns de programação. Mas algumas destas diretivas são
importantes como a override que foi apresentada na parte sobre classes e a overload que veremos daqui
a pouco. “Instruções” são as instruções(oh!) que devem ser executadas pela sub-rotina. “Tipo_de_retorno”
é o tipo de valor que a função retorna (String, Integer...). “Retorno_do_valor” é a instrução que atribui um
valor à função para que este seja retornado por ela. Existem duas maneiras de atribuir o valor de retorno à
função, pelo nome da função ou pela variável de retorno Result. Na primeira forma, para fazermos a
função retornar um valor pelo nome, fazemos:
Nome_da_função := Valor;
e da segunda forma, com a variável de retorno Result, fazemos:
Result := Valor;
Result é uma espécie de variável interna que toda função Delphi possui e que não precisa ser declarada,
bastando atribuir diretamente. Result sempre é do mesmo tipo de retorno da função.

(* nota: Ao contrário do que ocorre na instrução return do Java por exemplo, a execução do programa não
sai da função ao atribuirmos o resultado a ela em Delphi, ou seja, se você atribuir um valor ao result mas
ainda houverem instruções depois, todas elas serão executadas. A função só retorna o valor após
executar todas as suas instruções *)

58
A lista de parâmetros merece uma atenção especial. Primeiramente, podemos declarar os
parâmetros da mesma forma que declaramos variáveis: simples, lista e com inicialização (aqui chamado
do parâmetro com valor default).
Parâmetros simples não têm segredo (são separados com ponto-e-vírgula):
procedure P(Parametro1: Integer; Parametro2: String);

Agora com lista (os de mesmo tipo são separados com vírgula e os de tipos diferentes são separados com
ponto-e-vírgula. Agrupar parâmetros de mesmo tipo em lista é opcional):
procedure P(Parametro1, Parametro2: Integer; Parametro3: String);

Com default (se nada for passado como argumento, assume o valor da inicialização):
procedure P(Parametro1: Integer; Parametro2: Boolean = True);

E agora sem parâmetros (veja que não é necessário colocar parênteses vazios em Delphi):
procedure P;

Estas regras são as mesmas para funções.


Para executar procedimentos e funções, basta chama-los pelo nome. Se eu tenho um procedure
P(A: Integer; B: Boolean); só precisamos fazer P(100, True); para chamá-lo! O mesmo valendo
para funções, só que elas têm um valor de retorno que pode ser ou não atribuído a alguma variável ou
testado em comandos de decisão e repetição.
Podemos sobrecarregar sub-rotinas em Delphi utilizando a diretiva overload mencionada acima.
Exemplos de rotinas sobrecarregadas:

procedure P; overload;
procedure P(I: Integer); overload;
procedure P(S: String; B: Boolean); overload;

É só isso! Basta que eles tenham o mesmo nome, mas com listas de parâmetros diferentes, e a diretiva
overload em cada versão sobrecarregada.

4. Componentes

A programação típica em Delphi é bastante centralizada na adição e configuração de componentes


da Palheta de Componentes no Form Designer. Então, vamos ver alguns conceitos e propriedades
básicas dos componentes.

59
4.1. Relacionamentos entre Componentes
Existem dois relacionamentos comuns entre componentes: O relacionamento Parent e o
relacionamento Owner.
O relacionamento Parent, que só vale para componentes visuais, indica quem é o contêiner (o
Parent) de um componente. O Parent ou contêiner é responsável pelo alinhamento visual de seus
componentes.
Já o relacionamento Owner (proprietário) é uma facilidade para a destruição de objetos criada
em tempos de ausência de garbage collector! Quando um componente é Owner de outros, significa
que quando ele for destruído, todos os componentes que são propriedade dele também serão! Numa
aplicação comum, o Owner de todos os componentes costuma ser o formulário. Dessa forma, quando
o Form é destruído, todos os outros componentes são destruídos junto com ele!

4.2. Propriedades e Eventos Comuns


Os componentes são objetos que estão numa vasta hierarquia de classes. A classe básica de
um componente é TComponent, onde estão definidas características básicas que todo componente,
visual ou não deve ter.
Por terem uma origem comum, muitos componentes apresentam propriedades, eventos e
métodos comuns. Por isso, antes de vermos componentes de forma mais específica, é bom que
conheçamos estes elementos comuns, e que são também frequentemente utilizados.
Entre as propriedades mais corriqueiras, podemos destacar:

• Action: Torna um componente cliente de um componente TAction, que será visto mais a frente.
• Anchors: Servem para manter constantes a posição dos lados de um componente quando a
janela é redimensionada.
• TabOrder: É a ordem em que os componentes vão ganhando foco à medida que a tecla Tab é
pressionada.
• TabStop: Define se o componente vai ou não receber o foco ao se pressionar Tab. Se esta
propriedade for falsa, TabOrder não tem efeito.
• Name: É o nome do componente. É usado pelo Delphi para criar as referências para os
componentes adicionados ao Form Designer.
• Hint: Usada para exibir uma dica sobre o componente ao pararmos o mouse sobre ele.
• ShowHint: Ativa ou desativa a exibição do hint.
• Height e Width: Altura e largura do componente.

60
• Left e Top: São as coordenadas do canto superior esquerdo do componente em relação ao seu
Parent. Left é a coordenada X e Top a Y, e são medidas a partir do canto superior esquerdo do
Parent.
• Visible: Torna o componente visível ou invisível.
• Enable: Desabilita ou habilita o componente. Quando desabilitado, ele continua visível, mas o
usuário não pode interagir com ele.
• ReadOnly: Todo componente que contém um texto ou valor que pode ser editado possui esta
propriedade, que define se este valor pode ou não ser editado. se ReadOnly for True, o valor é
apenas para leitura – não pode ser mudado pelo usuário.
• Align: Contém alinhamentos pré-definidos para componentes visuais, fazendo com que eles
ocupem totalmente um dos lados do Parent (top, bottom, left ou right).
• Ctrl3D: Controla a tridimensionalidade. se estiver falsa, o componente se torna bidimensional.
• Caption: Muitos componentes possuem esta propriedade que apenas exibe neles um texto fixo,
ao qual o usuário não tem acesso.
• Font: É a fonte que será usada nas propriedades de texto do componente, como a Caption.
Porém, para a classe TForm, Font é usada para dar uma fonte padrão aos componentes
colocados no formulário, que automaticamente ajustam suas fontes para ela.
• Color: É a cor de fundo do componente.

Agora, os eventos mais populares:

• OnClick: Ocorre quando o componente é clicado (não diga!).


• Eventos de mouse: Os eventos de mouse são OnMouseMove, OnMouseDown e OnMouseUp e
embora se pareçam com o click, são mais específicos para tratamento de mouse. OnMouseMove
ocorre quando o mouse passa sobre um componente. Recebe como argumentos, além do famoso
Sender, as coordenadas do mouse e o ShiftState (estado das teclas shift, ctrl, alt e o estado dos
botões do mouse). OnMouseDown é chamado quando o botão do mouse é pressionado, ou seja,
quando ele desce. Recebe como argumentos a posição do mouse, o botão do mouse que foi
clicado, além do ShiftState. OnMouseUp é Idêntico ao mouse down, só que é disparado quando o
usuário solta o botão do mouse.
• Eventos de teclado: São OnKeyPress, OnKeyDown e OnKeyUp. OnKeyDown e OnKeyUp
possuem a mesma idéia dos eventos de mouse de mesmo nome e são indicados para tratar teclas

61
como enter, esc, delete, F1, F2, direcionais... etc. as chamadas “teclas virtuais”, que não
representam caracteres. Para tratar teclas de caracteres, é indicado u uso do OnKeyPress.
• OnEnter: Ocorre quando um componente recebe o foco.
• OnExit: Oposto do OnEnter. É chamado ao perder o foco.
• OnChange: Alguns componentes possuem este evento que é chamado sempre o estado do
componente muda. Mas cada um tem sua própria versão desta mudança.

4.3. Componentes mais Usados


Veremos agora alguns dos componentes usados mais frequentemente na programação em
Delphi e conheceremos suas propriedades e eventos mais significativos.

4.4. TForm
Os componentes da classe TForm são os formulários sobre os quais incluímos outros
componentes e através do qual criamos a telas da aplicação. Suas propriedades mais importantes
são:

• BorderIcons: Configura a presença dos botões de maximizar, minimizar, fechar e help ao


configurar cada uma como True ou False.
• BorderStyle: Configura o estilo da borda do formulário. Seu uso mais típico é para impedir que o
usuário redimensione o formulário, alterando seu valor para bsSingle (o padrão é bsSizeable, que
permite que o usuário ajuste o tamanho da janela em tempo de execução).
• Icon: Sobrescreve o ícone padrão definido em Application do Project Options e o exibe no canto
superior esquerdo do Form.
• Menu: Associa o Form a um objeto TMainMenu, que será o menu daquela tela.
• Position: É a posição na qual o Form vai aparecer na tela ao ser mostrado. Seu valor padrão é
poDesigned, que indica que ele será mostrado onde foi deixado em tempo de projeto. Em
situações normais deve ser configurada como poScreenCenter para que o Form seja mostrado no
centro da tela, independente de onde ele estava durante o projeto.
• WindowState: É o estado da janela ao ser mostrada. O padrão é o valor wsNormal, em que ela
fica normal, no tamanho em que foi projetada. Mas pode mudar para maximizada (típico para o
form principal da aplicação) ou minimizada se mudarmos seu valor para wsMaximized ou
wsMinimized.

62
Os eventos mais utilizados de um objeto TForm são os seguintes:

• OnActivate: Ocorre quando o Form se torna ativo.


• OnClose: Ocorre quando o Form é fechado.
• OnCloseQuery: Este evento ocorre imediatamente antes de fechar o Form e é usado para decidir
se ele realmente tem permissão para fechar ou não, através do parâmetro CanClose. Se o
programador definir que o formulário não pode ser fechado se uma determinada operação ainda
está pendente (um arquivo não salvo por exemplo), basta definir CanClose para False;
• OnCreate: Este evento é chamado pelo construtor do Form como parte do processo de
instanciação. É usado para inicializar valores de propriedades, campos, propriedades de
componentes, etc.
• OnDeactivate: É o oposto do OnActivate, ocorrendo ao desativar a janela.
• OnDestroy: Evento chamado pelo método destruidor do Form, usado para liberar recursos
alocados por ele (destruir objetos globais, fechar arquivos...).
• OnShow: Ocorre imediatamente antes do Form ser exibido na tela.
O Form possui também alguns métodos bastante usados:

• Show: Mostra o formulário.


• ShowModal: Faz o mesmo que show, só que neste caso o Form não permite que outras telas do
sistema sejam ativadas enquanto ele não for fechado. ShowModal é uma função que retona um
valor inteiro que pode ser testado quando ele se fecha.

4.5. Botões
Temos 3 componentes que representam diferentes tipos de botões, cada um com suas
funcionalidades especificas. São eles o TButton, TBitBtn e o TSpeedButton.
Eles possuem propriedades comuns, que veremos agora:

• Cancel: Se for verdadeira, clica o botão automaticamente ao pressionar a tecla Esc. Não está
presente no SpeedButton, pois ele não responde ao teclado.
• Default: Clica o botão automaticamente ao pressionarmos a tela Enter, quando está True. Assim
como Cancel, não está no SpeedButton pela mesma razão.

63
Agora vamos dar uma olhada no TBitBtn. O maior diferencial deste botão em relação ao
TButton é o suporte à imagens, o que significa que podemos colocar um ícone nele, através da
propriedade Glyph. Outras propriedades existem em função deste ícone: Margin e Spacing, que
controlam respectivamente a margem que deve ser respeitada antes do glyph e o espaço entre o
glyph e o caption. Há também a propriedade layout que informa a posição do glyph (à esquerda,
direita, acima ou abaixo em relação ao caption). Estas três propriedades estão também no
TSpeedButton.
O botão do tipo SpeedButton é diferente dos outros. Ele não pode ser acessado por
tabulações como os outros e não pode receber foco, comportamento encontrado em botões de barras
de ferramentas por exemplo. Possui uma propriedade exclusiva entre os botões, a Flat, que quando
verdadeira, esconde o contorno do botão até que o mouse passe sobre ele.

4.6. O Label
Componente usado para criar um rótulo, tipicamente usado com edits. Um Label não pode
receber foco nem pode ser editado em tempo de execução. Sua funcionalidade básica se restringe a
exibir um texto pela propriedade Caption. Possui também a propriedade FocusControl, que faz com
que o controle referenciado por ela receba o foco, se o Caption do Label estiver com configurado com
um atalho Alt + tecla, configurado com um “&” antes do caractere que servirá de tecla de atalho junto
com Alt.

4.7. Os Edits
São os componentes tipo caixa de texto de uma única linha onde o usuário pode digitar um
texto qualquer. O Delphi fornece 3 edits básicos: TEdit, TMaskEdit, TLabeledEdit.
Algumas propriedades comuns entre eles são:

• MaxLength: Nº. máximo de caracteres que podem ser digitados


• PasswordChar: Caractere que será exibido para esconder o texto real do edit ao digitar (usado
para colocar o “*” em campos de senha, daí o nome PasswordChar!).
• CharCase: Define se o texto digitado vai estar sempre em maiúsculas, minúsculas ou normal
(permitindo tudo).
• Text: É o texto digitado no edit.

O MaskEdit é um edit especial, cujo Text pode ser formatado usando máscaras, com a

64
propriedade EditMask. Basta utilizar o editor de mascaras que não tem mistério! Já o LabeledEdit é
um edit que já vem com um Label embutido, que agiliza ainda mais a criação de telas. A propriedade
EditLabel permite configurar as propriedades do Label embutido. de novidade só temos as
propriedades LabelPosition e LabelSpacing, que controlam a posição (esquerda, direita, acima e
abaixo) e a distância do Label interno em relação ao edit.
4.8. O Painel
Um painel é um componente do tipo TPanel, que é um contêiner para outros componentes. è
usado para organizar o layout do Form, agrupando componentes, portanto suas funcionalidades se
restringem ao projeto na maioria dos casos. Sus propriedades mais usadas são as que controlam a
aparência das bordas:

• BevelInner: Controla o layout da borda interna.


• BevelOuter: Manipula a borda externa.
• BevelWidth: É o tamanho das bordas.

Seus valores definem se a borda será “pra fora” (raised), “pra dentro” (lowered) ou nehuma.
Pode-se criar efeitos interessantes combinando de formas diferentes as bordas do Panel.

4.9. Barra de Status


O componente TStatusbar é o responsável por representar as barras de status, bastante
comuns em diversos tipos de programas. Na realidade, o mérito não está na StatusBar em si, mas na
propriedade Panels. É nos painéis que criamos dentro da StatusBar que inserimos os textos que ela
exibe. Os TStatusPanel têm como propriedades mais legais:

• Alignment: É o alinhamento do texto do painel (esquerdo, direito ou centralizado)


• Bevel: Se o painel terá visual “raised” ou “lowered”, como um Tpanel
• Text: O texto que será exibido no StatusPanel.

A StatusBar pode ser usada sem os StatusPanels (ativando a propriedade SimplePanel, e


preenchendo a propriedade SimpleText), mas aí adeus alinhamento e adeus bevel.

4.10. RadioButton

65
O RadioButton é um componente usado para implementar uma seleção onde as opções são
mutuamente exclusivas, ou seja, o usuário só pode marcar um valor.
O estado do RadioButton pode ser lido através da propriedade Checked, que é True se ele
estiver marcado e False caso contrário.
Fato curioso é que se houverem vários RadioButtons no mesmo parent, eles assumen
automaticamente o comportamento de mútua exclusão, sem precisar de nenhuma programação!

4.11. CheckBox
Assim como o RadioButton, serve para implementar seleções, mas com a CheckBox o usuário
pode marcar várias opções ao mesmo tempo. Também possui a propriedade Checked, que guarda
seu estado, exatamente como o RadioButton.

4.12. RadioGroup
Usado para simplificar a criação de vários RadioButtons agrupados. Nele, cada RadioButton é
tratado como uma linha editada na propriedade Items. Para saber qual deles está selecionado,
usamos a propriedade ItemIndex, que começa no Item 0 e termina no Item n-1 (para que nenhum
item seja marcado, configure ItemIndex como -1).
Quanto à organização dos RadioButtons em seu interior, o Radiogroup costuma colocar um
por linha, o que nem sempre fica bonito... Para resolver este impasse, basta configurar a propriedade
Colunms para o número de colunas desejado!

4.13. ComboBox
As ComboBoxes são como Edits com uma lista embutida que se abre ao clicarmos no botão
com a setinha à direita. Vamos ver suas propriedades mais manjadas:

• Items: Igual à Items do RadioGroup, é a lista dos itens que aparecerão na lista quando o botão for
pressionado.
• ItemIndex: Também é como à do RadioGroup, retornando o índice do item da lista que está
selecionado. Se não há itens selecionados, ItemIndex assume o valor -1.
• DropDownCount: Número máximo de itens que aparecerão na lista suspensa. Se o número de
itens for maior que o valor de DropDownCount, uma barra de rolagem aparece.
• Sorted: Se esta propriedade for habilitada, os itens serão ordenados.
• Style: Determina o estilo do display da ComboBox. Serve principalmente para controlar se ela é
editável (csDropDown) ou se serve apenas para seleção (csDropDownList).

66
• Text: É o texto do elemento corrente.

4.12. MainMenu e MenuItem


O MainMenu é o componente que representa a barra de menu de um formulário e serve como
contêiner para os objetos MenuItem, que são os menus propriamente ditos. Os MenuItem são
componentes que não aparecem na paleta de componentes e só podem ser criados em tempo de
projeto através da propriedade Items do MainMenu, que abre o editor “Menu Designer”, que permite
criar os MenuItems facilmente, apenas usando as setas e o clique com botão direito, onde estão
algumas funcionalidades como “Create Sub-Menu”, que cria um sub-menu de um MenuItem na
lateral, iniciando um outro ramo.
Existe um tipo especial de item, o separador, que é uma linha que separa outros itens. Para
criar um separador, basta colocar um “-” no Caption. Algumas propriedades importantes do MenuItem
são:

• Checked: Cria um menu de checagem, igual ao do “Quebra automática de linha” do bloco de


notas
• RadioItem: quando habilitada em vários MenuItems, cria neles comportamento de RadioButtons,
ou seja, a seleção de exclusão mútua.
• Bitmap: Coloca uma imagem no menu, como as do menu do Delphi
• ShortCut: Cria um atalho de teclado para o menu, que pode ser acionado sem abri-lo, como o
Salvar do bloco de notas Ctrl + S.
• ImageIndex: É uma outra forma de colocar imagens nos menus, que ao invés de selecionar um
bitmap diretamente, trabalha em parceria com um componente ImageList, que guarda uma lista de
imagens. ImageIndex é o índice de cada imagem guardada no ImageList, que será visto mais a
frente. A image list é associada ao MainMenu, através da propriedade Images.

4.13. PopupMenu
Componente usado para implementar menus estilo pop-up (não diga!), que aparecem quando
clicamos com o botão direito. A criação de itens é idêntica à do MainMenu.

4.14. Toolbar
É o componente usado para criar barras de ferramentas. Sua propriedades mais usadas são:

67
• ButtonHeight e ButtonWidth: Controlam a altura e a largura dos botões adicionados na barra.
• Customizable: Se estiver ativa, permite que o usuário modifique a barra de ferramentas em tempo
de execução, de duas formas diferentes: com duplo click, chamando o diálogo de customização
(semelhante ao do Internet Explorer) ou segurando a tecla Shift, o que permite que os botões
sejam arrastados para outras posições ou para fora da barra, o que os exclui.
• ShowCaptions: Se estiver True, exibe os Captions dos botões.
• Flat: Faz com que os botões fiquem sem borda até que o mouse passe sobre eles. Se flat é False,
os botões ficam sempre com borda (o que dá à aplicação um aspecto de programa antigo!).
• Images: Associa a Toolbar com um objeto ImageList, para que as imagens contidas nele possam
ser colocadas nos botões.

Os botões colocados na Toolbar são um tipo especial de botão, da classe TToolButton, e


podem ser adicionados à barra de ferramentas clicando com o botão direito e escolhendo “New
Button”. O ToolButton pode assumir a forma de um separador, se adicionarmos “New Separator”, ou
então mudando sua propriedade Style para tbsSeparator. As principais propriedades dos ToolButtons
são:

• Style: Como já foi mencionado, controla o estilo do botão, tipicamente entre tbsButton e
tbsSeparator. Mas há outras possibilidades, dentre as quais se destaca a tbsDropDown, usada
para fazer um ToolButton como o Run do Delphi, que tem um menuzinho abaixo! Para se usar
este estilo, devemos preencher a propriedade DropdownMenu.
• DropdownMenu: Associa o ToolButton a um PopupMenu, criando assim a listinha que surge
quando o ToolButton é criado.

4.15. ImageList
Chegou a hora de falarmos a respeito da tão comentada ImageList, que já deu as caras nos
tópicos sobre menus e Toolbar. Este componente guarda uma lista de imagens para compartilhar
com outros componentes, principalmente com Menus e barras de ferramentas, que a referenciam a
ImageList pela propriedade Images, e depois por ImageIndex obtém uma das imagens armazenadas
nela.
Normalmente não se configura nenhuma propriedade da ImageList, apenas adicionamos
imagens a ela, dando um duplo click para chamar o editor, que faz as operações de adicionar excluir
ou mudar as imagens. Não há complicações para usá-lo!

68
4.16. ActionList e Actions
Sem dúvida são dois dos componentes mais interessantes e importantes do Delphi! A
ActionList é apenas um contêiner para as Actions, os componentes que realmente fazem todo o
trabalho.
Com eles, é possível centralizar funcionalidades e propriedades que são compartilhadas entre
vários componentes, chamados de clientes das Actions.
A Aplicação típica destes componentes é manter a consistência entre o menu da aplicação e a
barra de ferramentas, já que a Toolbar é só um atalho para as funcionalidades disponíveis no menu,
os dois objetos acabam tendo elementos em comum, tanto no que diz respeito à funcionalidade
quanto também às figuras, captions, hints, enable, atalhos de teclado, etc. Em outras palavras, se
temos um menu que salva um arquivo, cujo ícone é um disquete, o hint e o caption são “Salvar”, o
atalho de teclado é Ctrl + S e fica desabilitado se o arquivo já foi salvo, vamos querer que o botão
correspondente na barra de ferramentas tenha as mesmas características e funcionalidade, certo?
Para não termos que configurar os dois separadamente e manter a consistência do enable “no
braço”, usamos a ActionList para centralizar todas estas características em componentes Action e
então, configuramos tanto o item de menu quanto o tool button para serem clientes da mesma Action
de salvar. Pronto! Os clientes automaticamente assumem as propriedades definidas na Action, bem
como o evento de salvar!
Na ActionList, a única propriedade utilizada efetivamente na prática é a Images, que a associa
com um objeto ImageList. Com isso, as Actions contidas nela podem acessar cada imagem pelo
ImageIndex.
Para criarmos as Actions que estarão contidas na ActionList, basta dar um duplo click nela
para abrir o editor. Com ele, podemos criar dois tipos de Actions, as Standard e as comuns. Standard
Actions são componentes descendentes de TAction que já possuem funcionalidades prontas de
várias categorias diferentes. Antes de pensar em criar uma Action do zero, dê uma olhada nas
Standard... quem sabe ela já não está lá prontinha, esperando por você! (é aquela velha história de
não reinventar a roda...).
As funcionalidades de uma Action devem ser implementadas no evento OnExecute. Depois,
no componente cliente, este evento deve ser associado ao evento adequado (no caso dos menus,
Toolbuttons e Botões comuns, OnExecute é automaticamente associado ao evento OnClick, mas ele
pode ser associado a qualquer outro evento do tipo TNotifyEvent, como vimos na parte sobre tipos
procedurais)

69
Moral da história: nada de configurar captions, bitmaps, hints, etc. de menus e barras de
ferramentas. Apenas crie os MenuItens e os Toolbuttons, associe a ImageList e faça a propriedade
Action referenciar a Action correspondente que ela faz o resto! E em tempo de execução, para mudar
o enable do menu salvar e do botão salvar do nosso caso hipotético, mude o enable apenas na
Action de salvar e pronto! O enable de todos os clientes dela muda junto!

4.17. Diálogos
Os diálogos são os componentes que encapsulam os principais diálogos do Windows, como o
diálogo de abertura de arquivos, salvamento de arquivos, diálogo de impressão, de fonte, de cores...
todos estão lá!
O método central de um diálogo é o Execute, usado para abrir a janela do diálogo para que o
usuário interaja com ele. O método execute é uma função booleana que retorna True se o usuário
confirmou a operação executada pelo diálogo, clicando no botão OK. Se o usuário desistir da
operação clicando em cancelar, Execute retorna False. Desta forma podemos testar este retorno e só
implementar nosso código quando o usuário realmente confirmar a operação. A seguir temos uma
visão geral de alguns diálogos:

• OpenDialog: Componente que representa o diálogo de abertura de arquivos: Suas propriedades


mais importantes são:
o DefaltExt: É a extensão padrão que é adicionada ao nome do arquivo que queremos
abrir, caso estejamos digitando e a extensão não for fornecida. Não é necessário
colocar o ponto no valor da propriedade.
o Filename: Guarda o nome do arquivo selecionado para a abertura ou que foi aberto.
o Filter: Permite filtrar os tipos de arquivo que queremos que apareçam no diálogo.
Possui um editor onde especificamos o nome do filtro (tipo “Arquivos de texto” ou
“Imagens JPEG”). O filtro é escrito na forma “*.txt” ou “*.jpeg” por exemplo. Para exibir
todos os tipos de arquivo, faça um filtro do tipo “*.*”.
o FilterIndex: Cada filtro criado em Filter recebe um índice, de 1 a n. FilterIndex define o
índice do filtro que estará ativo.
o InitialDir: Define o diretório inicial que aparece quando o diálogo é aberto.
o Title: É o texto que vai aparecer no caption do diálogo.
o Options e OptionsEx: Estas extensas propriedades fornecem diversas opções de
configuração para o diálogo, mas que raramente são usadas. Por isso, não as

70
discutiremos aqui (devido também ao grande número de opções disponíveis,
perderíamos muito tempo para discuti-las e não são tão complicadas de entender).
• SaveDialog: Diálogo para salvar arquivos. Possui as mesmas propriedades do OpenDialog,
mudando apenas a função de abrir para salvar. Não tem mistério!
• OpenPictureDialog e SavePictureDialog: Idênticos aos dois anteriores, porém espacializados
em arquivos de imagens.
• FontDialog: É o diálogo de fontes. Tudo nele gira em torno da propriedade fonte, onde é guardada
a fonte selecionada e onde configuramos a fonte na qual ele vai abrir.
• ColorDialog: Diálogo de cores. Sua principal propriedade é Color, de onde obtemos a cor
selecionada pelo usuário e através da qual configuramos a cor inicial no momento de abertura do
diálogo.
• PrinterSetupDialog: É o diálogo de configurações da impressora. Não tem nenhuma propriedade
interessante; todas as suas funcionalidades só surgem em execução, no diálogo propriamente
dito.
• PrintDialog: Diálogo que configura propriedades da impressão, como número de cópias por
exemplo.
• PegeSetupDialog: É o diálogo onde se configura as características das páginas, como o tamanho
das margens e tamanho do papel por exemplo.
• FindDialog e ReplaceDialog: São os diálogos que permitem a localização e a substituição de
trechos de um texto. Só que os diálogos, ao contrário do que possa parecer, não possuem as
funcionalidades de localização e substituição; é o programador que deve fazer estas operações
por código! Os diálogos servem apenas para coletar aquilo que o usuário deseja fazer (que texto
deverá ser localizado/substituído; se a busca irá diferenciar maiúsculas e minúsculas; se deve
buscar apenas palavras inteiras, etc.). Então, a partir dos valores armazenados em suas
propriedades, desenvolve-se o código que irá fazer aquilo que o usuário solicitou. As propriedades
utilizadas são:
o FindText: O texto a ser localizado.
o ReplaceText: Pertence ao ReplaceDialog e é o texto pelo qual o FindText dele deverá
ser substituído.
o Options: Guarda as opções de pesquisa definidas pelo usuário num Set, no qual
podemos testar se uma determinada opção está presente – pesquisar apenas palavras
inteiras é frWholeWord, diferenciar maiúsculas e minúsculas é frMatchCase, e assim
por diante.

71

Você também pode gostar