Introdução a Classe TCanvas no Delphi

Tempo de leitura: 6 minutos

Hoje vamos falar da mística classe TCanvas no Delphi. Basicamente podemos descrevê-la como um “wrapper” (encapsulamento) para as funções de desenho do Windows (GDI). Na prática ela serve para desenhar formas básicas, componentes, imagens, transparências, gradientes, etc. Agora os reclamões já devem estar resmungando: “Porra bruto, você vai ensinar a gente a desenhar quadradinhos e bolinhas na tela? Isso a gente encontra em 4 de cada 5 blogs de Delphi! ”

Vou, vou ensinar a desenhar bolinhas e quadradinhos na tela sim e antes que se pergunte para que você usará isso na vida real, vou te dizer que você pode usar TCanvas em muito mais lugares do que a fórmula de Báskara. Você pode usá-la para criar, sem usar componentes de terceiros, DBGrids muito mais ricos, personalizar StringGrids e DrawGrids, criar maravilhas com DBControlGrids e algumas coisinhas a mais que vou explicando ao longo dos posts. Mas vamos parar de enrolação.

Antes de começar a meter a mão na massa, infelizmente, vamos ter que enfrentar um pouco de teoria. Se você programa com Delphi a um tempinho já notou que o sistema de posicionamento de componentes conta da esquerda para a direita e de cima para baixo. Isso quer dizer que (0,0) é o ponto mais à esquerda e ao topo. É muito bom decorar isso agora ou você vai acabar desenhando as coisas ao contrário.

Para começar, abra um programa novo, procure nos componentes um PaintBox e deixe-o com no mínimo 200px por 200px. Eu confesso que deve ser meio difícil de achar porque eu mesmo nunca o usei em 12 anos de programação e acho que foi criado só para ensino do TCanvas no Delphi. Coloque um botão também e no click dele coloque a seguinte linha:

PaintBox1.Canvas.Rectangle(10,20,20,30);

Receba conteúdos como este

Não perca nenhum conteúdo aqui do blog, faça como milhares de assinantes, receba gratuitamente nossas atualizações!


Após executar o programa e clicar no botão você pode notar que apareceu um quadrado monótono, de bordas pretas, interior cinza (ou da cor do seu form), com 10 pixels de lado, a 10 pixels de distância da margem esquerda e a 20 pixels da margem superior. Vou te explicar o porquê se você ainda não adivinhou. Os dois primeiros parâmetros nos dizem a quantos pixels da margem esquerda e da margem superior, respectivamente, o desenho vai começar. Já os terceiro e quarto parâmetros nos dizem a quantos pixels de distância da margem esquerda e superior, respectivamente, o desenho vai terminar. Presta bem atenção nisso cabeção: TERMINAR. Não é o tamanho do desenho nem a distância do ponto inicial do desenho, é a distância do (0, 0), por isso que nosso desenho é quadrado mesmo o quarto parâmetro sendo maior que o terceiro, pois o desenho começou mais para baixo. Agora adicione a seguinte linha no botão:

PaintBox1.Canvas.Ellipse(75,50,100,100);

Ao executar teremos uma elipse ligeiramente ovalada. Isso é porque começamos com ela mais abaixo do que à esquerda e terminaram a mesma distância das origens. Cinza e preto não são minhas cores favoritas então vamos dar um jeito de trocá-las. Canvas.Pen é o objeto que trata das linhas de contorno como espessura, cor, tipo de tracejado Já Canvas.Brush é o objeto que trata da face do desenho, isto é, cor e estilo de preenchimento. No momento só estamos interessados nas cores, então vamos fazer o seguinte:

PaintBox1.Canvas.Pen.Color := clRed;
PaintBox1.Canvas.Brush.Color := ClYellow;
PaintBox1.Canvas.Rectangle(10,20,20,30);

TCanvas no Delphi

Agora temos um quadrado vermelho de bordas amarelas, discreto pra caralho, né? Você pode não acreditar, mas conhecendo esses 4 “comandos” já podemos fazer bastante coisas legais. Para exemplificar, vamos desenhar um tabuleiro de damas, com as peças nas posições de início do jogo. No clique do botão inclua o código abaixo:

var
  TamanhoVerticalPeca,TamanhoHorizonalPeca,
  Linha,Coluna,InicioVertical,InicioHorizontal,
  InicioCasaHorizontal,InicioCasaVertical,
  FimCasaHorizontal,FimCasaVertical,
  InicioPecaHorizontal,InicioPecaVertical,
  FimPecaHorizontal,FimPecaVertical, Pecas: Integer;
  EBranca: Boolean;
