You are on page 1of 26

http://www.geocities.

com/WallStreet/Exc
hange/1726/computing/delphi/delphi_3.ht
m

2. FUNDAMENTOS DO OBJECT PASCAL


O Pascal é uma linguagem surgida a partir de um projeto experimental do
professor Niklaus Wirth, da Escola Politécnica de Zurique (a mesma escola
onde Einstein estudou). O nome da linguagem é uma homenagem ao filósofo
francês Blaise Pascal, que inventou uma máquina de calcular mecânica. A
descrição formal do Pascal foi publicada em 1971.

O Pascal nasceu dentro do conceito de programação estruturada, muito


discutida na Europa durante os anos 60 e hoje difundido pelo mundo e
incorporado em todas as linguagens modernas (C, C++, Java, Visual Basic,
etc.). A idéia principal do Pascal é a ordem, administrada através de um
conceito de dados baseado em tipos, requerendo declarações explícitas de
todas as variáveis e controles do programa. Parte da popularidade do Pascal
se deve ao compilador Turbo Pascal, da Borland, lançado em 1985. A
linguagem usada no Delphi é o sucessor do Turbo Pascal, conhecido como
Object Pascal.

2.1. INSTRUÇÕES CONDICIONAIS

2.1.1. INSTRUÇÕES IF

Este é o tipo mais básico de instrução condicional e pode ser usada para
executar um trecho de programa caso uma condição for satisfeita (if –then),
ou, mais genericamente, para escolher entre duas instruções (if-then-else). A
sintaxe geral da instrução if é a seguinte:

if condição then
[bloco de instruções 1]
else
[bloco de instruções 2];
Composto se as condições, e múltiplas declarações
Nós podemos ter várias condições para a condição se. E nós podemos ter
mais do que uma declaração para a outra e em seguida cláusulas. Aqui estão
alguns exemplos

if (condition1) And (condition2) // Both conditions must


be satisfied
then
begin
statement1;
statement2;
...
end // Notice no terminating ';' - still
part of 'if'
else
begin
statement3;
statement4;
...
end;

Note que não deve haver ponto-e-vírgula após o primeiro bloco de instruções.
Isto ocorre porque a instrução if-then-else deve ser lida como uma linha
inteira. Como teste, inicie um novo projeto e acrescente duas CheckBoxes e
três Botões de Comando no formulário, conforme a Figura 2.1 a seguir. Não é
necessário mudar os nomes ou legendas dos componentes. Dando um duplo
clique no primeiro botão e escreva o seguinte código:

procedure TForm1.Button1Click(Sender: TObject);


begin
{instrução if simples}

if CheckBox1.checked then
ShowMessage ('CheckBox1 está selecionada ')

end;

Este é um if simples. Durante a execução, se você clicar sobre o botão 1, e se


CheckBox1 estiver selecionada, um aviso será emitido. Mas nada acontece
caso CheckBox1 não esteja selecionada. Para contornar este problema,
escreva o seguinte código no evento click do botão 2:

procedure TForm1.Button2Click(Sender: TObject);


begin
{instrução if-else}

if CheckBox1.checked then

ShowMessage ('CheckBox1 está selecionada')

else

ShowMessage ('CheckBox1 não está selecionada ')

end;

Agora um aviso continuará a ser emitido caso CheckBox1 esteja selecionada.


Caso contrário (else), um aviso será emitido com a mensagem de que
CheckBox1 não está selecionada.

Você é capaz de imaginar o que aconteceria se as duas caixas estivessem


selecionadas? Neste caso, apenas o primeiro bloco será executado. Como o
programa verifica que a primeira condição é verdadeira, então a segunda,
dentro da lógica do if-then-else, não tem importância. Assim, a mensagem
recebida seria apenas a de que CheckBox1 está selecionada. Para testar
ambas as condições, escreva o código a seguir no botão 3:

procedure TForm1.Button3Click(Sender: TObject);


begin

if CheckBox1.checked and CheckBox2.checked then

ShowMessage('Ambas as caixas estão selecionadas')

end;

Note que usamos o operador booleano and para compor uma condição de
duas partes, que só será verdadeira se ambas as caixas estiverem
selecionadas.
2.1.2. INSTRUÇÃO CASE

Se a quantidade de condições a serem verificadas for muito grande, o uso da


instrução if poderá acarretar em códigos muito complexos. Neste caso é
melhor usar a instrução Case, que seleciona um valor dentro de uma lista de
possíveis valores ou intervalos de valores. Uma das limitações da instrução
Case do Pascal é que estes valores devem ser de tipo ordinal, ou seja, não é
possível testar literais ou números reais, por exemplo.

Para testar o Case, salve o projeto anterior e inicie um novo, inserindo uma
caixa de edição e dois botões, conforme a Figura 2.2 abaixo.

No evento click do botão 1, escreva o seguinte código:

procedure TForm1.Button1Click(Sender: TObject);


var Numero: integer;
begin

Numero := StrToInt(edit1.text);

case Numero of

1: Showmessage ('Você digitou 1');


2: Showmessage ('Você digitou 2');
3: Showmessage ('Você digitou 3');
4: Showmessage ('Você digitou 4');
5: Showmessage ('Você digitou 5');
6: Showmessage ('Você digitou 6');
7: Showmessage ('Você digitou 7');
8: Showmessage ('Você digitou 8');
9: Showmessage ('você digitou 9');
10: Showmessage ('você digitou 10');

