Sign in Join
Wiki copytemporary

BGRABitmap tutorial 3: what changed

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

Title: BGRABitmap tutorial 3

OldNewLine
1+This tutorial shows you how to draw on a bitmap with the mouse.
2+
3+### Create a new project
4+
5+Create a new project and add a reference to [[BGRABitmap]], the same way as in [[BGRABitmap tutorial|the first tutorial]].
6+
7+### Create a new image
8+
9+Add a private variable to the main form to store the image:
10+
11+``` pascal
12+TForm1 = class(TForm)
13+ private
14+ { private declarations }
15+ image: TBGRABitmap;
16+ public
17+ { public declarations }
18+ end;
19+```
20+
21+Create the image when the form is created. To do this, double-click on the form, a procedure should appear in the code editor. Add the create instruction:
22+
23+``` pascal
24+procedure TForm1.FormCreate(Sender: TObject);
25+begin
26+ image := TBGRABitmap.Create(640,480,BGRAWhite); //create a 640x480 image
27+end;
28+```
29+
30+### Draw the bitmap
31+
32+Add an OnPaint handler. To do this, select the main form, then go to the object inspector, in the event tab, and double-click on the OnPaint line. Then, add the drawing code:
33+
34+``` pascal
35+procedure TForm1.FormPaint(Sender: TObject);
36+begin
37+ PaintImage;
38+end;
39+```
40+
41+Add the PaintImage procedure:
42+
43+``` pascal
44+procedure TForm1.PaintImage;
45+begin
46+ image.Draw(Canvas,0,0,True);
47+end;
48+```
49+
50+After writing this, put the cursor on PaintImage and press Ctrl-Shift-C to add the declaration to the interface.
51+
52+### Handle mouse
53+
54+With the object inspector, add handlers for MouseDown and MouseMove events:
55+
56+``` pascal
57+procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
58+ Shift: TShiftState; X, Y: Integer);
59+begin
60+ if Button = mbLeft then DrawBrush(X,Y);
61+end;
62+
63+procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
64+ Y: Integer);
65+begin
66+ if ssLeft in Shift then DrawBrush(X,Y);
67+end;
68+```
69+
70+Add the DrawBrush procedure:
71+
72+``` pascal
73+procedure TForm1.DrawBrush(X, Y: Integer);
74+const radius = 5;
75+begin
76+ image.GradientFill(X-radius,Y-radius, X+radius,Y+radius,
77+ BGRABlack,BGRAPixelTransparent, gtRadial,
78+ PointF(X,Y), PointF(X+radius,Y), dmDrawWithTransparency);
79+
80+ PaintImage;
81+end;
82+```
83+
84+After writing this, put the cursor on DrawBrush and press Ctrl-Shift-C to add the declaration to the interface.
85+
86+This procedure draws as radial gradient (gtRadial):
87+
88+- the bounding rectangle is (X-radius,Y-radius, X+radius,Y+radius).
89+- the center is black, the border is transparent
90+- the center is at (X,Y) and the border at (X+radius,Y)
91+
92+### Code
93+
94+``` pascal
95+unit UMain;
96+
97+{$mode objfpc}{$H+}
98+
99+interface
100+
101+uses
102+ Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
103+ BGRABitmap, BGRABitmapTypes;
104+
105+type
106+ { TForm1 }
107+
108+ TForm1 = class(TForm)
109+ procedure FormCreate(Sender: TObject);
110+ procedure FormDestroy(Sender: TObject);
111+ procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
112+ Shift: TShiftState; X, Y: Integer);
113+ procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
114+ procedure FormPaint(Sender: TObject);
115+ private
116+ { private declarations }
117+ image: TBGRABitmap;
118+ procedure DrawBrush(X, Y: Integer);
119+ procedure PaintImage;
120+ public
121+ { public declarations }
122+ end;
123+
124+var
125+ Form1: TForm1;
126+
127+implementation
128+
129+{ TForm1 }
130+
131+procedure TForm1.FormCreate(Sender: TObject);
132+begin
133+ image := TBGRABitmap.Create(640,480,BGRAWhite);
134+end;
135+
136+procedure TForm1.FormDestroy(Sender: TObject);
137+begin
138+ image.Free;
139+end;
140+
141+procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
142+ Shift: TShiftState; X, Y: Integer);
143+begin
144+ if Button = mbLeft then DrawBrush(X,Y);
145+end;
146+
147+procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
148+ Y: Integer);
149+begin
150+ if ssLeft in Shift then DrawBrush(X,Y);
151+end;
152+
153+procedure TForm1.FormPaint(Sender: TObject);
154+begin
155+ PaintImage;
156+end;
157+
158+procedure TForm1.DrawBrush(X, Y: Integer);
159+const radius = 20;
160+begin
161+ image.GradientFill(X-radius,Y-radius, X+radius,Y+radius,
162+ BGRABlack,BGRAPixelTransparent,gtRadial,
163+ PointF(X,Y), PointF(X+radius,Y), dmDrawWithTransparency);
164+
165+ PaintImage;
166+end;
167+
168+procedure TForm1.PaintImage;
169+begin
170+ image.Draw(Canvas,0,0,True);
171+end;
172+
173+initialization
174+ {$I UMain.lrs}
175+
176+end.
177+```
178+
179+### Run the program
180+
181+You should be able to draw on the form.
182+
183+<figure>
184+<img src="BGRATutorial3.png" title="BGRATutorial3.png" />
185+<figcaption>BGRATutorial3.png</figcaption>
186+</figure>
187+
188+### Continuous drawing
189+
190+To have a continuous drawing, we need additionnal variables:
191+
192+``` pascal
193+
194+TForm1 = class(TForm)
195+ ...
196+ private
197+ { private declarations }
198+ image: TBGRABitmap;
199+ mouseDrawing: boolean;
200+ mouseOrigin: TPoint;
201+```
202+
203+mouseDrawing will be True during the drawing (with left button pressed) and mouseOrigin will be the starting point of the segment being drawn.
204+
205+The clicking handler becomes a little bit more complicated:
206+
207+``` pascal
208+procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
209+ Shift: TShiftState; X, Y: Integer);
210+begin
211+ if Button = mbLeft then
212+ begin
213+ mouseDrawing := True;
214+ mouseOrigin := Point(X,Y);
215+ DrawBrush(X,Y,True); // or DrawBrush(X,Y);
216+ end;
217+end;
218+```
219+
220+It initialises the drawing with the current position. Then, it draws as closed segment (note the new parameter for DrawBrush). Indeed, at the beginning, the segment is closed and has a length of zero, which gives a disk:
221+
222+<figure>
223+<img src="BGRATutorial3b.png" title="BGRATutorial3b.png" />
224+<figcaption>BGRATutorial3b.png</figcaption>
225+</figure>
226+
227+Little by little, we add a new part, which is an opened segment:
228+
229+<figure>
230+<img src="BGRATutorial3c.png" title="BGRATutorial3c.png" />
231+<figcaption>BGRATutorial3c.png</figcaption>
232+</figure>
233+
234+That's why we need a new parameter for the DrawBrush function, which becomes:
235+
236+``` pascal
237+procedure TForm1.DrawBrush(X, Y: Integer; Closed: Boolean);
238+const brushRadius = 20;
239+begin
240+ image.DrawLineAntialias(X,Y,mouseOrigin.X,mouseOrigin.Y,BGRA(0,0,0,128),brushRadius,Closed);
241+ mouseOrigin := Point(X,Y);
242+
243+ PaintImage;
244+end;
245+```
246+
247+We transmit the parameter Closed to DrawLineAntialias, to indicate whether the segment is closed or not. Note coordinates order. The start position and the end position are swapped. Indeed, for DrawLineAntialias, it's the end that is opened, whereas in this case, we want that the beginning be opened.
248+
249+DrawBrush definition must be updated in the interface.
250+
251+The MouseMove handler becomes:
252+
253+``` pascal
254+procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
255+ Y: Integer);
256+begin
257+ if mouseDrawing then DrawBrush(X,Y,False);
258+end;
259+```
260+
261+Finally, we need to add a MouseUp handler to update mouseDrawing:
262+
263+``` pascal
264+procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
265+ Shift: TShiftState; X, Y: Integer);
266+begin
267+ if Button = mbLeft then
268+ mouseDrawing := False;
269+end;
270+```
271+
272+### Code
273+
274+``` pascal
275+unit UMain;
276+
277+{$mode objfpc}{$H+}
278+
279+interface
280+
281+uses
282+ Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
283+ BGRABitmap, BGRABitmapTypes;
284+
285+type
286+ { TForm1 }
287+
288+ TForm1 = class(TForm)
289+ procedure FormCreate(Sender: TObject);
290+ procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
291+ Shift: TShiftState; X, Y: Integer);
292+ procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
293+ procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
294+ Shift: TShiftState; X, Y: Integer);
295+ procedure FormPaint(Sender: TObject);
296+ private
297+ { private declarations }
298+ image: TBGRABitmap;
299+ mouseDrawing: boolean;
300+ mouseOrigin: TPoint;
301+ procedure DrawBrush(X, Y: Integer; Closed: boolean);
302+ procedure PaintImage;
303+ public
304+ { public declarations }
305+ end;
306+
307+var
308+ Form1: TForm1;
309+
310+implementation
311+
312+{ TForm1 }
313+
314+procedure TForm1.FormCreate(Sender: TObject);
315+begin
316+ image := TBGRABitmap.Create(640,480,BGRAWhite);
317+end;
318+
319+procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
320+ Shift: TShiftState; X, Y: Integer);
321+begin
322+ if Button = mbLeft then
323+ begin
324+ mouseDrawing := True;
325+ mouseOrigin := Point(X,Y);
326+ DrawBrush(X,Y,True);
327+ end;
328+end;
329+
330+procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
331+ Y: Integer);
332+begin
333+ if mouseDrawing then DrawBrush(X,Y,False);
334+end;
335+
336+procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
337+ Shift: TShiftState; X, Y: Integer);
338+begin
339+ if Button = mbLeft then
340+ mouseDrawing := False;
341+end;
342+
343+procedure TForm1.FormPaint(Sender: TObject);
344+begin
345+ PaintImage;
346+end;
347+
348+procedure TForm1.DrawBrush(X, Y: Integer; Closed: Boolean);
349+const brushRadius = 20;
350+begin
351+ image.DrawLineAntialias(X,Y,mouseOrigin.X,mouseOrigin.Y,BGRA(0,0,0,128),brushRadius,Closed);
352+ mouseOrigin := Point(X,Y);
353+
354+ PaintImage;
355+end;
356+
357+procedure TForm1.PaintImage;
358+begin
359+ image.Draw(Canvas,0,0,True);
360+end;
361+
362+initialization
363+ {$I UMain.lrs}
364+
365+end.
366+```
367+
368+### Run the program
369+
370+Now the drawing is almost continous:
371+
372+<figure>
373+<img src="BGRATutorial3d.png" title="BGRATutorial3d.png" />
374+<figcaption>BGRATutorial3d.png</figcaption>
375+</figure>
376+
377+[[BGRABitmap tutorial 2|Previous tutorial (image loading)]] \| [[BGRABitmap tutorial 4|Next tutorial (direct pixel access)]]
378+
379+---
380+*From the Free Pascal wiki, page "BGRABitmap tutorial 3", as it stood on 2023-02-13 after a change by Wp, 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).*
381+Category: BGRABitmap
382+Category: Graphics

Back to history