delphi canvas

14
DELPHI 4.0 Capítulo 5: Gráficos 56 Anotações: 5. GRÁFICOS 5.1. O CANVAS O canvas (tela) representa uma superfície em um objeto onde se pode desenhar um bitmap. O can- vas é sempre uma propriedade de alguma coisa e nunca uma classe ou objeto por si mesmo. Quando se deseja desenhar ou pintar sobre um objeto, deve-se desenhar ou pintar sobre o canvas a ele associado. Operações de desenho envolvem a manipulação de pixels individuais de modo a se desenhar pon- tos ou linhas. Por exemplo, a cor de um pixel pode ser alterada com a seguinte instrução: Canvas.Pixels [10, 10] := clRed; Operações de pintura envolvem a manipulação de grandes quantidades de pixels. Geralmente, pin- tura inclui desenho. Para desenhar ou pintar, o usuário provavelmente pensará em usar o mouse. Antes de implemenatr métodos de desenho, portanto, é necessário ver como o Delphi pode responder a eventos de mouse. 5.2. RESPONDENDO AO MOUSE Existem quatro tipos de eventos de mouse que podem capturados por um aplicativo. Destes, três são realmente causados por ações do mouse: Mouse-Down, Mouse-Up e Mouse-Move. Um querto evento de mouse seria o Click, mas este evento é um pouco diferente, correspondendo a uma sequência completa que compreende clicar e liberar o botão esquerdo do mouse. O evento Click não é capaz de diferenciar entre os botões do mouse ou detectar teclas pressionadas junto com o botão do mouse. Os eventos OnMouseDown, OnMouseMove e OnMouseUp repassam os seguintes parâmetros: Parâmetro Significado Sender O objeto que causou o evento Button Indica qual o botão envolvido no evento: mbLeft, mbMiddle, or mbRight Shift Indica o estado das teclas Alt, Ctrl e Shift keys du- rante o evento de mouse X, Y São as coordenadas da tela onde ocorreu o evento.

Upload: roklen

Post on 24-Oct-2015

84 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 56

Anotações:

5. GRÁFICOS

5.1. O CANVAS

O canvas (tela) representa uma superfície em um objeto onde se pode desenhar um bitmap. O can-vas é sempre uma propriedade de alguma coisa e nunca uma classe ou objeto por si mesmo.

Quando se deseja desenhar ou pintar sobre um objeto, deve-se desenhar ou pintar sobre o canvas a ele associado.

Operações de desenho envolvem a manipulação de pixels individuais de modo a se desenhar pon-

tos ou linhas. Por exemplo, a cor de um pixel pode ser alterada com a seguinte instrução:

Canvas.Pixels [10, 10] := clRed;

Operações de pintura envolvem a manipulação de grandes quantidades de pixels. Geralmente, pin-tura inclui desenho. Para desenhar ou pintar, o usuário provavelmente pensará em usar o mouse. Antes de implemenatr métodos de desenho, portanto, é necessário ver como o Delphi pode responder a eventos de mouse.

5.2. RESPONDENDO AO MOUSE

Existem quatro tipos de eventos de mouse que podem capturados por um aplicativo. Destes, três

são realmente causados por ações do mouse: Mouse-Down, Mouse-Up e Mouse-Move. Um querto evento de mouse seria o Click, mas este evento é um pouco diferente, correspondendo a uma sequência completa que compreende clicar e liberar o botão esquerdo do mouse. O evento Click não é capaz de diferenciar entre os botões do mouse ou detectar teclas pressionadas junto com o botão do mouse.

Os eventos OnMouseDown, OnMouseMove e OnMouseUp repassam os seguintes parâmetros:

Parâmetro Significado

Sender O objeto que causou o evento Button Indica qual o botão envolvido no evento: mbLeft,

mbMiddle, or mbRight Shift Indica o estado das teclas Alt, Ctrl e Shift keys du-

rante o evento de mouse X, Y São as coordenadas da tela onde ocorreu o evento.

Page 2: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 57

Anotações:

O Delphi gera automaticamente um manipulador de eventos para os eventos de Mouse, os quais têm a seguinte forma:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

end;