else

Showmessage ('Você digitou um número maior que 10');


end;

end;

Note que devemos converter a propriedade text da caixa de edição, que é um


string, para um valor inteiro, pois não podemos testar text diretamente. Isto é
feito com a função StrToInt.

Podemos usar o Case também para testar intervalos de valores. Por exemplo,
escreva o seguinte trecho no evento click do botão 2:

procedure TForm1.Button2Click(Sender: TObject);


var Numero: integer;
begin

Numero := StrToInt(edit1.text);

case Numero of

1..10: Showmessage ('Você digitou um número entre 1 e 10');


11..20: Showmessage ('Você digitou um número entre 11 e
20');
21..30: Showmessage ('Você digitou um número entre 21 e
30');
31..40: Showmessage ('Você digitou um número entre 31 e
40');
41..50: Showmessage ('Você digitou um número entre 41 e
50');

else

Showmessage ('Você digitou um número maior do que 50');

end;

end;

2.2. INSTRUÇÕES DE LAÇO

2.2.1. LAÇO FOR

A instrução for do Pascal é semelhante à de outras linguagens, mas não é


muito flexível. Não é possível estabelecer incrementos diferentes de um,
embora seja possível contar para cima e para baixo. Por exemplo, inicie um
novo projeto, adicione dois botões no formulário, e escreva o seguinte código
no evento click do primeiro:

procedure TForm1.Button1Click(Sender: TObject);


var I: integer;

begin

for I:=1 to 10 do ShowMessage(IntToStr(I));

end;

Estamos usando a função IntToStr para converter o número inteiro I para um


string, pois a função ShowMessage só exibe strings. Clicando-se sobre o botão
1 em tempo de execução aparece uma caixa de mensagens que vai exibindo
números de 1 a 10. O código abaixo pode ser inserido no segundo botão e
exibirá números no sentido decrescente, isto é, de 10 a 1.

procedure TForm1.Button2Click(Sender: TObject);


var I: integer;

begin

for I:= 10 downto 1 do ShowMessage(IntToStr(I));

end;

2.2.2. INSTRUÇÕES WHILE E REPEAT

A diferença entre os laços while-do e repeat-until é que o código da instrução


repeat é sempre executado ao menos uma vez. Você pode entender essa
diferença escrevendo os códigos a seguir nos botões do projeto anterior:

procedure TForm1.Button1Click(Sender: TObject);


var I: integer;

begin
I:=0;

while I < 10 do

begin

ShowMessage(IntToStr(I));
I:= I+1;
end;

end;

procedure TForm1.Button2Click(Sender: TObject);


var I: integer;

begin
I:=0;

repeat

ShowMessage(IntToStr(I));
I:=I+1;

until I>10;

end;

Rode o programa e veja o que acontece.

Algumas observações são importantes. Primeiro, você mesmo precisa


providenciar o incremento da variável contadora I, e esta variável não precisa
ser inteira. Segundo, a instrução while-do exige que o bloco de instruções a
ser controlado fique entre um begin e um end, o que não acontece na
instrução repeat-until.

2.3. VARIÁVEIS

A linguagem Pascal é fortemente baseada em tipos de dados. O tipo de uma


variável determina os valores que esta variável pode ter e as operações que
podem ser executadas com ela. Também é necessário que todas as variáveis
sejam declaradas antes de ser usadas, o que é feito por meio da palavra-chave
var. Esta declaração pode ser feita em uma unidade, em uma procedure ou
para declarar variáveis globais, tendo o seguinte aspecto:

var
Numero: Integer;
Fechado: Boolean;

Uma tentativa de realizar uma operação com tipos de dados diferentes resulta
em um erro de compilação. Isto aconteceria se tentássemos, por exemplo,
somar Numero e Fechado.
Constantes podem ser declaradas de forma semelhante, com auxílio da
palavra-chave const:

const
Pi = 3.141592;
Nome = ‘Alvaro’;

Note que não usamos, aqui, o sinal de atribuição ":=", e sim o sinal de
igualdade convencional.

O Object Pascal apresenta vários tipos de dados construídos internamente,


denominados tipos pré-definidos. Também é possível construir outros tipos a
partir dos pré-definidos. A Tabela 2.1 a seguir apresenta os tipos de dados pré-
definidos.

Tabela 2.1 - Tipos de dados pré-definidos do Object Pascal

TIPO DE DADO VARIAÇÃO TAMANHO OBSERVAÇÕES


ShorInt -128 a 127 1 byte
SmallInt -32768 a 32767 2 bytes
-2147483647 a
LongInt 4 bytes
2147483647
No Delphi este
-2147483647 a
Integer 4 bytes tipo é idêntico ao
2147483647
LongInt.
Byte 0 a 255 1 byte
Word 0 a 65535 2 bytes
Single ± 1.5 x10-45 a 3.4x1038 4 bytes 7-8 dígitos
Double 5.0x10-324 a 1.7x10308 8 bytes 15-16 dígitos
Extended 3.4x10-4932 a 1.1x104932 10 bytes 19-20 dígitos
-
922337203675477.5808
Currency 8 bytes 19-20 dígitos
a
922337203685477.5807
Comp -263 a 263 8 bytes 19-20 dígitos
11-12 dígitos. Use
este tipo apenas
para
Real 2.0x10-39 a 1.7x1038 6 bytes compatibilidade
com versões
anteriores do
Pascal
Boolean True ou false 1 byte
AnsiChar Caracteres ANSI
WideChar Caracteres Unicode
No Delphi este
Char Caracteres ANSI 1 byte tipo é idêntico ao
AnsiChar
ShortString Até 255 caracteres
AnsiString Virtualmente sem limite
Em geral, é
String Virtualmente sem limite idêntico ao
AnsiString
Pode conter
Variant qualquer tipo de
dados

Como o Object Pascal é uma linguagem fortemente estruturada, você não


poderá realizar operações entre variáveis de tipos diferentes. Será necessário,
então, convertê-las para o tipo adequado antes de realizar a operação. A
Tabela 2.2 a seguir mostra as funções de conversão mais utilizadas.

Tabela 2.2 - Funções de conversão de tipos mais utilizadas

FUNÇÃO DESCRIÇÃO
Chr Converte um número ordinal em um caractere ANSI
Converte um real em um inteiro, arredondando a parte
Round
decimal
Converte um real em um inteiro, truncando a parte
Trunc
decimal
Retorna a parte inteira de um argumento de ponto
Int
flutuante
IntToStr Converte um número em um string
Converte um string em um inteiro, levantando uma
StrToInt exceção (erro) caso o string não represente um inteiro
válido
Converte um string em um inteiro, usando um valor
StrToIntDef
padrão se o string não estiver correto
Converte um string em um número (rotina incluída para
Val
compatibilidade com o Turbo Pascal)
Converte um string em um número, usando parâmetros
Str de formatação (rotina incluída para compatibilidade com
o Turbo Pascal)
Converte um valor de ponto flutuante em um registro
FloatToDecimal (record) incluindo sua representação decimal (expoente,
dígitos, sinal)
Converte um valor de ponto flutuante para sua
FloatToStr
representação string usando formatação padrão
StrToFolat Converte um string e, um valor de ponto flutuante
Além dos tipos pré-definidos, o Object Pascal emprega a idéia de tipos de
dados definidos pelo usuário, que foi introduzida pela primeira vez no Pascal,
não estando presente nas linguagens anteriores. Os programadores podem
definir seus próprios tipos de dados por meio de construtores de tipos, tais
como subintervalos (subranges), matrizes (arrays), registros (records),
enumerações, ponteiros e conjuntos. A seguir, discutiremos brevemente cada
um destes tipos.

2.3.1. TIPOS ENUMERADOS

Este tipo permite que você crie uma lista organizada de itens. Para usar um
tipo você deve antes declará-lo com a palavra reservada type. Por exemplo,
um tipo enumerado que descreve os dias da semana pode ser declarado da
seguinte maneira:

implementation
{$R *.DFM}

type
Semana = (Segunda, Terça, Quarta, Quinta, Sexta, Sábado,
Domingo);

Espaços em branco não são permitidos dentro de um elemento. Uma vez


declarado um tipo, você deve declarar uma variável pertencente a este tipo.
Não usamos o tipo diretamente, mas sim uma variável deste tipo. Por exemplo,
vamos supor que queiramos construir um programa que forneça o nome da
pessoa escalada para um plantão semanal. Poderíamos declarar uma variável
Plantao da seguinte forma:

var
Plantao : Semana;

Para atribuir valores à variável Plantao escreva simplesmente:

Plantao := Segunda;
Plantao := Terça;
etc.

2.3.2. TIPOS SUBRANGE

O tipo subrange (subintervalo) permite que você defina um intervalo válido de


respostas que um usuário pode inserir em um programa, tal como o número de
horas trabalhadas em um mês, a faixa de idade dos membros de um clube, etc.
Um subintervalo pode conter os seguintes tipos: boolean, char, integer e tipos
enumerados.
A declaração de um tipo subintervalo é similar àquela de um tipo enumerado:

type
Salario_faixa1 = 500 .. 1000;

Note que usamos dois pontos para separar os limites do suintervalo, e não
vírgulas. Isto permite que o compilador identifique o tipo como um subintervalo
e não um tipo enumerado. A seguir, devemos declarar uma variável como
pertencente ao tipo declarado anteriormente:

var
Salario_Ana : Salario_faixa1;

Quando um programa usando subintervalos é executado, e se um valor


atribuído a um tipo subintervalo estiver fora do intervalo, o programa gerará um
erro de tempo de execução. Veremos mais tarde como capturar este erro de
modo a avisar ao usuário que ele deve entrar novamente com os dados, sem
que o programa seja abortado. Para que o teste de intervalo seja executado,
você deve antes incluir a diretiva de compilação {$R+} no programa, da
seguinte forma:

procedure Tform1.ButtonClick (Sender : Tobject);


{$R+}

type
Salario_faixa1 = 500 .. 1000;

var
Salario_Ana : Salario_faixa1;

2.3.3. TIPOS ARRAY

Arrays são matrizes, isto é, coleções ordenadas de elementos de um mesmo


tipo de dados, que faz uso de um índice para dar acesso aos itens da coleção.
Como array já é um tipo, basta declarar uma variável como array, da seguinte
forma:

var
Dia_da_semana: array [1..7] of string;
Dia_do_mês: array [1..31] of integer;
Note que separamos os valores mínimo e máximo de um array por dois pontos.
Os arrays declarados acima são unidimensionais, isto é, seus elementos
podem ser dispostos formando uma única linha. Para atribuir valores a um
array proceda da seguinte forma:

begin
Dia_da_semana [1] := ‘Domingo’;
Dia_da_semana [2] := ‘Segunda-feira’;
Dia_da_semana [3] := ‘Terça-feira;
Dia_da_semana [4] := ‘Quarta-feira’;
Dia_da_semana [5] := ‘Quinta-feira’;
Dia_da_semana [6] := ‘Sexta-feira’;
Dia_da_semana [7] := ‘Sábado’;
end;

Para armazenar valores de um array em outra variável, podemos escrever:

var
Dia : string;

begin
Dia := Dia_da_semana [1];
end;

e assim por diante. A declaração de arrays multidimensionais é semelhante à


de arrays unidimensionais. Por exemplo, para declarar um array a ser usado
como uma tabela 30x30, escrevemos:

var
Bi_array: array [1..30,1..30] of currency;

Note que os elementos de um array podem pertencer a qualquer tipo de dados


pré-definido ou definido pelo usuário. Os elementos de um array podem ser até
mesmo outro array, mas por enquanto ficamos por aqui.

2.3.4. TIPOS RECORD (REGISTRO)

O tipo de dados Record provavelmente é o mais versátil à disposição, pois


pode conter tipos de dados heterogêneos. Por exemplo, a folha de pagamento
de uma empresa conterá dados do tipo string (nome, endereço, etc), dados do
tipo currency (salário), dados do tipo TDateTime (data de contratação) e assim
por diante. Não poderíamos usar um array, pois este tipo só pode conter dados
de um mesmo tipo. O tipo Record resolve o problema e, mais uma vez,
devemos declarar o tipo de dados antes de usá-lo:
type
Folha_Pgto = Record
Nome: String;
Data_Cont : TDateTime;
Salario: currency;
end;

var
Folha_Abril: Folha_Pgto;

begin

Folha_Abril.Nome := ‘Ana Paula Magalhães’;


Folha_Abril.Data_Cont := 10/02/1998;
Folha_Abril.Salário := 2200;

end;

Note que você deve usar um ponto para separar o nome do Record do nome
do campo a que você está se referindo. O Object Pascal, e várias linguagens
modernas fornecem uma maneira mais fácil de executar esta operação, usando
a instrução With:

begin

With Folha_Abril do begin

Nome := ‘Ana Paula Magalhães’;


Data_Cont := 10/02/1998;
Salário := 2200;

end;

end;

Aqui, o primeiro "end" é da instrução With. A documentação do Object Pascal


sugere que você use With quando for possível, pois isto diminui o tempo de
execução.

Os tipos Record também podem conter arrays e são bastante usados quando
se requer bancos de dados simples. Veremos que o Delphi permite a
implementação de estruturas de dados bastante complexas, usando bancos de
dados Dbase, Paradox, Access, etc. Contudo, vez por outra não é necessária
toda esta sofisticação e é conveniente optar pelos tipos Record. Além disso,
nesses casos simples não será necessário instalar os drivers de bancos de
dados
3. USANDO COMPONENTES
3.1. CONVENÇÕES DE NOMES PARA COMPONENTES

É sempre bom estabelecer convenções de nomes para componentes do


Delphi, sob risco de não se saber, no meio de um projeto mais complicado,
qual o tipo de um componente cujo nome é, por exemplo, "dados". A Tabela
3.1 a seguir apresenta alguns exemplos.

Tabela 3.1

Componente Nome em Prefixo Exemplo


Português
Form Formulário frm frmAbrir
Caixa de
Check Box chk chkLeitura
Verificação
Caixa de
Combo Box cbo cboPortuguês
Combinação
Botão (de
Button cmd/but cmdCancelar
comando)
Label Rótulo lbl lblNome
(Caixa de)
Edit txt/edt txtTelefone
Edição
Image Imagem img imgPrincipal
Caixa de Lista
FileListBox fil filAbrir
de Arquivos
Caixa de Lista
DirectoryListBox dir dirSalvar
de Diretórios

Nomes de componentes são locais aos formulários que os contém. Por


exemplo, dois formulários diferentes podem conter componentes com o mesmo
nome. Usuários iniciantes costumam se preocupar um pouco com isto, mas é
como se, em duas casas diferentes, houvessem duas filhas chamadas Ana
Paula, também de pais diferentes. Mesmo que se encontrassem, os pais delas
jamais fariam confusão.

3.2. O BLOCO DE NOTAS BLOCO.DPR

Processamento de textos é uma das funções básicas dos computadores e o


Delphi oferece algumas ferramentas poderosas relacionadas a texto. Nosso
objetivo inicial é projetar um Bloco de Notas simplificado que funcione a partir
da caixa de memorando do Delphi e que disponha dos seguintes recursos:

• Edição básica: inserção e exclusão de texto, movimentação do cursor,


etc.;
• Seleção de texto;
• Cortar, copiar e colar textos.

Futuramente, nosso Bloco de Notas se transformará em um editor mais


poderoso, capaz de abrir e salvar arquivos do tipo texto e de funcionar também
a partir de menus.

O Bloco de Notas usará as seguintes propriedades de componentes do Delphi:

• Text: string que contém o texto em uma Caixa de Edição, Memorando


ou Rich Edit. O tamanho máximo é 64 kBytes.
• Enabled: se for true, o componente é disponível;
• Visible: se for true, o componente é visível;
• SelText: string que contém apenas o texto selecionado em uma Caixa
de Edição, Memorando ou Rich Edit.

A propriedade Enabled (que significa "habilitado" ou "disponível") é comum a


vários componentes do Delphi. Quando o componente está desabilitado ele
aparece acinzentado e o usuário não tem acesso a ele, seja com o mouse seja
de outra forma qualquer. Um componente invisível está carregado na memória,
o usuário não tem acesso a ele, mas em certas circunstâncias pode ser
acessado por meio de código. Por exemplo, você pode alterar certas
propriedades de um componente invisível por meio de código, mas não pode
definir o foco sobre ele.

Além disso, vamos precisar do método SetFocus, cuja sintaxe é a seguinte:

Objeto. Setfocus.

O "Foco" é uma propriedade comum a todos os componentes do Delphi.


Apenas um objeto pode ter o foco de cada vez e apenas objetos visíveis
podem receber o foco. Geralmente, o objeto que tem o foco é diferenciado dos
outros por uma legenda ou título realçado. Em tempo de execução, o usuário
define o foco clicando sobre os objetos ou usando a tecla TAB. O método
Setfocus também define o foco para um objeto em tempo de execução, mas
de maneira automática. Se ocorrer uma tentativa de definir o foco em um objeto
invisível ou desabilitado, um erro de execução será gerado.

a) Criando a interface de BLOCO.DPR

Inicie um novo projeto e desenhe, no formulário, uma Caixa de Memorando


(Memo) e quatro botões de comando, conforme ilustrado na Figura 3.1 a
seguir.
b) Definindo as propriedades

Defina as propriedades dos componentes de acordo com a Tabela 3.2 a seguir.

Tabela 3.2

COMPONENTE PROPRIEDADE DEFINIÇÃO


Formulário WindowState Maximized
Memo Name txtBloco
Text (vazio)
ScrollBars Vertical
Botão de Comando 1 Name cmdCortar
Caption &Cortar
Botão de Comando 2 Name cmdColar
Caption Co&lar
Botão de Comando 3 Name cmdApagar
Caption &Apagar
Botão de Comando 4 Name cmdSair
Caption &Sair

Note que Memo suporta textos com várias linhas e tem uma barra de
paginação vertical. Esta barra de paginação não é um objeto adicional, mas faz
parte do componente memorando. O Delphi cuida de toda a automação
necessária para a rolagem do texto. Você pode pensar que a disposição dos
componentes mostrados na Figura 3.1 é um pouco desorganizada (e realmente
é!). Contudo, em tempo de projeto, não é necessário posicionar os
componentes precisamente alinhados no formulário. O alinhamento será feito
de maneira automática e muito precisa na inicialização do programa.
c) Escrevendo o código

Neste aplicativo iremos copiar e cortar o texto, sendo necessário usar uma
variável para armazenamento temporário de texto. Declare a variável
CortaTexto na seção Private da unidade:

type
.
.
private

{Private daclarations}
CortaTexto : string;
.
.

O primeiro botão a ser implementado é o "Apagar". Este botão apagará todo o


texto da caixa de texto, indiscriminadamente. Tudo o que temos a fazer é
"anular" a propriedade text da caixa de memorando. Para tanto, dê dois cliques
sobre o botão apagar e escreva o seguinte código:

procedure TfrmBloco.cmdApagarClick (Sender : TObject);


begin

txtBloco.Text := ‘ ‘;
txtBloco.SetFocus;

end;

Após apagar o texto, o que é feito na primeira linha, devemos jogar o foco
novamente na caixa de memorando, pois após clicar o botão "Apagar" o foco
ficou com ele. Seria desagradável se o usuário tivesse que clicar na caixa de
memorando toda vez que usasse o botão "Apagar". O computador não se
importa de prestar este pequeno favor.

O botão "Sair" também é fácil :

procedure TfrmBloco.cmdSairClick (Sender : TObject);


begin

Close;

end;

Os manipuladores para os botões "Cortar" e "Colar" requerem um raciocínio


adicional. O que desejamos fazer é cortar um trecho de texto para ser colado
em algum outro lugar. Logo, será necessário armazenar o texto recortado em
alguma variável temporária, o que será conseguido com a variável CortaTexto.
Clique sobre o botão "Cortar" e escreva o seguinte trecho:
procedure TfrmBloco.cmdCortarClick (Sender : TObject);
begin

CortaTexto := txtBloco.SelText;
txtBloco.SelText := ‘ ‘;
txtBloco.SetFocus;

end;

A primeira linha armazena o conteúdo do texto selecionado na variável


CortaTexto. A segunda apaga o texto selecionado, dando um efeito de que o
texto foi recortado. Finalmente, a última linha joga o foco novamente na caixa
de memorando. O manipulador para o botão "Colar" atua de modo inverso a
"Cortar", ou seja, devemos recuperar o texto armazenado em CortaTexto e
atribuí-lo à propriedade SelText da caixa de memorando, conforme descrito a
seguir.

procedure TfrmBloco.cmdColarClick (Sender : TObject);


begin

txtBloco.SelText := CortaTexto;
txtBloco.SetFocus;

end;

O nosso "mini-editor" já funciona bem, mas algumas melhorias são


necessárias. Primeiro, caso o usuário queira redimensionar o formulário, os
botões e a caixa de texto não o acompanharão. Este problema pode ser
contornado de duas formas. Uma delas envolve o uso do evento Resize do
formulário. Este evento ocorre sempre que o formulário é redimensionado, seja
por meio do mouse, seja por meio dos ícones de maximizar e minimizar.
Resize também ocorre quando o formulário é exibido pela primeira vez, na
entrada do programa. O que devemos fazer é ajustar a caixa de texto
automaticamente no formulário cada vez que este for redimensionado, o que
pode ser conseguido com alguns cálculos.

Com o formulário ativo, vá até o Object Inspector e escolha a opção Events.


Clique duas vezes sobre o evento Resize para abrir o manipulador de eventos
adequado. Neste manipulador, escreva o código abaixo.

procedure TfrmBloco.FormResize (Sender : TObject);


begin

If frmBloco.Width > 50 then


begin

txtBloco.Top := 0;
txtBloco.Left := 0;
txtBloco.Width := frmBloco.ClientWidth;
txtBloco.Height := frmBloco.ClientHeight -
cmdCortar.Height;
cmdCortar.Left := 0;
cmdColar.Left := cmdCortar.Width;
cmdApagar.Left := 2 * cmdCortar.Width;
cmdSair.Left := frmBloco.ClientWidth - cmdSair.Width;
cmdCortar.Top := frmBloco.ClientHeight - cmdCortar.Height;
cmdColar.Top := frmBloco.ClientHeight - cmdColar.Height;
cmdApagar.Top := frmBloco.ClientHeight - cmdApagar.Height;
cmdSair.Top := frmBloco.ClientHeight - cmdSair.Height;

end;

end;

Estudando a procedure de Resize com cuidado você verá que estamos


simplesmente alterando valores de propriedades dos componentes. Em Delphi
isto é feito com muito mais freqüência do que você pode imaginar. As primeiras
quatro linhas ajustam a caixa de memorando propriamente dita, de forma que
sobre espaço em baixo para os botões (é por isso que a altura do botão Cortar
- cmdCortar.Height - é descontada). As linhas seguintes ajustam a posição de
todos os botões, atuando sobre as propriedades Left e Top.

Como exercício, fica a tarefa de descobrir qual a finalidade do comando If ...


Then.

Outra maneira de implementar a mudança automática de tamanho é mudando


a propriedade Align de txtBloco para alClient. Isto significa que o memo será
automaticamente alinhado em toda a área interna do formulário (área do
cliente). Contudo, ao menos neste caso, o efeito obtido não será muito bom,
pois estaremos escondendo os botões. Se estivéssemos trabalhando com
menus e não com botões não haveria problema, mas isso fica para o próximo
capítulo.

3.2.1. MOSTRANDO BITMAPS EM BOTÕES

Os botões de comando convencionais não permitem mostrar bitmaps, mas o


Delphi fornece também o componente BitBtn, na página Additional da Paleta
de Componentes, que realiza exatamente esta função.

Uma vez inserido este componente, você pode escolher o tipo de bitmap,
alterando o valor da propriedade Kind, que pode ser: bkOK, bkYes, bkHelp,
bkAbort, bkAll, bkIgnore, bkCancel, bkNo, bkClose e bkRetry. Uma vez
definida esta propriedade, a legenda e o bitmap do botão serão
automaticamente inseridos. Talvez você fique preocupado em ver a lagenda
aparecer em inglês, mas você sempre pode alterar a propriedade caption
manualmente.
Se você não gostou dos bitmaps exibidos pelo Delphi, você pode escolher os
seus próprios, alterando a propriedade Glyph. Você também pode alterar a
propriedade NumGlyphs para criar um botão animado com até quatro quadros.

3.2.2. EXIBINDO DICAS DE COMPONENTES

O Delphi permite que você exiba dicas de botões e demais componentes, ou


seja, quando você posicionar o mouse sobre um botão com dicas habilitadas,
uma pequena caixinha explicativa aparecerá. Existem quatro propriedades que
podem ser alteradas para personalizar as dicas:

• ShowHint: se for true, habilita a exibição de dicas;


• Hint: string que contém o texto explicativo;
• HintColor: constante que define a cor de fundo da caixa de dicas;
• HintPause: valor, medido em milisegundos, que determina o tempo que
o mouse deve permanecer sobre o botão para a dica aparecer.

Exemplo:

procedure TForm1.FormCreate (Sender : TObject);


begin

cmdCortar.ShowHint := true;
cmdOK.Hint := ‘Recorta o texto selecionado’;
Application.HintColor := clAqua;
Application.HintPause := 200;

end;

3.2.3. EXIBINDO CORES NO DELPHI

Existem duas maneiras de se exibir cores no Delphi:

a) Usando cores pré-definidas:

Cores pré-definidas são acessadas por meio das seguintes constantes:

Tabela 3.3

clBlack Preto clMaroon Marron-terra


clBlue Azul clNavy Azul-marinho
clDkGray Cinza escuro clOlive Verde-oliva
clFuchsia Lilás clPurple Roxo
clGray Cinza clRed Vermelho
clGreen Verde clSilver Prata
clLime Verde-limão clWhite Branco
clLtGray Cinza claro clYellow Amarelo

Os valores destas cores vêem do tempo dos monitores de dezesseis cores e


ainda são úteis em várias circunstâncias. Por exemplo, para mudar a cor de
fundo de uma caixa de edição para azul, em tempo de execução, escreva:

Edit1.color:=clBlue;

b) Usando a função RGB()

Esta função permite o acesso a todas as cores que o seu monitor é capaz de
mostrar, tendo a seguinte sintaxe:

Cor := RGB( vermelho, verde, azul);

onde Vermelho, Verde e Azul são parâmetros do tipo byte que variam de zero
até 255. Uma cor RGB, deste modo, é formada por uma parcela de vermelho,
uma parcela de verde e uma parcela de azul. Estas são as chamadas cores
básicas aditivas. A função RGB permite combinar 255 valores de cores três a
três, resultando em mais de dezesseis milhões de cores possíveis. O número
final de cores será limitado pelo seu monitor e pela configuração dele. Por
exemplo, para mudar a cor de fundo de uma caixa de edição para azul (zero
partes de vermelho, zero partes de verde e 255 partes de azul), em tempo de
execução, escreva:

