Sign in Join
Wiki copytemporary

Developing with Graphics/pt: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Visão Geral
22
33Esta página é o início de uma série de tutoriais a respeito da manipulação de Bitmaps e outros graficos. Como não sou um programador gráfico, eu convido a todos para contribuir. Basta apenas adicionar um link na próxima seção, adicionar uma página e criar seu próprio artigo Wiki.
44
55Nesta página algumas informações gerais serão fornecidas.
66
77## Outros Tutoriais Gráficos
88
99- [[GLScene]] - Uma porta para a biblioteca de gráficos visuais OpenGL [GLScene](http://www.glscene.org)
1010- [[TAChart/pt]] - Componente gráfico para Lazarus
1111- [[PascalMagick]] - Uma forma fácil de usar a API com interface para [ImageMagick](http://www.imagemagick.org), um pacote livre multi-plataforma para criar, editar e organizar imagens bitmaps.
1212- [[PlotPanel]] - Um componente para traçar e realizar gráficos animados.
1313
1414## Trabalhando com TBitmap
1515
1616A primeira idéia a ser lembrada é que Lazarus foi desenvolvido para ser multiplataforma, assim o uso de métodos da API do windows estão fora de questão. Deste modo o método ScanLine não é suportado pelo Lazarus pois ele é planejado para Dispositivo de Bitmap Independente (DIB) e utiliza uma função da \[biblioteca\] GDI32.dll
1717
1818### Um exemplo de desvanescimento (fading)
1919
20-Digamos que você deseja fazer uma figura desaparecer lentamente. No Delphi você pode fazer algo como: <code>
20+Digamos que você deseja fazer uma figura desaparecer lentamente. No Delphi você pode fazer algo como:
2121
2222`type`\
2323`  PRGBTripleArray = ^TRGBTripleArray;`\
2424`  TRGBTripleArray = array[0..32767] of TRGBTriple;`\
25-\
25+
2626`procedure TForm1.FadeIn(aBitMap: TBitMap);`\
2727`var`\
2828`  Bitmap, BaseBitmap: TBitmap;`\
2929`  Row, BaseRow: PRGBTripleArray;`\
3030`  x, y, step: integer;`\
3131`begin`\
3232`  Bitmap := TBitmap.Create;`\
3333`  try`\
3434`    Bitmap.PixelFormat := pf32bit;  //  ou pf24bit`\
3535`    Bitmap.Assign(aBitMap);`\
3636`    BaseBitmap := TBitmap.Create;`\
3737`    try`\
3838`      BaseBitmap.PixelFormat := pf32bit;`\
3939`      BaseBitmap.Assign(Bitmap);`\
4040`      for step := 0 to 32 do begin`\
4141`        for y := 0 to (Bitmap.Height - 1) do begin`\
4242`          BaseRow := BaseBitmap.Scanline[y];`\
4343`          Row := Bitmap.Scanline[y];`\
4444`          for x := 0 to (Bitmap.Width - 1) do begin`\
4545`            Row[x].rgbtRed := (step * BaseRow[x].rgbtRed) shr 5;`\
4646`            Row[x].rgbtGreen := (step * BaseRow[x].rgbtGreen) shr 5; // Fading`\
4747`            Row[x].rgbtBlue := (step * BaseRow[x].rgbtBlue) shr 5;`\
4848`          end;`\
4949`        end;`\
5050`        Form1.Canvas.Draw(0, 0, Bitmap);`\
5151`        InvalidateRect(Form1.Handle, nil, False);`\
5252`        RedrawWindow(Form1.Handle, nil, 0, RDW_UPDATENOW);`\
5353`      end;`\
5454`    finally`\
5555`      BaseBitmap.Free;`\
5656`    end;`\
5757`  finally`\
5858`    Bitmap.Free;`\
5959`  end;`\
6060`end;`
6161
62-</code> Esta função no Lazarus pode ser implementada como: <code>
62+Esta função no Lazarus pode ser implementada como:
6363
6464`procedure TForm1.FadeIn(ABitMap: TBitMap);`\
6565`var`\
6666`  SrcIntfImg, TempIntfImg: TLazIntfImage;`\
6767`  ImgHandle,ImgMaskHandle: HBitmap;`\
6868`  FadeStep: Integer;`\
6969`  px, py: Integer;`\
7070`  CurColor: TFPColor;`\
7171`  TempBitmap: TBitmap;`\
7272`begin`\
7373`  SrcIntfImg:=TLazIntfImage.Create(0,0);`\
7474`  SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);`\
7575`  TempIntfImg:=TLazIntfImage.Create(0,0);`\
7676`  TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);`\
7777`  TempBitmap:=TBitmap.Create;`\
7878`  for FadeStep:=1 to 32 do begin`\
7979`    for py:=0 to SrcIntfImg.Height-1 do begin`\
8080`      for px:=0 to SrcIntfImg.Width-1 do begin`\
8181`        CurColor:=SrcIntfImg.Colors[px,py];`\
8282`        CurColor.Red:=(CurColor.Red*FadeStep) shr 5;`\
8383`        CurColor.Green:=(CurColor.Green*FadeStep) shr 5;`\
8484`        CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5;`\
8585`        TempIntfImg.Colors[px,py]:=CurColor;`\
8686`      end;`\
8787`    end;`\
8888`    TempIntfImg.CreateBitmap(ImgHandle,ImgMaskHandle,false);`\
8989`    TempBitmap.Handle:=ImgHandle;`\
9090`    TempBitmap.MaskHandle:=ImgMaskHandle;`\
9191`    Canvas.Draw(0,0,TempBitmap);`\
9292`  end;`\
9393`  SrcIntfImg.Free;`\
9494`  TempIntfImg.Free;`\
9595`  TempBitmap.Free;`\
9696`end;`
9797
98-</code> O código Lazarus desta página foi pego do projeto \$LazarusPath/examples/lazintfimage/fadein1.lpi. Deste modo se você quiser começar bem com programação gráfica veja este exemplo.
98+O código Lazarus desta página foi pego do projeto \$LazarusPath/examples/lazintfimage/fadein1.lpi. Deste modo se você quiser começar bem com programação gráfica veja este exemplo.
9999
100100### Desenhando bitmaps com cor transparente
101101
102102Uma nova habilidade, implementada no Lazarus 0.9.11, é os bitmaps com cor transparente. Arquivos de Bitmap (*.BMP) não podem guardar informações sobre transparencia, mas podem trabalhar como se contivessem se definirmos uma cor para representar a área transparente. Este é um truque comum utilizado por aplicativos do Windows.
103103
104104O exemplo a seguir carrega um bitmap guardado dentro do executável como um recurso do Windows, seleciona uma cor para ser transparente (clFuchsia) e desenha a imagem para um Canvas.
105105
106106 procedure MyForm.MyButtonOnClick(Sender: TObject);
107107 var
108108 buffer: THandle;
109109 bmp: TBitmap;
110110 memstream: TMemoryStream;
111111 begin
112112 bmp := TBitmap.Create;
113113
114114 buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID));
115115
116116 if (buffer = 0) then exit; // Error loading the bitmap
117117
118118 bmp.Handle := buffer;
119119 memstream := TMemoryStream.create;
120120 try
121121 bmp.SaveToStream(memstream);
122122 memstream.position := 0;
123123 bmp.LoadFromStream(memstream);
124124 finally
125125 memstream.free;
126126 end;
127127
128128 bmp.Transparent := True;
129129 bmp.TransparentColor := clFuchsia;
130130
131131 MyCanvas.Draw(0, 0, bmp);
132132
133133 bmp.Free; // Release allocated resource
134134 end;
135135
136136Note as operações de memória executadas com o [[doc:rtl/classes/tmemorystream.html|TMemoryStream]]. Elas são necessárias para assegurar que a imagem seja carregada corretamente.
137137
138138## Gráficos em movimento - Como evitar a tremulação
139139
140140Muitos programas desenham gráficos 2D na interface de usuário. Caso estes gráficos precisem mudar rapida e continuamente você logo irá se deparar com um problema: A tremulação. Isto ocorre quando o usuário as vezes vê a imagem inteira e as vezes a imagem apenas parcialmente desenhada. Isto ocorre pois o processo de pintura demanda tempo.
141141
142142Mas como evitar a tremulação e obter a melhor performance de desenho? É claro que você pode trabalhar com aceleração de hardware usando o OpenGL, mas esta abordagem pode ser muito pesada para programas pequenos ou computadores antigos. Este tutorial foca no desenho utilizando o objeto TCanvas. Se você precisa de ajuda com o OpenGL observe os exemplos que vêm com o Lazarus. Você também pode usar o A.J. Venter's gamepack, que provê um canvas com buffer duplo e um componente de sprite.
143143
144144Agora nós examinaremos as opções que temos para desenhar na tela:
145145
146146- Desenhando num TImage
147147- Desenhando no evento OnPaint de uma janela, TPaintBox ou outro controle
148148- Criando um controle personalizado que se desenha
149149- Utilizando o A.J. Venter's gamepack
150150
151151### Desenhando num TImage
152152
153153Nunca use o evento OnPaint para desenhar na TImage. O TImage é armazenado temporariamente , e assim tudo que você precisa fazer é desenhar em qualquer lugar e e a mudança será para sempre. Todavia, se você está constantemente redesenhando, a imagem tremulará. Neste caso pode tentar outras opções. Desenhar com o TImage é considerado lento comparado a outras abordagens.
154154
155-<code>
156-
157155`procedure TForm1.BitBtn1Click(Sender: TObject);`\
158156`var`\
159157`  x, y: Integer;`\
160158`begin`\
161159`  // Draws the backgroung`\
162160`  Image.Canvas.Pen.Color := clWhite;`\
163161`  Image.Canvas.Rectangle(0, 0, Image.Width, Image.Height);`\
164162`  `\
165163`  // Draws squares`\
166164`  Bitmap.Canvas.Pen.Color := clBlack;`\
167165`  for x := 1 to 8 do`\
168166`   for y := 1 to 8 do`\
169167`    Image.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),`\
170168`       Round(x * Image.Width / 8), Round(y * Image.Height / 8));`\
171169`end;`
172170
173-</code>
174-
175171### Desenhando no evento OnPaint
176172
177173Neste caso todo o desenho tem que ser feito no evento OnPaint. Não permanece no armazenamento temporário, como no evento TImage.
178174
179175### Criando um controle personalizado que se desenha
180176
181177Utilizar um controle personalizado possuí a vantagem de estruturar o código e permitir o reuso do controle. Esta abordagem é muito rápida, mas pode gerar tremulação caso a imagem não seja primeiro desenhada para um TBitmap e depois passada para a tela. Neste caso não há necessidade de utilizar o evento OnPaint do controle.
182178
183179Aqui está um controle personalizado como exemplo:
184180
185-<code>
186-
187181`type`\
188182`  TMyDrawingControl = class(TCustomControl)`\
189183`  public`\
190184`    procedure Paint; override;`\
191185`  end;`\
192-\
186+
193187`implementation`\
194-\
188+
195189`procedure TMyDrawingControl.Paint;`\
196190`var`\
197191`  x, y: Integer;`\
198192`  Bitmap: TBitmap;`\
199193`begin`\
200194`  Bitmap := TBitmap.Create;`\
201195`  try`\
202196`    // Initializes the Bitmap Size`\
203197`    Bitmap.Height := Height;`\
204198`    Bitmap.Width := Width;`\
205199` `\
206200`    // Draws the background`\
207201`    Bitmap.Canvas.Pen.Color := clWhite;`\
208202`    Bitmap.Canvas.Rectangle(0, 0, Width, Height);`\
209-\
203+
210204`    // Draws squares`\
211205`    Bitmap.Canvas.Pen.Color := clBlack;`\
212206`    for x := 1 to 8 do`\
213207`     for y := 1 to 8 do`\
214208`      Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),`\
215209`       Round(x * Width / 8), Round(y * Height / 8));`\
216210`      `\
217211`    Canvas.Draw(0, 0, Bitmap);`\
218212`  finally`\
219213`    Bitmap.Free;`\
220214`  end;`\
221-\
215+
222216`  inherited Paint;`\
223217`end;`
224218
225-</code> e como o criamos numa janela: <code>
219+e como o criamos numa janela:
226220
227221`procedure TMyForm.FormCreate(Sender: TObject);`\
228222`begin`\
229223`  MyDrawingControl:= TMyDrawingControl.Create(Self);`\
230224`  MyDrawingControl.Height := 400;`\
231225`  MyDrawingControl.Width := 500;`\
232226`  MyDrawingControl.Top := 0;`\
233227`  MyDrawingControl.Left := 0;`\
234228`  MyDrawingControl.Parent := Self;`\
235229`  MyDrawingControl.DoubleBuffered := True;`\
236230`end;`
237231
238-</code> apenas não esqueça de destrui-lo: <code>
232+apenas não esqueça de destrui-lo:
239233
240234`procedure TMyForm.FormDestroy(Sender: TObject);`\
241235`begin`\
242236`  MyDrawingControl.Free;`\
243237`end;`
244-
245-</code>
246238
247239Atribuir zero às propriedades Top e Left não é necessário, logo que essa é a posição padrão, mas isso é feito para reforçar onde o controle será posto.
248240
249241"MyDrawingControl.Parent := Self;" é muito importante e você não verá seu controle se não o fizer.
250242
251243"MyDrawingControl.DoubleBuffered := True;" é necessário para evitar flutuação/tremulação no Windows. Mas isto não faz efeito com GTK.
252244
253245### Utilizando o A.J. Venter's gamepack
254246
255247The gamepack approach is to draw everything to one double-buffered canvas, which only gets updated to the visible canvas when you are ready. This takes quite a bit of code, but it has the advantage of being able to do large rapidly changing scenes with multiple sprites on them. If you wish to use this approach, you may be interested in A.J. Venter's gamepack, a set of components for game development in Lazarus, which provides a double-buffered display area component as well as a sprite component, designed to integrate well with one another. You can get gamepack via subversion:\
256248`svn co `[`svn://silentcoder.co.za/lazarus/gamepack`](svn://silentcoder.co.za/lazarus/gamepack)
257249
258250---
259251*From the Free Pascal wiki, page "Developing with Graphics/pt", as it stood on 2010-09-15 after a change by Sfalcao, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history