Por exemplo, o trecho de código a seguir mostrará a palvra “Aqui !” nas coordenadas da tela onde o

mouse for clicado. procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Canvas.TextOut(X, Y, 'Aqui!');

end;

Podemos pensar em desenhar linhas retas com o mouse, como fazem programas de edição de figu-

ras. Clicando com o mouse, definimos o início da linha a ser desenhada. Para isto, usamos o método Mo-veTo para definir uma nova posição gráfica (a posição do último evento gráfico na tela).

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Canvas.MoveTo(X, Y);

end;

Pressionando o mouse, agora, definimos a posição da caneta (pen position). Para desenhar a linha, devemos capturar o evento OnMouseUp e definir as coordenadas da tela onde o usuário liberou o mouse.

Um evento OnMouseUp ocorre sempre que o usuário libera o botão do mouse sobre um objeto. Este evento, por si mesmo, não detecta o movimento do mouse. Podemos usar o método LineTo para desenhar uma linha reta que irá da posição da caneta (PenPos) até a coordenada onde o mouse foi liberado:

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Canvas.LineTo(X, Y);

end;

Page 3: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 58

Anotações:

Por enquanto, o usuário não pode ver a linha que está FlagDesenho. Para que isto seja possível,

devemos capturar o evento OnMouseMove e usá-lo para desenhar uma “inha elástica”. O evento OnMouseMove ocorre periodicamente, quando o usuário move o mouse sobre um objeto.O exem-plo a seguir mostra como desenhar linhas retas a partir da PenPos até a coordenada onde ocorrre o evento OnMouseMove. Entretanto, por enquanto, todos os desenhos intermediários aparecem e não são apagados.

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Canvas.LineTo(X, Y);

end;

Note que o evento OnMouseMove ocorre mesmo se o usuário não pressionar qualquer botão. Se você quizer detectar se um botão, por exemplo, o botão direito, foi pressionado, será necessário adicionar um campo (field) ao formulário.

Quando você adiciona um componente a um formulário, o Delphi também adiciona um campo que representa o componente para o formulário. Você pode se referir ao componente pelo nome do campo. Você também pode inserir campos, editando a declaração de tipos (type) na parte de cima da unidade do formulá-rio. Para detectar se o botão do mouse foi pressionado, basta adicionar um campo do tipo Boolean.

O seguinte trecho de código declara dois campos, um do tipo Boolean e outro do tipo Tpoint, que servirá para armazenar coordenadas:

type

TForm1 = class(TForm)

procedure FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

procedure FormMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

procedure FormMouseMove(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

public

FlagDesenho: Boolean; {campo para detectar se um botão foi .

pressionado}

Origem, MovePt: TPoint; { campo para armazenar pontos}

end;

A seguir, o campo FlagDesenho será feito igual a True no início do evento OnMouseDown, e igual a false no evento OnMouseUp.

Page 4: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 59

Anotações:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

FlagDesenho := True;

Canvas.MoveTo(X, Y);

end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Canvas.LineTo(X, Y);

FlagDesenho := False;

end;

A procedure do evento OnMouseMove deve ser modificada para desenhar linhas apenas se o botão tiver sido pressionado.

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if FlagDesenho then

Canvas.LineTo(X, Y);

end;

O problema, agora, é que em vez de uma linha reta, o que obtemos é uma linha desenhada a mão li-

vre. Isto ocorre porque, cada vez que uma linha é desenhada, o mouse atualiza a PenPos do objeto Canvas. Para resolver este problema, devemos armazenar as coordenadas do evento OnMouseDown inicial e dese-nhar a linha a partir delas.

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

FlagDesenho := True;

Canvas.MoveTo(X, Y);

Origem := Point(X, Y);

end;

Page 5: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 60

Anotações:

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Canvas.MoveTo(Origem.X, Origem.Y);

Canvas.LineTo(X, Y);

FlagDesenho := False;

end;

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if FlagDesenho then

begin

Canvas.MoveTo(Origem.X, Origem.Y);

Canvas.LineTo(X, Y);

end;

end;

Note a maneira usada para nos referirmos ao campo Origem (Origem.X e Origem.Y).

O que temos por enquanto é o seguinte: o evento OnMouseDown fixa as coordenadas do evento e define a PenPos. OnMouseMove desenha uma linha reta sempre começando da Origem até as coordenadas atuais. A linha final é fixada no evento OnMouseUp. Contudo, as linhas intermediárias ainda não sãio apa-gadas. Isto pode ser corrigido apagando-se cada linha antes que a próxima seja desenhada. Um novo cam-po, denominado MovePonto, será usado para memorizar a linha anterior. Além disso, para apagar uma linha, é mais fácil desenhar outra linha sobre ela, com o modo de desenho da caneta (Pen.Mode) definido para pmNotXor.

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

. Shift: TShiftState; X, Y: Integer);

begin

FlagDesenho := True;

Canvas.MoveTo(X, Y);

Origem := Point(X, Y);

MovePonto := Point(X, Y); { memoriza as coordenadas último

movimento}

end;

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if FlagDesenho then

Page 6: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 61

Anotações:

begin

Canvas.Pen.Mode := pmNotXor; { usa o modo XOR para .

desenhar}

Canvas.MoveTo(Origem.X, Origem.Y); {move a caneta para a

origem}

Canvas.LineTo(MovePonto.X, MovePonto.Y); { apaga a linha .

anterior}

Canvas.MoveTo(Origem.X, Origem.Y); { volta para a origem}

Canvas.LineTo(X, Y); { desenha a nova .

linha}

end;

MovePonto := Point(X, Y); { memoriza as coordenadas .

para o . próximo movimento}

Canvas.Pen.Mode := pmCopy; {retorna ao modo Copy (default)]

end;

O resultado deve ser uma linha reta elástica, que pode ser esticada pela tela com o evento OnMou-seMove e fixa com o evento OnMouseUp. Note que o campo MovePonto, do tipo Tpoint, deve ser definido na seção Type, juntamente com Origem e FlagDesenho

5.3. DESENHANDO FIGURAS

O próximo passo do nosso programa gráfico é ser capza de desenhar figuras como retângulos e elipses. Para tanto, precisamos definir qual ferramenta de desenho será usada e a maneira mais fácil de fazer isto, em Pascal, é usar um tipo enumerado, que pode ser declarado da seguinte forma: type TFerramenta = (frLinha, frRetângulo, frElipse, frRetRedondo);

Por convenção, identificadores de tipocomeçam com a letra T. e grupos de constantes começam com

o mesmo prefixo de duas letras. A declaração do tipo Tferramenta é similar a declarar constantes separadas: const

frLinha = 0;

frRetângulo = 1;

frElipse = 2;

frRetRedondo = 3;

Page 7: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 62

Anotações:

Entretanto, a declaração de um tipo enumerado apresenta certas vantagens, pois não será possível atribuir à variável um valor não definido. Caso isso aconteça, um erro de compilação é gerado. O próximo passo é declarar um campo Ferramenta como pertencente ao tipo Tferramenta.

type

TFerramenta = (frLinha, frRetângulo, frElipse, frRetRedondo);

TForm1 = class(TForm)

public

FlagDesenho: Boolean;

Origem, MovePonto: TPoint;

Ferramenta: TDrawingTool;

end;

É conveniente lembrar que todos os objetos inicializam todos os seus campos em zero, o que signi-fica que o valor inicial de Ferramenta será frLinha.

Você pode, agora, posicionar quatro botões do tipo SpeedButtons no formulário e usá-los para defi-nir a ferramenta de desenho a ser usada. Por exemplo, se o nome deste botões forem spbLinha, spbRetân-gulo, spbElipse e spbRetRedondo, os manipuladores de eventos serão, respectivemente:

procedure TForm1.spbLinhaClick(Sender: TObject);

begin

Ferramenta := frLinha;

end;

procedure TForm1.spbRetânguloClick(Sender: TObject);

begin

Ferramenta := frRetângulo;

end;

procedure TForm1.spbElipseClick(Sender: TObject);

begin

Ferramenta := frElipse;

end;

Page 8: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 63

Anotações:

procedure TForm1.sobRetRedondoClick(Sender: TObject);

begin

Ferramenta := frRetRedondo;

end;

A escolha de quais procedimentos serão executados quando o usuário pressionar cada um dos bo-tões poderia ser feita com instruções If ..Then. Entretanto, o Object Pascal fornece o comando Case, que é muito mais eficiente neste caso. Além disso, para desenhar figuras basta executar o método apropriado:

procedure TForm1.FormMouseUp(Sender: TObject);

begin

case Ferramenta of

frLinha:

begin

Canvas.MoveTo(Origem.X, Origem.Y);

Canvas.LineTo(X, Y)

end;

frRetângulo: Canvas.Rectangle(Origem.X, Origem.Y, X, Y);

frElipse: Canvas.Ellipse(Origem.X, Origem.Y, X, Y);

frRetRedondo: Canvas.RoundRect(Origem.X, Origem.Y, X, Y, .

(Origem.X - X) div 2, (Origem.Y - Y) div 2);

end;

FlagDesenho := False;

end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: .

Integer);

begin

if FlagDesenho then

begin

Canvas.Pen.Mode := pmNotXor;

case Ferramenta of

frLinha :

begin

Canvas.MoveTo(Origem.X, Origem.Y);

Canvas.LineTo(MovePonto.X, MovePonto.Y);

Canvas.MoveTo(Origem.X, Origem.Y);

Canvas.LineTo(X, Y);

end;

frRetângulo :

begin

Page 9: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 64

Anotações:

Canvas.Rectangle(Origem.X, Origem.Y, MovePonto.X, .

MovePonto.Y);

Canvas.Rectangle(Origem.X, Origem.Y, X, Y);

end;

frElipse :

begin

Canvas.Ellipse(Origem.X, Origem.Y, X, Y);

Canvas.Ellipse(Origem.X, Origem.Y, X, Y);

end;

frRetRedondo :

begin

Canvas.RoundRect(Origem.X, Origem.Y, X, Y,

(Origem.X - X) div 2, (Origem.Y - Y) div 2);

Canvas.RoundRect(Origem.X, Origem.Y, X, Y,

(Origem.X - X) div 2, (Origem.Y - Y) div 2);

end;

end;

MovePonto := Point(X, Y);

end;

Canvas.Pen.Mode := pmCopy;

end;

Você deve ter notado que há muita repetição de código nestas duas procedures. Quando isto acon-tece, é melhor escrever uma sub-rotina separada que será acessada por partes diferentes do programa, evi-tando repetição desnecessária.

Como adicionar uma sub-rotina (método) a um formulário:

1. Adicione a declaração do método ao objeto formulário. Isto pode ser feito dentro das seções public ou private da unidade associada ao formulário:

2. Escreva a implementação do método na seção implementation. No nosso caso, o código fica da seguinte forma:

. type

. TForm1 = class(TForm)

.

.

.public

{ Public declarations }

procedure DesenhaForma(SupEsq, InfDir: TPoint; AModo: TPenMode);

end;

Page 10: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 65

Anotações:

Note que DesenhaForma recebe três parâmetros, correspondendo às coordenadas do canto superior esquerdo, às coordenadas do canto inferior direito e ao modo de desenho. A implementação não traz muitas novidades.

.implementation

{$R *.FRM}

.

procedure TForm1.DesenhaForma(SupEsq, InfDir: TPoint; AModo: TPenMode);

begin

with Canvas do

begin

Pen.Mode := AModo;

case Ferramenta of

frLinha:

begin

MoveTo(SupEsq.X, SupEsq.Y);

LineTo(InfDir.X, InfDir.Y);

end;

frRetângulo: Rectangle(SupEsq.X, SupEsq.Y, InfDir.X, .

InfDir.Y);

frElipse: Ellipse(SupEsq.X, SupEsq.Y, InfDir.X, .

InfDir.Y);

frRetRedondo: RoundRect(SupEsq.X, SupEsq.Y, InfDir.X, .

InfDir.Y,

(SupEsq.X - InfDir.X) div 2, (SupEsq.Y - InfDir.Y) div .

2);

end;

end;

end;

As procedures dos eventos OnMOuseUp e OnMOuseMove precisam ser modificadas:

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

. DesenhaForma(Origem, Point(X, Y), pmCopy);

. FlagDesenho := False;

. end;