Edit1.color:=RGB(0, 0, 255);

3.3. TRATAMENTO DE EXCEÇÕES E UM RELÓGIO DESPERTADOR

É comum que programadores iniciantes não se preocupem com erros e que até
alimentem a vã esperança de que o usuário nunca realizará determinada ação
que resultaria em um erro em tempo de execução. Os usuários, por outro lado,
não parecem pensar assim e, se existe uma maneira de travar o seu programa,
pode ter certeza de que o usuário a encontrará.

O Delphi emprega a palavra reservada exception (exceção) para se referir a


erros em tempo de execução. A expressão "tratamento de exceções" significa
o desenvolvimento de rotinas que sejam capazes de capturar um erro e tratá-lo
de forma adequada, evitando o colapso do programa. A sintaxe de um
manipulador de exceções é a seguinte:

try
[bloco de comandos]
except
[código de tratamento de erros]
end;
Quando você estiver rodando um programa dentro do IDE do Delphi, os
manipuladores de exceção somente funcionarão caso a opção Break On
Exception do menu Tools | Environment Options estiver desligada. Caso
contrário, o programa parará a execução em qualquer exceção,
independentemente dos manipuladores.

Uma grande utilidade dos manipuladores de exceção é na validação de dados


de entrada e vamos nos valer desta característica para construir um relógio
despertador que mostre a hora certa e seja capaz de emitir um alarme quando
a hora ajustada já tiver decorrido.