begin
  TamanhoVerticalPeca := Trunc(PaintBox1.Height/8);
  TamanhoHorizonalPeca := Trunc(PaintBox1.Width/8);
  EBranca := True; //começamos com a peça branca
  PaintBox1.Canvas.Pen.Color := clGray; //as linhas entra as casas serão cinzas escuras
  
  for Linha := 0 to 7 do //linhas verticais
  begin
    for Coluna := 0 to 7 do //colunas horizontais
    begin
      if EBranca then 
        PaintBox1.Canvas.Brush.Color := clWhite
      else
        PaintBox1.Canvas.Brush.Color := clBlack;
      InicioCasaHorizontal := Coluna*TamanhoHorizonalPeca;
      FimCasaHorizontal := InicioCasaHorizontal + TamanhoHorizonalPeca;
      InicioCasaVertical := Linha * TamanhoVerticalPeca;
      FimCasaVertical := InicioCasaVertical + TamanhoVerticalPeca;
      PaintBox1.Canvas.Rectangle(InicioCasaHorizontal, InicioCasaVertical,FimCasaHorizontal, FimCasaVertical);
      EBranca := not EBranca;
    end;
    EBranca := not EBranca;
  end;

  //As pedras são colocadas só nas casas pretas, mas a primeira casa é branca
  InicioVertical := 0;
  InicioHorizontal := TamanhoHorizonalPeca; //então vamos começar no final da primeira casa.
  PaintBox1.Canvas.Pen.Color := clWhite;
  PaintBox1.Canvas.Brush.Color := clDkGray;
 
  for Pecas := 1 to 12 do //são 12 peças pretas
  begin
    InicioPecaHorizontal := InicioHorizontal+5;
    FimPecaHorizontal := InicioHorizontal+TamanhoHorizonalPeca-5;
    InicioPecaVertical := InicioVertical+5;
    FimPecaVertical := InicioVertical+TamanhoVerticalPeca-5;
    PaintBox1.Canvas.Ellipse(InicioPecaHorizontal,InicioPecaVertical,FimPecaHorizontal,FimPecaVertical);
    if Pecas mod 4 = 0 then //apenas 4 pedras por linhas (8 casas, 4 brancas, 4 pretas)
    begin
      InicioVertical := InicioVertical + TamanhoVerticalPeca;
      if InicioHorizontal+TamanhoHorizonalPeca >= PaintBox1.Width then //se a ultima casa dessa linha for preta, a primeira casa da próxima linha também é preta.
        InicioHorizontal := 0
      else
        InicioHorizontal := TamanhoHorizonalPeca;
    end
    else
      InicioHorizontal := InicioHorizontal + (TamanhoHorizonalPeca*2);
  end;
  
  InicioVertical := 5*TamanhoVerticalPeca; //o segundo jogador, começa a colocar suas pedras na sexta linha do tabuleiro
  InicioHorizontal := 0; //e a primeira casa da quinta coluna é preta
  PaintBox1.Canvas.Pen.Color := clWhite;
  PaintBox1.Canvas.Brush.Color := clSilver;
  for Pecas := 1 to 12 do //são 12 peças brancas
  begin
    InicioPecaHorizontal := InicioHorizontal+5;
    FimPecaHorizontal := InicioHorizontal+TamanhoHorizonalPeca-5;
    InicioPecaVertical := InicioVertical+5;
    FimPecaVertical := InicioVertical+TamanhoVerticalPeca-5;
    PaintBox1.Canvas.Ellipse(InicioPecaHorizontal,InicioPecaVertical,FimPecaHorizontal,FimPecaVertical);
    if Pecas mod 4 = 0 then //mesmo esquema: 4 casas brancas, 4 pretas, só coloco peças nas pretas
    begin
      InicioVertical := InicioVertical + TamanhoVerticalPeca;
      if InicioHorizontal+TamanhoHorizonalPeca >= PaintBox1.Width then
        InicioHorizontal := 0
      else
        InicioHorizontal := TamanhoHorizonalPeca;
      end
    else
      InicioHorizontal := InicioHorizontal + (TamanhoHorizonalPeca*2);
  end;
end;

O código está bem comentado, mas vou dar uma pinceladinha para os mais preguiçosos: dividi o tamanho do nosso PaintBox1 por 8 em largura e altura para termos o tamanho horizontal e vertical de cada peça (se você nunca jogou dama, o tabuleiro tem 8 por 8 casas). Então se você quer casas quadradas no seu tabuleiro é ótimo que o PaintBox tenha o mesmo tamanho horizontal e vertical.

Com essas informações em mãos, desenho os quadrados brancos e pretos, linha por linha, até aí tranquilo. Depois vou desenhar as peças, pulo o tamanho de uma casa, para começar na casa preta e a cada peça desenhada pulo o tamanho de duas casas para cair na próxima casa preta. Depois de 4 peças eu vou para a próxima linha.

A lógica é a mesma para as pedras brancas, exceto pelo fato que eu começo da sexta linha, e nessa linha, a primeira casa já é preta. A imagem abaixo mostra nosso tabuleiro de damas reiderizado via TCanvas no Delphi.

TCanvas no Delphi
Tabuleiro reinderizado com TCanvas

Se ainda tiver alguém com dúvidas sobre o código estude um pouco de matemática do ensino básico pois até agora só usamos 3 das 4 operações básicas, além de alguns fors e ifs. Mas se mesmo assim ainda tiver alguma dúvida, pergunte nos comentários. No próximo post vou mostrar como aplicar este conhecimento para tornar sua aplicação mais rica, embelezando e dando mais funções aos seus grids.

Vou nessa e até a próxima!

  • Paulo Do Prado Borba

    Já solucionei a minha dúvida. Me desculpem, Obrigado.

  • Paulo Do Prado Borba

    Ao rodar o código o Delphi apresentou erro na linha 72 do código, que reproduzo aqui.

    if InicioHorizontal+TamanhoHorizonalPeca >= PaintBox1.Width then InicioHorizontal := 0

    O que é esse termo &gt no código ?

    Obrigado

    Paulo do Prado Borba