Anda di halaman 1dari 14

DELPHI 4.

0 Captulo 5: Grficos
56

5. GRFICOS
5.1. O CANVAS
O canvas (tela) representa uma superfcie em um objeto onde se pode desenhar um bitmap. O canvas 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. Operaes de desenho envolvem a manipulao de pixels individuais de modo a se desenhar pontos ou linhas. Por exemplo, a cor de um pixel pode ser alterada com a seguinte instruo: Canvas.Pixels [10, 10] := clRed;

Operaes de pintura envolvem a manipulao de grandes quantidades de pixels. Geralmente, pintura inclui desenho. Para desenhar ou pintar, o usurio provavelmente pensar em usar o mouse. Antes de implemenatr mtodos de desenho, portanto, necessrio 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, trs so realmente causados por aes 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 sequncia completa que compreende clicar e liberar o boto esquerdo do mouse. O evento Click no capaz de diferenciar entre os botes do mouse ou detectar teclas pressionadas junto com o boto do mouse. Os eventos OnMouseDown, OnMouseMove e OnMouseUp repassam os seguintes parmetros: Parmetro Sender Button Shift X, Y Significado O objeto que causou o evento Indica qual o boto envolvido no evento: mbLeft, mbMiddle, or mbRight Indica o estado das teclas Alt, Ctrl e Shift keys durante o evento de mouse So as coordenadas da tela onde ocorreu o evento.

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


57

O Delphi gera automaticamente um manipulador de eventos para os eventos de Mouse, os quais tm a seguinte forma: procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end;

Por exemplo, o trecho de cdigo 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 edio de figuras. Clicando com o mouse, definimos o incio da linha a ser desenhada. Para isto, usamos o mtodo MoveTo para definir uma nova posio grfica (a posio do ltimo evento grfico 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 posio da caneta (pen position). Para desenhar a linha, devemos capturar o evento OnMouseUp e definir as coordenadas da tela onde o usurio liberou o mouse. Um evento OnMouseUp ocorre sempre que o usurio libera o boto do mouse sobre um objeto. Este evento, por si mesmo, no detecta o movimento do mouse. Podemos usar o mtodo LineTo para desenhar uma linha reta que ir da posio 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;

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


58

Por enquanto, o usurio no pode ver a linha que est FlagDesenho. Para que isto seja possvel, devemos capturar o evento OnMouseMove e us-lo para desenhar uma inha elstica. O evento OnMouseMove ocorre periodicamente, quando o usurio move o mouse sobre um objeto.O exemplo 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 intermedirios aparecem e no so 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 usurio no pressionar qualquer boto. Se voc quizer detectar se um boto, por exemplo, o boto direito, foi pressionado, ser necessrio adicionar um campo (field) ao formulrio. Quando voc adiciona um componente a um formulrio, o Delphi tambm adiciona um campo que representa o componente para o formulrio. Voc pode se referir ao componente pelo nome do campo. Voc tambm pode inserir campos, editando a declarao de tipos (type) na parte de cima da unidade do formulrio. Para detectar se o boto do mouse foi pressionado, basta adicionar um campo do tipo Boolean. O seguinte trecho de cdigo 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 boto foi . pressionado} Origem, MovePt: TPoint; { campo para armazenar pontos} end;

A seguir, o campo FlagDesenho ser feito igual a True no incio do evento OnMouseDown, e igual a false no evento OnMouseUp.

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


59

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 boto 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 mo livre. 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 desenhar 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;

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


60 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 comeando da Origem at as coordenadas atuais. A linha final fixada no evento OnMouseUp. Contudo, as linhas intermedirias ainda no sio apagadas. Isto pode ser corrigido apagando-se cada linha antes que a prxima seja desenhada. Um novo campo, denominado MovePonto, ser usado para memorizar a linha anterior. Alm disso, para apagar uma linha, mais fcil 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

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


61 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 . prximo movimento} Canvas.Pen.Mode := pmCopy; {retorna ao modo Copy (default)] end;

O resultado deve ser uma linha reta elstica, que pode ser esticada pela tela com o evento OnMouseMove e fixa com o evento OnMouseUp. Note que o campo MovePonto, do tipo Tpoint, deve ser definido na seo Type, juntamente com Origem e FlagDesenho

5.3. DESENHANDO FIGURAS


O prximo passo do nosso programa grfico ser capza de desenhar figuras como retngulos e elipses. Para tanto, precisamos definir qual ferramenta de desenho ser usada e a maneira mais fcil de fazer isto, em Pascal, usar um tipo enumerado, que pode ser declarado da seguinte forma:

type TFerramenta = (frLinha, frRetngulo, frElipse, frRetRedondo);