O programa de relógio-despertador utiliza, ainda, algumas funções do Delphi,


descritas abaixo.

• Time$: retorna a hora atual do sistema, no formato hh:mm:ss;


• TimeToStr: converte dados do formato Time para String;
• StrToTime: converte dados do formato String para Time.

Para iniciar o projeto do Relógio Despertador, posicione os seguintes


componentes em um formulário, conforme a Figura 3.2:

• Dois Rótulos;
• Dois Botões de Opção;
• Um Timer.

Um rótulo (página Standard), ou label, é basicamente um componente


não editável para saída de dados. Deve ser usado em substituição à caixa
de texto sempre que não for permitido que o usuário edite o texto. Estaremos
usando dois rótulos neste projeto: um deles servirá de "display" para mostrar as
horas. Este componente deve ser um rótulo, pois não queremos,
evidentemente, que o usuário edite a hora atual !; o outro rótulo terá uma
finalidade mais prosaica, servindo apenas para indicar a função da caixa de
textos. Rótulos constituem, portanto, um maneira fácil de se imprimir textos no
formulário. Para modificar o texto em tempo de execução, mude a propriedade
"caption" (rótulos não têm a propriedade "text").
Os botões de opção, algumas vezes denominados "botões de rádio", são
semelhantes àqueles botões push-button encontrados em vários tipos de
aparelhos de som. A finalidade é convidar o usuário a escolher apenas uma
opção dentre várias.

O componente Timer tem a propriedade Interval ajustada para 1000 ms, ou 1


s, pois desejamos que a hora seja mostrada no display a intervalos de 1
segundo. A Tabela 3.4 mostra as definições dos objetos de Alarme.DPR.

Na seção private da unidade, declare as seguintes variáveis: AlarmeOn e


Tempo.

private

{Private declarations}
AlarmeOn : boolean;
Tempo : TTime;

Para começar a inserção do código de optOpção, clique duas vezes nos botões
de opção e digite os seguintes trechos:

procedure TfrmAlarme.optOnOffClick(Sender: TObject);


begin

AlarmeOn:=false;

end;

procedure TfrmAlarme.RadioButton1Click(Sender: TObject);


begin

AlarmeOn:=true;

end;

Tabela 3.4

OBJETO PROPRIEDADE DEFINIÇÃO


Formulário Nome frmAlarme
Rótulo Nome lblDispaly
Legenda (vazio)
MS Sans Serif 24
Fonte
negrito
Caixa de Edição Nome txtAjuste
Botão de Opção
Nome optOn
1
Botão de Opção
Nome optOff
2
Timer Interval 1000

AlarmOn é uma variável booleana que definirá se o som de alarme deve estar
ligado ou desligado.

O próximo passo é escrever o código de validação de entrada da caixa de texto


