Explorar E-books
Categorias
Explorar Audiolivros
Categorias
Explorar Revistas
Categorias
Explorar Documentos
Categorias
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.
Anotaes:
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:
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:
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:
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:
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
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:
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;
Anotaes:
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:
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.
Anotaes:
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;
. . .
Anotaes:
Anotaes:
Anotaes:
Anotaes:
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: