LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
DESENHO LIVRE
!
OBJETIVO:
Mostrar ao estudante como desenhar através do método Canvas de alguns objetos.
!
APARÊNCIA DO PROJETO:
!
OBJETOS A ACRESCENTAR/MODIFICAR PROPRIEDADES INICIALMENTE:
Objetos
Form1
Panel1
Panel2
Image1
!
Propriedades
Caption
Color
Position
Height
Width
BorderStyle
BorderIcons
Caption
Height
Align
Caption
Height
Align
Align
Descrição/Valor
DESENHO LIVRE
clWhite
poScreenCenter
478
639
bsSingle
BiMaximize = false
(deixar em branco)
41
alTop
(deixar em branco)
41
alBottom
AlClient
FASE 01: PRIMEIROS PONTOS:
Nesta primeira fase iremos permitir o desenho de pontos de tamanhos variáveis.
Para que possamos desenhar qualquer ponto, na realidade teremos que desenhar um círculo com
um raio muito pequeno. Para se desenhar um círculo, usa-se o método Ellipse da propriedade Canvas de
um objeto onde se vai desenhar. No nosso caso, iremos desenhar dentro do objeto Image1; mas
poderíamos desenhar em outros objetos do Windows, inclusive até o formulário.
O evento que iremos utilizar será o OnMouseDown do objeto Image1.
Antes de programar o evento citado, vamos declarar algumas variáveis globais que utilizaremos
no decorrer do projeto:
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Tam,
- Página
CorPreench: integer;
implementation
{$R *.DFM}
end.
1-
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
" Digite apenas o que está em negrito, exatamente no local indicado !
Agora, acione o evento OnMouseDown do objeto Image1 e digite os comandos que aparecem em
negrito:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.Brush.Color:= CorPreench;
Image1.Canvas.Ellipse( x – tam , y – tam , x + tam , y + tam);
end;
end.
Notem que nesta rotina, utilizamos os valores de “X” e “Y”, que são as coordenadas do mouse
ora somados ora subtraídos de um valor representado pela variável “Tam” (tamanho).
Esta variável “Tam” iremos inicializá-la com o valor 1, dentro do evento OnCreate do
formulário.
Ao atribuirmos os valores (X-tam, Y-tam) para o ponto do canto superior esquerdo do retângulo
que circunscreve o círculo (elipse), estamos supondo que o ponteiro do mouse encontra-se no centro do
círculo:
(x-tam,y-tam)
(x+tam,y+tam)
(x,y)
A variável “Tam” representa o raio do círculo. Vamos inicializá-la no evento OnCreate do objeto
Form1:
procedure TForm1.FormCreate(Sender: TObject);
begin
Tam:= 1;
CorPreench:= clBlack;
end;
" Aproveitamos o ensejo para inicializar outra variável, que utilizaremos nas rotinas deste
projeto para definir a cor da linha (pen.color) e a cor de preenchimento (brush.color).
!
FASE 02: TAMANHO DOS PONTOS:
Nesta fase iremos implementar a mudança do tamanho dos pontos que são desenhados na tela.
Para isto, iremos possibilitar a alteração do valor da variável “tam” (tamanho) que foi inicializada
com o valor 1. Aumentaremos o valor de “tam” toda vez que o usuário acionar a tecla “+” e
diminuiremos seu valor toda vez que acionar a tecla “-“. Com isto, os valores das coordenadas X-tam,
Y-tam, X+tam e Y+tam que representam o retângulo que circunscreve o círculo (elipse) irão aumentar
ou diminuir o mesmo.
Para que o windows dê prioridade ao teclado, temos que alterar a propriedade KeyPreview do
formulário para True, pois, a partir daí todo evento gerado pelo teclado será examinado primeiramente
pelos métodos do formulário. Caso não exista nenhum método de tratamento de teclado programado, o
controle passará para o próximo objeto.
Vamos exemplificar o que acabamos de afirmar: Vamos supor que você esteja digitando algo dentro
de um objeto Edit. A cada tecla que você digita, são acionados primeiramente os eventos OnKeyPress,
OnKeyDown, OnKeyUp, etc... do formulário e não do Edit. Se existir algum tratamento para estes
eventos do formulário, eles são executados antes de se atender ao objeto Edit.
Isto é importante, pois, assim, por exemplo, podemos encerrar um determinado programa a qualquer
momento que a tecla “Esc” for acionada, bastando testar o acionamento da mesma dentro de um evento
OnKeyPress de um formulário, mesmo que no momento estejamos digitando um texto em um objeto
“Memo” por exemplo.
Portanto, mude a propriedade KeyPreview do formulário Form1 para True.
- Página 2 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Agora, digite as instruções (que estão em negrito) a seguir, dentro do evento OnKeyPress do
formulário:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
If key = '+' then
If tam < 12 then Inc(Tam);
If key = '-' then
If tam > 1 then Dec(tam);
If key = #27 then Close;
end;
Na rotina acima podemos verificar que ao ser acionada qualquer tecla do teclado, verifica-se qual é a
mesma:
Se for a tecla “+” aumenta-se o valor de “Tam” em uma unidade até o valor máximo de 12, através
do procedimento Inc(tam).
Se for a tecla “-“ verifica-se primeiramente se o valor de “Tam” é maior que 1, para evitar valores
negativos do mesmo, se for, diminui-se o valor de “Tam” de um unidade através do procedimento
Dec(tam).
Colocamos também, o teste da tecla Esc, cujo código ASCII é 27. Se esta tecla for acionada, o programa é
encerrado (ao se fechar o formulário principal).
!
FASE 03: COR DOS PONTOS:
Podemos criar a possibilidade de se alterar a cor dos pontos que estão sendo desenhados. Para isto,
iremos incluir um botão (SpeedButton) que irá chamar um diálogo de cores (ColorDialog).
- Página 3 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Insira dentro de Panel1 um SpeedButton e um objeto ColorDialog e altere as algumas de suas
propriedades:
SpeedButton1
Glyph
Height
Width
Left
Top
Hint
ShowHint
=
=
=
=
=
=
=
Brush.bmp
36
36
3
3
Escolhe a cor de preenchimento
True
ColorDialog1
nenhuma de suas propriedades serão alteradas
Agora, vamos ao evento OnClick do SpeedButton1. Ele deverá chamar a execução do diálogo
ColorDialog. A função “Execute” deste diálogo, retorna o valor true se uma cor for selecionada ou false
caso contrário. Se uma cor for selecionada, ela será informada na propriedade Color deste objeto de
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
If ColorDialog1.execute then CorPreench:= ColorDialog1.color;
end;
diálogo.
Nota-se na rotina acima que alteramos a cor de preenchimento (CorPreench), atribuindo à mesma o
valor da propriedade Color do objeto ColorDialog1.
!
FASE 04: PREVIEW DOS PONTOS:
Acho que é necessário neste momento, que incluamos no nosso projeto um “preview” do ponto que
será desenhado, para que possamos ter uma idéia do seu tamanho e cor atuais.
Para isto, iremos incluir no nosso projeto um objeto Panel3 dentro do Panel2. Alterando as
seguintes propriedades do mesmo:
Panel3
Caption
Width
Height
Color
BevelWidth
BevelInner
Top
Left
=
=
=
=
=
=
=
=
(deixar em branco)
37
37
clWhite
3
bvLowered
2
3
Agora, acrescente dentro deste Panel3 um objeto Image, e altere as suas seguintes propriedades:
Image2
Width
Height
Top
Left
=
=
=
=
25
25
7
7
Dentro deste objeto Image2 é que colocaremos um preview do ponto que será desenhado. Para que
isto ocorra, é melhor digitarmos um procedimento que faça isto acontecer (Pincel), e depois, colocar o
comando de chamada do mesmo em lugares estratégicos dentro do programa.
Não esqueça de além de digitar as linhas abaixo, colocar a definição deste procedimento dentro do
escopo public da classe TForm1:
procedure TForm1.Pincel;
var x, y: integer;
begin
x:= image2.width div 2;
y:= image2.height div 2;
Image2.picture:= nil;
If corpreench <> Panel3.color then Image2.Canvas.Pen.color:= CorPreench
else Image2.Canvas.Pen.color:= clBlack;
Image2.Canvas.Brush.Color:= CorPreench;
Image2.canvas.ellipse(x-tam,y-tam,x+tam,y+tam);
end;
- Página 4 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Na rotina acima, observamos que foram criadas 2 variáveis locais: “x” e “y” que recebem as
coordenadas do centro do objeto Image2. Em seguida, a imagem que porventura esteja desenhada em Image2
é apagada atribuindo-se Nil à propriedade Picture. Depois, verifica-se a cor do ponto, se é a mesma do
Panel3, pois, se isto acontecer, o “preview” não mostrará nada, pois o fundo do Panel3 seria da mesma cor.
Daí, a cor da linha que envolve o ponto é desenhada na cor preta, caso contrário, continua com a mesma cor
do preenchimento. A seguir, é atribuido o valor da cor de preenchimento e finalmente é desenhado o ponto
dentro do objeto Image2.
Um dos “locais estratégicos” para colocarmos a chamada a Pincel, é no botão SpeedButton1, pois,
com isto, se a cor for alterada, a cor do ponto no preview será alterada:
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
If ColorDialog1.execute then CorPreench:= ColorDialog1.color;
Pincel;
end;
Outro local estratégico, é no evento OnKeyPress do formulário, pois, ao acionarmos as teclas “+” ou
“-“ temos uma mudança no tamanho do ponto, o que também deverá ser mostrado no preview do mesmo:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
If key = '+' then
If tam < 12 then Inc(Tam);
If key = '-' then
If tam > 1 then Dec(tam);
Pincel;
If key = #27 then Close;
end;
Existe mais um local estratégico: no método OnCreate do formulário. Neste local, a chamada é
necessária para que o ponto apareça no “preview” tão logo inicie o programa:
procedure TForm1.FormCreate(Sender: TObject);
begin
Tam:= 1;
CorPreench:= clBlack;
Pincel;
end;
!
FASE 05: GRAVANDO O DESENHO:
Você já deve ter percebido que todo o desenho é perdido depois que nós fechamos o programa.
Claro que você já deve ter chegado à conclusão que necessitamos de gravá-lo. Para fazer isto, precisamos
introduzir no nosso projeto mais 2 objetos: um SpeedButton dentro do Panel1 e um SaveDialog.
Altere as seguintes propriedades dos mesmos:
SpeedButton2
Glyph
Height
Width
Left
Top
Hint
ShowHint
=
=
=
=
=
=
=
- Página 5 -
Floppy.bmp
37
37
41
3
Grava o desenho atual
True
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
SaveDialog1
DefaultExt
Filter
=
=
Title
=
*.bmp
BitMaps
| *.bmp
Todos os arquivos | *.*
Grava figura
Agora, temos que programar o método correspondente ao evento Onclick do objeto SpeedButton2:
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
If SaveDialog1.execute then
begin
Image1.Picture.SaveToFile(SaveDialog1.Filename);
end;
end;
Na rotina acima destacada, verificamos a execução da função Execute do objeto SaveDialog1. Esta
função retornará o valor True se o usuário escolher um nome de arquivo para gravar a figura, ou o valor False
se ele acionar o botão “Cancel”.
O método SaveToFile grava a figura contida em Image1 no arquivo que foi especificado no diálogo
SaveDialog1, e cujo nome foi guardado na propriedade FileName do mesmo.
!
FASE 06: PERGUNTANDO ANTES DE TERMINAR O PROGRAMA:
Toda vez que um formulário é fechado, o seu evento “OnClose” é chamado.
Como devemos lembrar, na rotina de tratamento do evento “onKeyPress” do formulário, fechamos o
formulário toda vez que a tecla “Esc” é acionada, e com isto, encerramos o programa.
Se quizermos perguntar ao usuário se ele realmente deseja encerrar o aplicativo, podemos interceptar
esta decisão, programando o evento “OnClose” do formulário, onde podemos Abortar o encerramento do
mesmo da seguinte forma:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
If not Termina_programa then Abort;
O comando Abort, “aborta” este evento, isto é, o formulário não é fechado, caso a função
end;
“Termina_programa” (que descreveremos a seguir) retorne o valor False.
A rotina “Termina_Programa”, que deverá ser declarada no escopo public da classe TForm1 no
início da Unit1, deverá ser digitada conforme aparece a seguir:
Function TForm1.Termina_programa: boolean;
begin
Result:= true;
If MessageBoxEx(0,'Deseja mesmo sair do programa ?', 'ENCERRAMENTO ...',MB_YESNO+
MB_ICONSTOP+MB_DEFBUTTON2,lang_portuguese) = idNo then Result:= false;
end;
A palavra Result colocada na função faz com que retorne no nome da mesma (Termina_programa) o
resultado (true ou false). Ao invés de utilizar a palavra Result, você poderia utilizar o próprio nome da
rotina: Termina_programa:= true, etc...
Utilizei a palavra Result, pois, economiza digitação.
Nesta rotina, também fizemos uso, pela primeira vez, da função interna do Delphi, MessageBoxEx,
esta função tem a seguinte sintaxe:
MessageBoxEx( 0, pergunta , caption , botões , língua ) : identificador do botão acionado;
•
•
PERGUNTA: um texto no formato PChar contendo o texto que será perguntado.
CAPTION: também um texto PChar que será colocado na faixa superior da janela da caixa de
mensagem.
- Página 6 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
•
BOTÕES: são códigos que identificam quais os botões serão mostrados, qual ícone será
colocado na caixa, e qual dos botões ficará selecionado. No nosso programa escolhemos os
botões Yes e No, que serão mostrados em português em virtude do próximo parâmetro (língua)
informar a língua que queremos. Escolhemos o ícone Stop e o botão default selecionado é o
segundo (Não). Se não informarmos o botão a ser selecionado o botão mais a esquerda é
selecionado como padrão. Observe que as constantes devem ser somadas.
Os valores possíveis para este parâmetro são:
Flag
MB_ABORTRETRYIGNORE
MB_OK
MB_OKCANCEL
MB_RETRYCANCEL
MB_YESNO
MB_YESNOCANCEL
MB_ICONEXCLAMATION,
MB_ICONWARNING
MB_ICONINFORMATION,
MB_ICONASTERISK
MB_ICONQUESTION
MB_ICONSTOP, MB_ICONERROR,
MB_ICONHAND
MB_DEFBUTTON1
MB_DEFBUTTON2
MB_DEFBUTTON3
MB_DEFBUTTON4
MB_APPLMODAL
Descrição
A caixa de mensagem conterá três botões: Abort, Retry, e Ignore.
A caixa de mensagem conterá um botão OK.
A caixa de mensagem conterá dois botões: OK e Cancel.
A caixa de mensagem conterá dois botões: Retry e Cancel.
A caixa de mensagem conterá dois botões: Yes e No.
A caixa de mensagem conterá três botões: Yes, No, e Cancel.
Um ícone com um ponto de exclamação será colocado na caixa de
mensagem.
Um ícone com a letra i dentro de um círculo será colocado na caixa de
mensagem.
Um ícone com um ponto de interrogação será colocado na caixa de
mensagem.
Um ícone com o sinal STOP será colocado na caixa de mensagem.
O primeiro botão será o default.
O segundo botão será o default.
O terceiro botão será o default.
O quarto botão será o default.
A caixa de mensagem é mostrada na forma Modal, isto é, o usuário é
obrigado a responder à pergunta antes de passar para o próximo passo
do programa.
- Página 7 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
MB_SYSTEMMODAL
MB_TASKMODAL
MB_DEFAULT_DESKTOP_ONLY
MB_HELP
MB_RIGHT
MB_RTLREADING
MB_SETFOREGROUND
MB_TOPMOST
•
O mesmo que o MB_APPLMODAL, exceto que a caixa de mensagem
tem o estilo WS_EX_TOPMOST. Use a caixa de mensagem systemmodal para informar o usuário sobre erros sérios que devem ser
reparados imediatamente.
O mesmo que o MB_APPLMODAL, exceto que todas as demais janelas
que estiverem abertas serão desabilitadas se o primeiro parâmetro da
caixa de mensagem for NULL.
O desktop que recebe a caixa de mensagem deve ser o desktop padrão,
se não for, a função falha.
Acrescenta um botão de Help na caixa de mensagens. Acionando este
botão ou pressionando F1 gerará um evento de Help.
O texto é justificado à direita.
Mostra a mensagem e o caption da direita para a esquerda no sistema
Hebreu e Árabe.
A caixa de mensagem torna-se uma janela de fundo (foreground
window).
Internamente,
o
Windows
chama
a
função
SetForegroundWindow para a caixa de mensagem.
A caixa de mensagem é criada no estilo de janela WS_EX_TOPMOST.
LÍNGUA: aqui colocamos uma constante que identifica a língua que queremos utilizar nos
captions dos botões. Mostramos as línguas disponíveis, e as sub-línguas quando for o caso:
LANG_AFRIKAANS
LANG_ALBANIAN
LANG_ARABIC
LANG_BASQUE
LANG_BELARUSIAN
LANG_BULGARIAN
LANG_CATALAN
LANG_CHINESE
LANG_CROATIAN
LANG_CZECH
LANG_DANISH
LANG_DUTCH
LANG_ENGLISH
LANG_ESTONIAN
LANG_FAEROESE
LANG_FARSI
LANG_FINNISH
LANG_FRENCH
LANG_GERMAN
LANG_GREEK
LANG_HEBREW
LANG_HUNGARIAN
LANG_ICELANDIC
LANG_INDONESIAN
LANG_ITALIAN
LANG_JAPANESE
LANG_KOREAN
LANG_LATVIAN
LANG_LITHUANIAN
LANG_NEUTRAL
LANG_NORWEGIAN
LANG_POLISH
LANG_PORTUGUESE
LANG_ROMANIAN
LANG_RUSSIAN
LANG_SERBIAN
LANG_SLOVAK
LANG_SLOVENIAN
LANG_SPANISH
LANG_SWEDISH
LANG_THAI
LANG_TURKISH
LANG_UKRANIAN
LANG_VIETNAMESE
SUBLANG_ARABIC_SAUDI_ARABIA
SUBLANG_ARABIC_IRAQ
SUBLANG_ARABIC_EGYPT
SUBLANG_ARABIC_LIBYA
SUBLANG_ARABIC_ALGERIA
SUBLANG_ARABIC_MOROCCO
SUBLANG_ARABIC_TUNISIA
SUBLANG_ARABIC_OMAN
SUBLANG_ARABIC_YEMEN
SUBLANG_ARABIC_SYRIA
SUBLANG_ARABIC_JORDAN
SUBLANG_ARABIC_LEBANON
SUBLANG_ARABIC_KUWAIT
SUBLANG_ARABIC_UAE
SUBLANG_ARABIC_BAHRAIN
SUBLANG_ARABIC_QATAR
SUBLANG_CHINESE_TRADITIONAL
SUBLANG_CHINESE_SIMPLIFIED
SUBLANG_CHINESE_HONGKONG
SUBLANG_CHINESE_SINGAPORE
SUBLANG_DEFAULT
SUBLANG_DUTCH
SUBLANG_DUTCH_BELGIAN
SUBLANG_ENGLISH_UK
SUBLANG_ENGLISH_AUS
SUBLANG_ENGLISH_CAN
SUBLANG_ENGLISH_NZ
SUBLANG_ENGLISH_EIRE
SUBLANG_GERMAN
SUBLANG_GERMAN_SWISS
SUBLANG_GERMAN_AUSTRIAN
SUBLANG_GERMAN_LUXEMBOURG
SUBLANG_GERMAN_LIECHTENSTEIN
SUBLANG_ITALIAN
SUBLANG_ITALIAN_SWISS
SUBLANG_KOREAN
SUBLANG_KOREAN_JOHAB
SUBLANG_NEUTRAL
SUBLANG_NORWEGIAN_BOKMAL
SUBLANG_NORWEGIAN_NYNORSK
SUBLANG_PORTUGUESE
SUBLANG_PORTUGUESE_BRAZILIAN
SUBLANG_SERBIAN_LATIN
SUBLANG_SERBIAN_CYRILLIC
SUBLANG_SPANISH
SUBLANG_SPANISH_MEXICAN
SUBLANG_SPANISH_MODERN
SUBLANG_SPANISH_GUATEMALA
SUBLANG_SPANISH_COSTA_RICA
SUBLANG_SPANISH_PANAMA
SUBLANG_ENGLISH_US
SUBLANG_SPANISH_COLOMBIA
SUBLANG_SPANISH_PERU
SUBLANG_SPANISH_ARGENTINA
SUBLANG_SPANISH_ECUADOR
SUBLANG_SPANISH_CHILE
- Página 8 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
SUBLANG_ENGLISH_SOUTH_AFRICA
SUBLANG_SPANISH_URUGUAY
SUBLANG_ENGLISH_JAMAICA
SUBLANG_SPANISH_PARAGUAY
SUBLANG_ENGLISH_CARIBBEAN
SUBLANG_SPANISH_BOLIVIA
SUBLANG_ENGLISH_BELIZE
SUBLANG_SPANISH_EL_SALVADOR
SUBLANG_ENGLISH_TRINIDAD
SUBLANG_SPANISH_HONDURAS
SUBLANG_FRENCH
SUBLANG_SPANISH_NICARAGUA
SUBLANG_FRENCH_BELGIAN
SUBLANG_SPANISH_PUERTO_RICO
SUBLANG_FRENCH_CANADIAN
SUBLANG_SWEDISH
SUBLANG_FRENCH_SWISS
SUBLANG_SWEDISH_FINLAND
SUBLANG_FRENCH_LUXEMBOURG
SUBLANG_SYS_DEFAULT
SUBLANG_SPANISH_DOMINICAN_REPUBLIC
SUBLANG_SPANISH_VENEZUELA
•
IDENTIFICADOR DO BOTÃO ACIONADO: aqui colocamos uma constante que identifica
qual foi a tecla acionada. Dentre os identificadores podemos enumerar:
IDABORT
IDCANCEL
IDIGNORE
IDNO
IDOK
IDRETRY
IDYES
•
!
O botão Abort foi acionado
O botão Cancel foi acionado
O botão Ignore foi acionado
O botão No foi acionado
O botão OK foi acionado
O botão Retry foi acionado
O botão Yes foi acionado
Veja o aspecto da caixa de mensagem deste programa:
FASE 07: VERIFICANDO GRAVAÇÃO DO DESENHO:
Seria bom que o seu programa testasse, antes de ser encerrado, se a figura que está na tela já foi
gravada.
Para isto, iremos declarar uma variável “Booleana”, de nome Gravou, globalmente:
var
Form1: TForm1;
Tam,
CorPreench: integer;
Gravou: boolean;
implementation
{$R * DFM}
Esta variável vai receber o valor True toda vez que a figura for efetivamente gravada, e o valor False
toda vez que se der um clique no objeto Image1.
Vamos ver como vão ficar estes procedimentos:
Faça asalteração, que aparece em negrito, no evento OnClick do botão SpeedButton2:
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
If SaveDialog1.execute then
begin
Image1.Picture.SaveToFile(SaveDialog1.Filename);
Gravou:= true;
end;
end;
- Página 9 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Faça a alteração, que aparece em negrito, no evento OnMouseDown do objeto Image1:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.Brush.Color:= CorPreench;
Image1.Canvas.Ellipse(x-tam,y-tam,x+tam,y+tam);
Gravou:= false;
end;
Agora, antes de sair do programa, devemos testar o valor da variável Gravou. Se for false é porque
ainda não gravamos, e deveremos dar uma mensagem de advertência.
O melhor local para colocarmos esta advertência, talvez seja, na função Termina_programa:
function TForm1.Termina_programa: boolean;
begin
If not Gravou then
begin
If MessageBoxEx(0, 'A figura não foi gravada. Deseja fazê-lo agora ?', 'ATENÇÃO !!!',
mb_YesNo+mb_IconWarning, lang_portuguese) = idYes
then SpeedButton2Click(Self);
end;
Result:= true;
If MessageBoxEx(0, 'Deseja mesmo sair do programa ?', 'ENCERRAMENTO ...',
MB_YESNO+MB_ICONSTOP+MB_DEFBUTTON2, lang_portuguese) = idNo
then Result:= false;
end;
A novidade que podemos notar nesta rotina, é o aparecimento de uma chamada a um
procedimento gerado pelo próprio Delphi (SpeedButton2Click) e que em cujo parâmetro de entrada,
colocamos a palavra Self para indicar que o objeto atual (Sender) é o próprio. Esta palavra substitui o
parâmetro Sender. Esta chamada evita termos que digitar novamente os comandos para gravação da figura.
!
FASE 08: CARREGANDO UM DESENHO PRONTO:
Para ler uma figura já gravada, iremos acrescentar mais 2 objetos do Delphi: outro SpeedButton
que deverá ser colocado no Panel1 e um objeto OpenPictureDialog.
Vamos incluir estes objetos e alterar algumas de suas propriedades:
SpeedButton3
Glyph
Height
Width
Left
Top
Hint
ShowHint
=
=
=
=
=
=
=
FldrOpen.bmp
37
37
79
3
Abre uma figura existente
True
OpenPictureDialog1
Filter
=
Title
=
BitMaps
| *.bmp
Todos os arquivos | *.*
Qual figura deseja abrir ?
O evento OnClick do SpeedButon3 ficaria assim:
- Página 10 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
If OpenPictureDialog1.execute then
Image1.Picture.LoadFromFile(OpenPictureDialog1.filename);
end;
Não vejo necessidade de maiores explicações, pois, este tipo de procedimento já foi detalhado
anteriormente.
!
FASE 09: DESENHANDO NOVOS ÍCONES:
Vamos dar uma pausa no nosso projeto para podermos explicar como se cria novos ícones. Estou
vendo esta necessidade neste momento porque alguns novos botões que iremos implementar necessitam
de ícones que não estão entre os fornecidos pelo Delphi.
Na realidade, no nosso programa precisaremos de BitMaps e não de ícones, pois, a propriedade
Glyph trabalha com BitMaps, da seguinte forma:
BITMAPS PARA GLYPHS:
As Glyphs admitem até 4 imagens em um mesmo BitMap. Estas imagens são colocadas lado a
lado, sendo que o componente sabe que deverá considerar como uma figura a largura igual à altura da
mesma, isto é, a figura será sempre quadrada. Para se ter uma glyph com 4 figuras, esta deverá ter uma
largura igual a até 4 vezes a altura.
Por exemplo, uma figura com 18 pixels de altura poderá ter: 18 ou 36 ou 54 ou 72 pixels de
largura, dependendo se representará 1, 2, 3 ou 4 figuras.
Porque 4 figuras ? a resposta é simples: cada uma delas representa uma determinada situação que
se encontra o botão acionado:
- A primeira figura é usada quando o botão está habilitado
- A segunda, quando o botão está desabilitado
- A terceira, quando o botão foi clicado
- A quarta, somente para o SpeedButton (não funciona no BitBtn), quando o botão estiver
afundado (Down = true).
A utilização das imagens é automática, e a quantidade delas é determinada na propriedade
NumGlyphs.
Outra característica importante deve ser mencionada: a cor do pixel situado no canto inferior
esquerdo da figura indica a cor que representará a transparência, isto é, se por exemplo, este pixel for
vermelho, todas as partes da figura que forem vermelhas serão transparentes e não vermelhas !
DESENHANDO NOVOS BITMAPS/ICONES/CURSORES:
Para isto, acione no menu do ambiente Delphi a opção Tools # Image Editor, ou diretamente na
barra de tarefas do Windows: Iniciar # Programas # Borland Delphi 4 # Image Editor.
O programa Image Editor tem a seguinte aparência:
Se você abrir no menu a opção File # New, você irá deparar com 5 opções, dentre as quais convém
citar: BitMap File, Icon File e Cursor File, que correspondem, respectivamente, à confecção de BitMaps,
Ícones e Cursores.
- Página 11 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Escolhendo BitMap Files, surge a tela:
Poderemos informar a largura e a altura de nossa imagem. Vamos usar os valores 30 e 30, para
desenharmos uma figura com somente 1 imagem (botão habilitado). Se fôssemos desenhar 2 imagens,
colocaríamos Width = 60 e Height = 30, e assim por diante.
Dando vários Ctrl I poderemos ampliar a nossa área de desenho para facilitar nossa visualização:
Vamos desenhar um ícone que possa representar a mudança do formato do ponto do nosso desenho,
de círculo para quadrado e vice-versa:
Em seguida, grave-o com um nome sugestivo, por exemplo: Circ-Quad.bmp.
Durante o nosso projeto, outros ícones deverão ser criados, por exemplo, um balde para indicar o
preenchimento:
- Página 12 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
!
FASE 10: ALTERANDO A FORMA DO PONTO:
Vamos agora, possibilitar ao usuário alterar o formato do ponto: entre o circular (como já está) e o
quadrado.
Para executar isto, temos que acrescentar mais um objeto SpeedButton, agora dentro do Panel2 e
colocar na propriedade Glyph do mesmo o ícone recém criado:
O seu evento OnClick ficaria assim:
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
Circulo:= not Circulo;
Pincel;
end;
Você pode perceber o aparecimento da variável “circulo”. Esta variável deverá ser declarada
globalmente como do tipo boolean e ela irá informar se a figura do ponto é um CIRCULO (true) ou
QUADRADO (false).
Nota-se também na rotina, a chamada ao procedimento Pincel. Este procedimento deverá ser
modificado para reconhecer o formato do ponto:
procedure TForm1.Pincel;
var x, y: integer;
begin
x:= image2.width div 2;
y:= image2.height div 2;
Image2.picture:= nil;
If corpreench <> Panel4.color then Image2.Canvas.Pen.color:= CorPreench
else Image2.Canvas.Pen.color:= clBlack;
Image2.Canvas.Brush.Color:= CorPreench;
If circulo then Image2.canvas.ellipse(x-tam,y-tam,x+tam,y+tam)
else Image2.canvas.rectangle(x-tam,y-tam,x+tam,y+tam);
end;
No método OnMouseDown do objeto Image1 devemos também fazer uma modificação, para testar o
formato do ponto a desenhar:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
- Página 13 Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.Brush.Color:= CorPreench;
Image1.Canvas.Ellipse( x - tam , y - tam , x + tam , y + tam);
If circulo then Image1.canvas.ellipse(x-tam,y-tam,x+tam,y+tam)
else Image1.canvas.rectangle(x-tam,y-tam,x+tam,y+tam);
Gravou:= false;
end;
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Também teremos que fazer uma ligeira modificação no método do evento OnCreate do objeto Form1, onde é
inicializada a variável “circulo com o valor true:
procedure TForm1.FormCreate(Sender: TObject);
begin
Tam:= 1;
CorPreench:= clBlack;
Circulo:= true;
Pincel;
end;
!
FASE 11: DESENHANDO UMA CURVA CONTÍNUA:
Para tal, acrescente ao projeto mais um SpeedButton (SpeedButton5), também dentro do Panel2.
Sugerimos o seguinte ícone para o mesmo:
Altere a propriedade GroupIndex colocando o valor 1. Esta propriedade numera botões que farão
parte de um grupo onde apenas um deles ficará “afundado” (propriedade Down = true). Quando Down é
verdadeiro o botão fica “afundado”, até que outro botão do mesmo grupo seja acionado, quando então
este último “afunda”, liberando o anterior.
Os demais botões do grupo ainda serão criados. Este é o primeiro deles.
Para haver esta liberação, devemos acrescentar mais um SpeedButton (SpeedButton6), a ser
colocado no Panel2, contendo o seguinte ícone (sugestão):
Neste último botão inserido, deveremos alterar as propriedades:
GroupIndex = 1
Down = true
Para que uma curva seja traçada, é necessário repetir o desenho de um ponto à medida que o mouse
se desloca na tela. Podemos deduzir que o melhor evento a utilizar é o OnMouseMove do objeto Image1:
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
If SpeedButton5.down then {curva}
If shift = [ssLeft] then
begin
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.Brush.Color:= CorPreench;
If circulo then Image1.Canvas.Ellipse(x-tam,y-tam,x+tam,y+tam)
else Image1.Canvas.Rectangle(x-tam,y-tam,x+tam,y+tam);
Gravou:= false;
end;
end;
Observamos na rotina acima que a primeira coisa que fizemos foi verificar se o SpeedButton5 está
“afundado” (down). Se estiver, e o botão esquerdo do mouse estiver acionado, deveremos desenhar o
ponto nas cores da linha e do preenchimento atuais, assim como, na forma de um círculo ou de um
quadrado.
Finalmente, atribuimos false ao valor da variável Gravou, para indicar que ainda não foi gravada a
alteração que o usuário está fazendo no desenho.
- Página 14 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
!
FASE 12: SELECIONANDO UMA ÁREA RETANGULAR:
Image1.Canvas.DrawFocusRect(RetSelect);
Utilizaremos o procedimento DrawFocusRect da propriedade Canvas do objeto Image1 para
desenhar um retângulo dado pelas coordenadas definidas na variável RetSelect cuja declaração será feita a
seguir. Através desta rotina, o retângulo é desenhado fazendo um XOR (ou-exclusivo) com a cor de Brush do
Canvas com a cor dos pontos por onde passa o retângulo, o que nos proporcionará a oportunidade de apaga-lo
sempre que quizermos, bastando chamar novamente tal procedimento, isto é, a execução de dois XOR
seguidos faz retornar à condição inicial .
Para desenhar o retângulo na tela, faremos uso de 2 eventos do objeto Image1:
No evento OnMouseDown iremos acrescentar as linhas em negrito (colocadas abaixo), que farão com
que as variáveis Sx e Sy recebam os valores atuais da posição do “mouse”, caso estejamos acionando o botão
direito do mouse. Estas variáveis irão guardar as coordenadas do canto superior esquerdo do retângulo de
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
If Shift = [ssRight] then
begin
Sx:= x; Sy:= y;
exit;
end;
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.Brush.Color:= CorPreench;
If circulo then Image1.Canvas.Ellipse(x-tam,y-tam,x+tam,y+tam)
else Image1.Canvas.Rectangle(x-tam,y-tam,x+tam,y+tam);
Gravou:= false;
end;
seleção:
No evento OnMouseMove, iremos traçar o retângulo de seleção enquanto movemos o mouse. Para isto,
o retângulo será desenhado e apagado sucessivamente, para dar este efeito de movimento:
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
If shift = [ssRight]) then
begin
Image1.Canvas.DrawFocusRect(RetSelect);
RetSelect:= Rect(Sx,Sy,x,y);
Image1.Canvas.Brush.color:= clAqua;
Image1.Canvas.DrawFocusRect(RetSelect);
exit;
end;
If SpeedButton5.down then {curva}
If shift = [ssLeft] then
begin
Image1.Canvas.Pen.color:= CorPreench;
- Página 15 -
………. Etc …………
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Na rotina, o programa irá fazer o teste se estamos acionando o botão direito do mouse. Se estiver, o
programa fará o seguinte:
a)
desenha o retângulo com as coordenadas atuais guardades na variável RetSelect, que na
primeira vez não tem significado. Nas vezes seguintes, servirá para apagar o último retângulo
desenhado pelo mesmo procedimento repetido na terceira linha logo abaixo.
b)
A variável RetSelect, que nós inventamos, irá guardar as coordenadas do retângulo que serão
transformadas para o formato TRect através da função Rect, para a qual informamos as
coordenadas do canto superior esquerdo do retângulo (Sx,Sy), obtidas no evento
OnMouseDown do objeto Image1 e a do canto inferior direito (x,y), posição atual do ponteiro
do mouse.
c)
Atribuímos à propriedade Brush a cor azul claro (clAqua), para desenhar o retângulo de
seleção nesta cor.
d)
É desenhado o retângulo de
seleção com as coordenadas:
(x,y)
(Sx,Sy)
e)
O comando Exit é utilizado para sair da rotina sem executar as demais linhas da mesma.
Agora, não podemos esquecer de declarar as 3 últimas variáveis incluídas no programa:
var
Form1: TForm1;
Sx, Sy,
Tam,
CorPreench: integer;
Circulo,
Gravou: boolean;
RetSelect: TRect;
!
FASE 13: PERMITINDO SELECIONAR ÁREA EM QUALQUER DIREÇÃO:
Você poderá facilmente constatar que a seleção ora implementada, só permite que arrastemos o
retângulo no sentido sudeste. Nas demais direções o retângulo não se forma.
Para que o retângulo seja desenhado em qualquer direção, temos que alterar algumas linhas do
trecho que desenha tal retângulo no método OnMouseMove do objeto Image1:
A solução encontrada é a de criarmos 2 variáveis “booleanas” que nos informarão se a abcissa e/ou
a ordenada de um dos cantos do retângulo está do outro lado.
Toda vez que iniciamos o desenho do retângulo, atribuímos a Sx e a Sy os valores fixos do primeiro
ponto do retângulo (ver método OnMouseDown do objeto Image1). Só que tal retângulo só pode ser
desenhado no sentido sudeste, e portanto, toda vez que isto não acontecer temos que trocar a posição das
abcissas e/ou ordenadas para que sempre o desenho seja feito no sentido sudeste. Para o usuário, isto será
transparente, pois, o desenho é feito tão rapidamente que ele não perceberá que foi feito neste sentido.
Portanto, digite as instruções que aparecem em negrito e que causam este efeito, além de eliminar a
linha sugerida:
- Página 16 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var trocax, trocay: boolean;
begin
If shift = [ssRight] then
begin
Image1.Canvas.DrawFocusRect(RetSelect);
If Sx > x then trocax:= true else trocax:= false;
If Sy > y then trocay:= true else trocay:= false;
If trocax and trocay then RetSelect:= Rect(x,y,Sx,Sy);
If not trocax and not trocay then RetSelect:= Rect(Sx,Sy,x,y);
If not trocax and trocay then RetSelect:= Rect(Sx,y,x,Sy);
If trocax and not trocay then RetSelect:= Rect(x,Sy,Sx,y);
RetSelect:= Rect(Sx,Sy,x,y);
Image1.Canvas.Brush.color:= clAqua;
Image1.Canvas.DrawFocusRect(RetSelect);
exit;
end;
If SpeedButton5.down then
{curva}
…………. ETC ……………
Verificamos que o valor da variável RetSelect será de acordo com a posição do ponto móvel em
relação ao fixo, do retãngulo de seleção.
Sx > x
Sy > y
Trocax = true
Trocay = true
Sx < x
Sy > y
Trocax = false
Trocay = true
Sx < x
Sy < y
Trocax = false
Trocay = false
!
Sx > x
Sy < y
Trocax = true
Trocay = false
As setas indicam o sentido do
movimento
FASE 14: COLORINDO UMA ÁREA DO DESENHO:
Para este tipo de efeito, utilizaremos o método FloodFill do Canvas. A sintaxe deste método está
descrita na página 81.
Para isto, iremos acrescentar mais um botão (SpeedButton7), dentro do objeto Panel2, alterando a
sua propriedade GroupIndex para 1. Para este botão, sugerimos o ícone:
No evento OnMouseDown do objeto Image1 digite o trecho que aparece em negrito:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var cor: TColor;
begin
If Shift = [ssRight] then
begin
Sx:= x; Sy:= y;
exit;
end;
If SpeedButton7.Down then
- Página 17 begin
Cor:= Image1.Canvas.Pixels[x,y];
Image1.Canvas.Brush.Color:= CorPreench;
Image1.Canvas.FloodFill(x,y,Cor,fsSurface);
Exit;
end;
If SpeedButton6.down then
… etc …
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Traduzindo o trecho acrescentado (em negrito):
Se o botão SpeedButton7 estiver “afundado”, o programa realizará os seguintes passos:
a)
A variável local “Cor” irá pegar a cor do pixel onde aconteceu o clique do ponteiro do mouse. Esta
cor será um dos parâmetros do método FloodFill, isto é, irá informar qual é a cor que será
substituída pela cor atual de preenchimento (CorPreench).
b) Atribuímos a cor de preenchimento atual à propriedade Brush do Canvas do objeto Image1.
c) Executamos o método FloodFill que irá preencher toda a área que contiver a cor “Cor” com a cor
“CorPreench” até encontrar uma cor diferente de “Cor” (fsSurface).
d) O comando “Exit” faz com que o controle do programa saia deste método sem executar as demais
linhas do mesmo.
!
FASE 15: BOTÃO PARA SAIR DO PROGRAMA:
Desta vez, iremos sair do programa fechando o formulário principal, para que tenhamos certeza que
o evento OnClose do formulário seja chamado, pois, neste evento, programamos a saída do programa
testando se o desenho foi gravado e perguntando se realmente o usuário deseja sair !
Para implentar isto, acrescente mais um botão SpeedButton no Panel1 e digite no seu evento
OnClick a seguinte linha de comando:
Form1.close;
O ícone utilizado foi o DoorShut.bmp encontrado na pasta: \Arquivos de programas\Arquivos
comuns\Borland Shared\Images\Buttons.
!
FASE 16: DESENHANDO FIGURAS GEOMÉTRICAS SIMPLES:
Vamos acrescentar mais 3 botões SpeedButton: o primeiro irá desenhar retângulos, o segundo
elipses e o terceiro linhas retas. Sugerimos para ícones os seguintes desenhos:
Abaixo descrevemos as modificações realizadas nos eventos OnMouseDown e OnMouseMove do
objeto Image1, pois, é aqui que os desenhos acontecem:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var cor: TColor;
begin
If (Shift = [ssRight]) or
(SpeedButton9.down) or
(SpeedButton10.down) or
(SpeedButton11.down) then
begin
Sx:= x; Sy:= y;
exit;
end;
If SpeedButton7.Down then
… etc …
No evento OnMouseMove de Image1 faça as alterações que aparecem em negrito:
- Página 18 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var trocax, trocay: boolean;
begin
If SpeedButton9.down or
SpeedButton10.down or
SpeedButton11.down then
begin
Fx:= x; Fy:= y;
end;
If shift = [ssRight] then
begin
. . . . etc . . . . .
Na rotina acima, atribuímos a Fx o valor atual da abcissa x do mouse e a Fy o valor atual da ordenada
y do mouse.
Se rodássemos o programa agora, provavelmente daria um erro de sintaxe, pois, não declaramos
ainda as variáveis Fx e Fy. Devemos fazê-lo agora:
var
Form1: TForm1;
Sx,Sy,
// coordenadas do canto superior esquerdo de uma área selecionada
Fx,Fy,
// coordenadas do canto inferior direito de uma área selecionada
Tam,
CorPreench: integer;
Circulo,
Gravou: boolean;
RetSelect: TRect;
- Página 19 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Você já deve ter percebido que o que fizemos não irá desenhar nenhuma figura geométrica. O problema é
que temos que escolher um evento para realizar isto. Se imaginarmos como o usuário estará operando o
programa neste momento, poderemos concluir que o melhor evento é o OnMouseUp, pois, após ter “esticado”
o retângulo, provavelmente ele irá soltar o botão do mouse, o que fará acionar o evento escolhido.
Por esta razão, apresentamos a seguir os comandos de desenho de figuras, colocados dentro do evento
OnMouseUp do objeto Image1.
Para desenhar um retângulo, não utilizamos o método Rectangle, pois, o mesmo desenha o retângulo
opaco, isto é, preenchido com a cor de brush. Para desenharmos apenas o contorno do retângulo, escolhemos
o método PolyLine que desenha uma série de linhas interligadas, cujos pontos são dados por um vetor
contendo dados do tipo Tpoint.
O tipo Tpoint é um registro contendo os campos X e Y do tipo inteiro.
Internamente, Tpoint é declarado como:
Tpoint = Record
X, Y: integer;
end;
Para guardarmos os pontos da “polyline” declaramos a variável P da seguinte forma:
var P: array[1..5] of Tpoint;
Para desenhar uma elipse, não utilizamos o método Ellipse, pois, da mesma forma que o retângulo,
este desenho será opaco, ou seja, preenchido com a cor de brush. Conseguiremos desenhar apenas o
contorno da elipse se fizermos uso do método Arc, cuja sintaxe já mencionamos na página 78.
Para desenhar a reta, utilizamos dois métodos: MoveTo, para colocar o início da reta nas
coordenadas especificadas; e o método LineTo, que desenha a reta do último ponto marcado até o ponto
informado nos parâmetros deste método. Resumindo: uma reta será traçada do ponto (Sx,Sy) até ao
ponto (Fx,Fy), pontos que correspondem à diagonal do retângulo de seleção.
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var P: array[1..5] of Tpoint;
begin
// Desenha o retângulo
If SpeedButton9.Down and (button = mbRight) then
If (Sx <> Fx) or (Sy <> Fy) then
begin
RetSelect:= Rect(0,0,0,0);
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.pen.Width:= 2 * Tam;
P[1].X:= Sx; P[1].Y:= Sy;
P[2].X:= Fx; P[2].Y:= Sy;
P[3].X:= Fx; P[3].Y:= Fy;
P[4].X:= Sx; P[4].Y:= Fy;
p[5]:= p[1];
Image1.Canvas.PolyLine(P);
Exit;
end;
- Página 20 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
// Desenha a elipse
If SpeedButton10.Down and (button = mbRight) then
If (Sx <> Fx) or (Sy <> Fy) then
begin
Image1.Canvas.DrawFocusRect(RetSelect);
RetSelect:= Rect(0,0,0,0);
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.pen.Width:= 2 * Tam;
Image1.Canvas.Arc(Sx,Sy,Fx,Fy,Fx,Fy,Fx,Fy);
Exit;
end;
// Desenha a reta
If SpeedButton11.Down and (button = mbRight) then
If (Sx <> Fx) or (Sy <> Fy) then
begin
Image1.Canvas.DrawFocusRect(RetSelect);
RetSelect:= Rect(0,0,0,0);
Image1.Canvas.Pen.color:= CorPreench;
Image1.Canvas.pen.Width:= 2 * Tam;
Image1.Canvas.MoveTo(Sx,Sy);
Image1.Canvas.LineTo(Fx,Fy);
Exit;
end;
end;
Funcionamento da rotina:
Retângulo:
a.
b.
c.
d.
e.
f.
g.
Se o botão de retângulo está acionado, então pode desenhar o retângulo.
Testamos, em seguida, se o ponteiro do mouse foi movido, verificando se os valores de
“Sx” e de “Sy” estão diferentes da posição do mouse ao soltar o botão. Isto foi feito para
evitar desenhar o retângulo em cima do ponto inicial, ou seja, apareceria um ponto no
desenho.
Zeramos “RetSelect” para que o retângulo de seleção desapareça ao movermos o mouse.
Atribuímos à cor da linha a mesma cor de preenchimento e alteramos o tamanho do ponto
(width) para 2 vezes o valor de “Tam” (lembre que Tam representa o raio do ponto e não o
seu diâmetro)
Para desenhar o retângulo, atribui-se à variável “P” as coordenadas de cada um dos cantos
do mesmo, fazendo um polígono fechado (por isto tem 5 valores).
O desenho é efetivamente realizado ao ser acionado o método PolyLine do Canvas.
Agora, saímos da rotina (Exit).
Elipse/Círculo:
a)
b)
c)
d)
e)
Primeiramente, como no retângulo fizemos os testes iniciais.
Também, conforme o retângulo, “apagamos” o retângulo de seleção.
Atribuímos as cores e tamanho da pena
Desenhamos o arco fechado (ellipse ou círculo)
Saímos da rotina.
Linha Reta:
a)
b)
c)
Para a reta, repetimos as operações iniciais.
Através do método MoveTo posicionamos o primeiro ponto da reta (Sx,Sy).
Através do método LineTo desenhamos a reta do primeiro ponto até o atual (Fx,Fy).
- Página 21 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
!
FASE 17: DESENHANDO TEXTO:
Acrescente ao projeto mais um SpeedButton no Panel2, e altere as seguintes propriedades do
mesmo:
GroupIndex
Caption
Font.Name
Font.Size
Font.Style
=
=
=
=
=
1
T
Times New Roman
20
fsBold
Acrescente também um objeto FontDialog, que está na aba “Dialogs”.
No método do seu evento OnClick digite os comandos necessários a alterar a fonte dos caracteres
que serão desenhados no Canvas do objeto Image1, assim como a dos caracteres que serão digitados
dentro de um objeto Edit que será acrescentado ao projeto a seguir:
procedure TForm1.SpeedButton12Click(Sender: TObject);
begin
If FontDialog1.execute then
begin
Image1.Canvas.Font:= FontDialog1.font;
Edit1.Font:= FontDialog1.font;
end;
end;
Acrescente agora um objeto Edit colocando-o dentro do objeto Image1. Este objeto Edit1 será o
meio pelo qual o usuário poderá digitar o texto que quer colocar no desenho, desfrutando de todas as
possibilidades de edição, sem que nós tenhamos que nos preocupar com elas.
Depois que o usuário digitar o seu texto é que o colocaremos no Canvas do Image1, tomando o
cuidado de fazer com que o usuário não perceba este “macete”. Para isto, iremos colocar o objeto Edit1
exatamente no local onde o usuário escolheu para colocar o texto, e tornando-o invisível depois que o
texto for digitado.
Para conseguir estes efeitos, altere as seguintes propriedades de Edit1:
Text
Visible
BorderStyle
=
=
=
(deixar em branco)
false
bsNone
Inicialmente o Edit1 está invisível. Para torná-lo visível e ter o foco do cursor, iremos utilizar o
método do evento OnMouseDown do Image1, da seguinte forma:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var cor: TColor;
begin
If (Shift = [ssRight]) or
(SpeedButton9.down) or
(SpeedButton10.down) or
(SpeedButton11.down) then
begin
Sx:= x; Sy:= y;
exit;
end;
If SpeedButton12.Down then
begin
Edit1.left:= x;
Edit1.top:= y+panel1.height;
Edit1.width:= Image1.width-x;
Edit1.Height:= Trunc(Edit1.font.Size * 1.5);
Edit1.visible:= true;
Edit1.setfocus;
Exit;
end;
If SpeedButton7.Down then
. . . . . ETC . . . . .
- Página 22 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Se o SpeedButton12 estiver “afundado”, significa que queremos escrever um texto. Por isto
alteramos a posição do objeto Edit1 através dos valores de suas propriedades Left e Top. Estas
propriedades recebem o valor da coordenada atual do mouse acrescida da altura do painel 1, pois, as
mesmas se referem à distancia do objeto Edit1 até uma das laterais do formulário, e não do objeto
Image1.
Tivemos o cuidado também de aumentar o comprimento de Edit1 para que o texto não fique
“rolando” horizontalmente, assim como a sua altura.. O comprimento é representado pela propriedade
Width, cujo valor será igual ao comprimento horizontal do Image1 subtraído da abcissa do ponteiro do
mouse. Já a altura é representada pela propriedade Height, cujo valor é de uma vez e meia o tamanho da
fonte.
Em seguida, tornamos o objeto Edit1 visível e depois colocamos o foco no mesmo (onde o cursor
de texto irá ficar).
Finalmente, saímos da rotina sem executar as demais linhas.
Isto não faz com que o texto seja desenhado !
Para desenharmos o texto, iremos utilizar o método TextOut. Iremos fazer uso do evento
OnKeyPress do objeto Edit1 para executá-lo, pois, é fácil de deduzir que a transposição do texto digitado
em Edit1 para o desenho deve acontecer quando o usuário acionar a tecla [Enter]. E o melhor local para
testar se tal tecla foi acionada é no evento mencionado:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
If key = #13 then
begin
Edit1.visible:= false;
Image1.Canvas.Brush.color:= Image1.Canvas.Pixels[Edit1.left,Edit1.top];
Image1.Canvas.TextOut(Edit1.left,Edit1.top-panel1.Height,Edit1.text);
Edit1.text:= '';
Image1.Canvas.Brush.color:= CorPreench;
end;
end;
Se a tecla acionada for o [Enter], cujo código ASCII é 13, faremos:
a) O objeto Edit1 se tornará novamente invisível.
b) A cor de fundo do texto será a mesma cor do pixel localizado na posição do canto
superior esquerdo do objeto Edit1, que agora não está mais lá.
c) O texto é “desenhado” no mesmo local onde estava o Edit1 através do método TextOut
do Canvas do objeto Image1.
d) Em seguida, apagamos o texto do objeto Edit1, embora o objeto já esteja invisível.
e) Retornamos a cor de preenchimento do Canvas para a cor corrente.
!
FASE 18: CAPTURANDO A COR DO PIXEL:
Vamos agora, possibilitar ao programa “pegar” uma cor que já esteja na tela para aplicá-la em
outro local:
Acrescente ao projeto mais um SpeedButton no Panel2, e altere a sua propriedade GroupIndex para
1. Para colocar na propriedade Glyph sugerimos você criar um ícone como este:
Para conseguir o efeito desejado, basta que altere mais uma vez o método do evento
OnMouseDown, acrescentando as linhas que aparecem em negrito na listagem a seguir:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var cor: TColor;
begin
If (Shift = [ssRight]) or
(SpeedButton9.down) or
(SpeedButton10.down) or
(SpeedButton11.down) then- Página 23 begin
Sx:= x; Sy:= y;
exit;
end;
If SpeedButton13.Down then
begin
CorPreench:= Image1.Canvas.Pixels[x,y];
Pincel;
Exit;
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
No trecho acima destacado, verifica-se se o SpeedButton13 está “afundado”. Se estiver, é porque
foi selecionado o “conta-gotas”:
a) Primeiramente, altera-se a cor de preenchimento (CorPreench), atribuindo-se à mesma a cor do
pixel onde está o cursor do mouse (“chupando” a cor).
b) Em seguida, chama-se a rotina “Pincel” para atualizar a forma e a cor do preview do ponto.
c) Finalmente, saímos da rotina sem executar as demais linhas da mesma.
!
FASE 19: IMPRIMINDO O DESENHO:
Para completar o nosso projeto vamos implementar a possibilidade de imprimir o desenho que
estiver na tela.
Basta que criemos um formulário de relatório (Quick Report) e nele coloquemos um objeto
QRImage, e transportemos para o mesmo a imagem que se encontra no objeto Image1.
O melhor evento para se fazer isto é o Onclick de um novo objeto SpeedButton que iremos
acrescentar ao projeto.
Acrescente, portanto, ao projeto mais um SpeedButton, colocando-o no Panel1 e coloque na sua
propriedade Glyph o ícone “Printer.bmp” que podemos encontrar na pasta: \Arquivos de
Programas\Arquivos Comuns\Borland Shared\Images\Buttons.
Agora, vá ao menu File " New " aba Forms " duplo clique no ícone Quick Report List
Um novo formulário será criado. Neste novo formulário faça:
a) Apague as “Bands”, deixando apenas a de nome Title.
b) Aumente o tamanho da mesma e acrescente a ela um objeto QRImage. Com o tamanho
que gostaria de imprimir o desenho.
c) Dê um clique em TitleBand e acione o método do evento Before Print da mesma,
acrescentando nele a linha que aparece em negrito:
procedure TQRListForm.TitleBand1BeforePrint(Sender: TQRCustomBand;
var PrintBand: Boolean);
begin
QRImage1.Picture:= Form1.Image1.picture;
end;
A linha acrescentada, transporta a imagem que se encontra no objeto Image1 que está no
formulário Form1, para o objeto QRImage1 que está no formulário QRListForm.
O evento BeforePrint, é acionado “antes de iniciar” a impressão da “band” Title.
- Página 24 -
LINGUAGEM DE PROGRAMAÇÃO DELPHI
Prof. Alberto Cezar de Carvalho
Para realmente conseguirmos imprimir alguma coisa, temos que programar o evento OnClick do
SpeedButton14. Digite o que aparece em negrito:
procedure TForm1.SpeedButton14Click(Sender: TObject);
begin
QRListForm.QuickRep1.Preview; // para imprimir direto coloque Print ao invés
// de Preview
end;
Ao rodar o programa irão surgir duas caixas de mensagens perguntando se pode declarar a
Unit1 dentro da Unit2, assim como a Unit2 dentro da Unit1. Responda afirmativamente às duas
solicitações.
!
FASE 23: OUTRAS IMPLEMENTAÇÕES:
Vamos considerar o nosso projeto terminado !!!
Outras implementações podem ser incorporadas. Se tiver interesse, tente fazê-las.
Por exemplo:
-
Poder modificar o tipo de linha do desenho;
Poder alterar o estilo de preenchimento;
Poder mover uma área selecionada dentro do desenho;
Poder inserir outros desenhos dentro de uma área previamente selecionada;
Poder girar o desenho;
Poder trocar uma cor por outra em todo o desenho;
Poder alterar o tamanho do desenho na impressão;
Poder desenhar retângulos ou elipses já preenchidos;
Poder desenhar linhas sucessivas (polylines);
Etc ...
$$$$$$$$$$$$$$$$$$$$$$$$$$$
- Página 25 -
Download

OS OBJETOS DA VIDA REAL