txtAjuste. Não queremos que o usuário escreva qualquer coisa nesta caixa.
Somente números no formato de hora devem ser permitidos. Para realizar a
validação, tentamos converter o texto de txtAjuste para Time. Se a conversão
falhar, significa que o texto não é uma hora válida. O erro é capturado e a caixa
de edição recebe o texto anterior.

procedure TfrmAlarme.Timer1Timer(Sender: TObject);


begin

try
Tempo:=StrToTime(txtAjuste.text);
except
{erro de conversão}
beep;
txtAjuste.text:=TimeToStr(Tempo);
end;

if txtAjuste.text <> '' then


begin

if (Time > StrToTime(txtAjuste.text)) then


begin

if AlarmeOn then
begin

Beep;

end;

end;

end;

lblDisplay.caption:=Tempo;

end;
As próximas linhas verificam se a hora ajustada é maior do que a hora atual.
Caso seja, um bip é acionado a cada segundo. A última linha do programa
exibe a hora atual no display.

Resumindo, o funcionamento do alarme é simples. A cada segundo é gerado


um evento de Timer e, capturando este evento, verificamos se o tempo
ajustado em txtAjuste é maior ou menor do que o tempo do display lblDisplay.
Se for maior, e se o botão de opção estiver na posição "Ligado", fazemos o
alto-falante emitir um "bip" a cada segundo. Cada vez que ocorre um evento
Timer a função Time$ é usada para atualizar a hora em lblDisplay.