procedure TForm1.FormMouseMove(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Page 11: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 66

Anotações:

if FlagDesenho then

begin

DesenhaForma(Origem, MovePonto, pmNotXor);

MovePonto := Point(X, Y); { record the current point }

DesenhaForma(Origem, MovePonto, pmNotXor);

end;

end;

5.4. MUDANDO O ESTILO DE DESENHO E PINTURA

MUDANDO O ESTILO DA CANETA O estilo da caneta pode ser definido para uma das seguintes constantes:

* psSolid; * psDash; * psDot; * psDashDot; * psDashDotDot; * psClear.

Por exemplo, podemos escrever:

Canvas.Pen.Style := psDash

MUDANDO A COR DA CANETA

A cor da caneta pode ser alterada por meio da propriedade Color. Por exemplo,

Canvas.Pen.Color := RGB(100, 200, 57);

Page 12: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 67

Anotações:

MUDANDO A ESPESSURA DA CANETA

A espessura (width) da caneta é um número que determina a espessura, em pixels, da linha a ser desenhada. O valor default é um (1).

Canvas.Pen.Width := 5;

MUDANDO O ESTILO DO PINCEL

O estilo do pincel determina qual o padrão usado para preencher objetos fechados, podendo assumir

um dos seguintes valores:

bsSolid;

bsClear;

bsHorizontal;

bsVertical;

bsFDiagonal;

bsBDiagonal;

bsCross;

bsDiagCross.

MUDANDO A COR DO PINCEL

A cor do pincel determina qual a cor usada pelo Canvas para preencher figuras. Por exemplo,

Canvas.Brush.Color := rgb(300, 0, 0);

5.5. CARREGANDO E SALVANDO FIGURAS

Para carregar uma figura a partir de um arquivo em disco, use a procedure LoadBitMap. Para salvar

uma figura em disco, use a procedure SaveBitMap. Por exemplo, para carregar o bitmap ‘BANDEIRA.BMP’, armazenado em C:\DELPHI_CURSO, para dentro do controle Image1 ( uma caixa de imagem), fazemos:

procedure TForm1.LoadBitmapClick(Sender: TObject);

begin

. Image1.Picture.LoadFromFile(‘C:\DELPHI_CURSO\BANDEIRA.BMP’);

end;

Page 13: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 68

Anotações:

Note que a figura é carregada para a propriedade Picture de Image1.

5.6. COPIANDO BITMAPS

O Delphi oferece quatro diferentes maneiras de copiar imagens de um canvas para outro, depen-

dendo do efeito que se deseja obter. A tabela a seguir mostra estes quatro métodos.

Efeito desejado Método

Copiar uma figura inteira Draw Copiar e redimensionar uma figura StretchDraw Copiar parte de um canvas CopyRect Copiar um bitmap com opções de rasterização BrushCopy

Page 14: Delphi Canvas

DELPHI 4.0 – Capítulo 5: Gráficos 69

Anotações:

COFFEE-BREAK: O LADO CÔMICO DA INFORMÁTICA

Documento secreto: Como a Microsoft realmente produz software.

1. Os programadores produzem códigos que julgam estar livres de bugs;

2. O produto é testado: 20 bugs são encontrados;

3. Os programadores corrigem 10 dos 20 bugs e explicam que os outros 10 não são

realmente bugs;

4. O departamento de testes descobre que 5 das correções não funcionam e des-

cobrem 15 novos bugs.

5. Volta para 3.

6. Volta para 4.

7. Volta para 5.

8. Volta para 6.

9. Volta para 7.

10. Volta para 8.

11. Devido a enormes pressões de marketing e à uma data de lançamento baseada e,

projeções muito otimistas, o programa é lançado; os usuários encontram 137 no-

vos bugs;

12. Os programadores originais não são mais encontrados em lugar algum;

13. Uma nova equipe de programadores corrige quase todos os 137 bugs, mas intro-

duz outros 456;

14. Os programadores originais mandam postais das Ilhas Fiji;

15. Um novo diretor de desenvolvimento assume e contrata novos programadores

para refazer o produto a partir do início;

16. Os programadores produzem códigos que julgam estar livres de bugs;

17. Volta para 2 .