Por conveno, identificadores de tipocomeam com a letra T. e grupos de constantes comeam com o mesmo prefixo de duas letras. A declarao do tipo Tferramenta similar a declarar constantes separadas: const frLinha = 0; frRetngulo = 1; frElipse = 2; frRetRedondo = 3;

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


62

Entretanto, a declarao de um tipo enumerado apresenta certas vantagens, pois no ser possvel atribuir varivel um valor no definido. Caso isso acontea, um erro de compilao gerado. O prximo passo declarar um campo Ferramenta como pertencente ao tipo Tferramenta. type TFerramenta = (frLinha, frRetngulo, 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 significa que o valor inicial de Ferramenta ser frLinha. Voc pode, agora, posicionar quatro botes do tipo SpeedButtons no formulrio e us-los para definir a ferramenta de desenho a ser usada. Por exemplo, se o nome deste botes forem spbLinha, spbRetngulo, spbElipse e spbRetRedondo, os manipuladores de eventos sero, respectivemente: procedure TForm1.spbLinhaClick(Sender: TObject); begin Ferramenta := frLinha; end;

procedure TForm1.spbRetnguloClick(Sender: TObject); begin Ferramenta := frRetngulo; end;

procedure TForm1.spbElipseClick(Sender: TObject); begin Ferramenta := frElipse; end;

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


63

procedure TForm1.sobRetRedondoClick(Sender: TObject); begin Ferramenta := frRetRedondo; end;

A escolha de quais procedimentos sero executados quando o usurio pressionar cada um dos botes poderia ser feita com instrues If ..Then. Entretanto, o Object Pascal fornece o comando Case, que muito mais eficiente neste caso. Alm disso, para desenhar figuras basta executar o mtodo apropriado: procedure TForm1.FormMouseUp(Sender: TObject); begin case Ferramenta of frLinha: begin Canvas.MoveTo(Origem.X, Origem.Y); Canvas.LineTo(X, Y) end; frRetngulo: 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; frRetngulo : begin

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


64 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, (Origem.X - X) div 2, (Origem.Y - Y) Canvas.RoundRect(Origem.X, Origem.Y, (Origem.X - X) div 2, (Origem.Y - Y) end; end; MovePonto := Point(X, Y); end; Canvas.Pen.Mode := pmCopy; end;

X, Y, div 2); X, Y, div 2);

Voc deve ter notado que h muita repetio de cdigo nestas duas procedures. Quando isto acontece, melhor escrever uma sub-rotina separada que ser acessada por partes diferentes do programa, evitando repetio desnecessria.

Como adicionar uma sub-rotina (mtodo) a um formulrio:


1. Adicione a declarao do mtodo ao objeto formulrio. Isto pode ser feito dentro das sees public ou private da unidade associada ao formulrio: 2. Escreva a implementao do mtodo na seo implementation. No nosso caso, o cdigo fica da seguinte forma: . . type TForm1 = class(TForm) . . .public { Public declarations } procedure DesenhaForma(SupEsq, InfDir: TPoint; AModo: TPenMode); end;

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


65

Note que DesenhaForma recebe trs parmetros, correspondendo s coordenadas do canto superior esquerdo, s coordenadas do canto inferior direito e ao modo de desenho. A implementao no 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; frRetngulo: 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

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


66 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);

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


67

MUDANDO A ESPESSURA DA CANETA


A espessura (width) da caneta um nmero 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 padro 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;

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


68

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, dependendo do efeito que se deseja obter. A tabela a seguir mostra estes quatro mtodos. Efeito desejado Copiar uma figura inteira Copiar e redimensionar uma figura Copiar parte de um canvas Copiar um bitmap com opes de rasterizao Mtodo Draw StretchDraw CopyRect BrushCopy

Anotaes:

DELPHI 4.0 Captulo 5: Grficos


69

COFFEE-BREAK: O LADO CMICO DA INFORMTICA Documento secreto: Como a Microsoft realmente produz software.
1. Os programadores produzem cdigos que julgam estar livres de bugs; 2. O produto testado: 20 bugs so encontrados; 3. Os programadores corrigem 10 dos 20 bugs e explicam que os outros 10 no so realmente bugs; 4. O departamento de testes descobre que 5 das correes no funcionam e descobrem 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 presses de marketing e uma data de lanamento baseada e, projees muito otimistas, o programa lanado; os usurios encontram 137 novos bugs; 12. Os programadores originais no so mais encontrados em lugar algum; 13. Uma nova equipe de programadores corrige quase todos os 137 bugs, mas introduz 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 incio; 16. Os programadores produzem cdigos que julgam estar livres de bugs; 17. Volta para 2 .

Anotaes:

Anda mungkin juga menyukai