3.4. NOTA SOBRE OS CÓDIGOS ASCII, ANSI E UNICODE

O ASCII é um código de caracteres de 8 bits (1 byte) desenvolvido na época


em que só o DOS existia. Com estes 8 bits não é possível representar mais do
que 256 caracteres, mas no início as coisas eram mais simples e, memórias de
computador, mais caras. O ANSI também é um código de 8 bits, mas inclui
alguns caracteres não suportados pelo ASCII. O Windows 3.1 usava o ANSI
como padrão, suportando também o ASCII.

O Unicode é um código de 16 bits desenvolvido pela International Standards


Organization (ISO), com possibilidade para 65.536 caracteres diferentes. Este
espaço é suficiente para acomodar todos os caracteres usados no mundo
atualmente, incluindo línguas antigas como sânscrito e hieroglifos egípcios.
Também existe espaço vago suficiente para que não se precise preocupar com
isto durante mais algumas centenas de anos. O Unicode é totalmente
suportado pelo Windows 95 e pelo Windows NT, convertendo-se caracteres do
ANSI para o Unicode e vice-versa. Os caracteres são armazenados em ANSI
pelo sistema operacional e manipulados em Unicode pelo Delphi.

3.5. ERROS COMUNS EM PROGRAMAÇÃO

3.5.1. FORMULÁRIOS MUITO CARREGADOS

O Delphi disponibiliza uma quantidade fantástica de componentes e é grande a


tentação de usar todos em um só formulário. Esta estória é semelhante à de
um grande jornal brasileiro que, certa vez, completou a instalação de um
parque gráfico de última geração. No dia seguinte, a primeira página do jornal
continha reportagens escritas em todas as cores e fontes disponíveis nos
equipamentos, como se os jornalistas não tivessem resistido à tentação de
fazer todas as experiências possíveis de um só vez.

O Delphi oferece mais de uma solução para este problema da "densidade


gráfica", tais como componentes giratórios (spin buttons), caixas "drop-down",
páginas "tab-strip" e outros. A melhor ferramenta, contudo, é uma boa
programação gráfica dos formulários. Outra maneira de evitar o carregamento
dos formulários é usar componentes carregados dinamicamente, isto é, à
medida que o programa vai sendo executado. Lembre-se, o uso excessivo de
componentes não será visto como um sinal de que o programador conhece
profundamente a linguagem, mas sim como um sinal de amadorismo.

3.5.2. FALTA DE IDENTAÇÃO E ESPAÇAMENTO

O Delphi não exige que você idente o código e compilará trechos de código
identados ou não exatamente da mesma maneira. Ainda assim, você
descobrirá que a identação é uma ferramenta poderosa na documentação de
programas. Facilidade de leitura não é um preciosismo, mas sim um
instrumento de depuração muito usado. Infelizmente, linguagens mais antigas,
especialmente linguagens para MainFrame, não permitiam a identação nem a
presença de linhas em branco. Pior para elas !

3.5.3. USAR NOMES LONGOS

Outra prática desaconselhável é usar nomes longos para variáveis e


constantes. Alguns desenvolvedores, em vez de chamar um simples botão de
cmdOK, preferem escrever cmdOKformulárioFechaArquivoSemSalvar. Esta
prática é totalmente desnecessária e dificulta enormemente a leitura (se bem
que eu tenho a impressão de que a intenção destes programadores é
justamente esta.).

3.5.4. PROCEDIMENTOS LONGOS

Sempre é possível quebrar um procedimento longo em outros menores,


aumentando a reusabilidade do código e facilitando o entendimento. Além
disso, procedimentos muito longos tornarão o programa susceptível a estouro
de memória.

You might also like