Sign in Join
Wiki copytemporary

BGRABitmap tutorial 3: what changed

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

OldNewLine
11This tutorial shows you how to draw on a bitmap with the mouse.
22
33### Create a new project
44
55Create a new project and add a reference to [[BGRABitmap]], the same way as in [[BGRABitmap tutorial|the first tutorial]].
66
77### Create a new image
88
99Add a private variable to the main form to store the image:
1010
1111``` pascal
1212TForm1 = class(TForm)
1313 private
1414 { private declarations }
1515 image: TBGRABitmap;
1616 public
1717 { public declarations }
1818 end;
1919```
2020
2121Create 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:
2222
2323``` pascal
2424procedure TForm1.FormCreate(Sender: TObject);
2525begin
2626 image := TBGRABitmap.Create(640,480,BGRAWhite); //create a 640x480 image
2727end;
2828```
2929
3030### Draw the bitmap
3131
3232Add 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:
3333
3434``` pascal
3535procedure TForm1.FormPaint(Sender: TObject);
3636begin
3737 PaintImage;
3838end;
3939```
4040
4141Add the PaintImage procedure:
4242
4343``` pascal
4444procedure TForm1.PaintImage;
4545begin
4646 image.Draw(Canvas,0,0,True);
4747end;
4848```
4949
5050After writing this, put the cursor on PaintImage and press Ctrl-Shift-C to add the declaration to the interface.
5151
5252### Handle mouse
5353
5454With the object inspector, add handlers for MouseDown and MouseMove events:
5555
5656``` pascal
5757procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
5858 Shift: TShiftState; X, Y: Integer);
5959begin
6060 if Button = mbLeft then DrawBrush(X,Y);
6161end;
6262
6363procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
6464 Y: Integer);
6565begin
6666 if ssLeft in Shift then DrawBrush(X,Y);
6767end;
6868```
6969
7070Add the DrawBrush procedure:
7171
7272``` pascal
7373procedure TForm1.DrawBrush(X, Y: Integer);
7474const radius = 5;
7575begin
7676 image.GradientFill(X-radius,Y-radius, X+radius,Y+radius,
7777 BGRABlack,BGRAPixelTransparent, gtRadial,
7878 PointF(X,Y), PointF(X+radius,Y), dmDrawWithTransparency);
7979
8080 PaintImage;
8181end;
8282```
8383
8484After writing this, put the cursor on DrawBrush and press Ctrl-Shift-C to add the declaration to the interface.
8585
8686This procedure draws as radial gradient (gtRadial):
8787
8888- the bounding rectangle is (X-radius,Y-radius, X+radius,Y+radius).
8989- the center is black, the border is transparent
9090- the center is at (X,Y) and the border at (X+radius,Y)
9191
9292### Code
9393
9494``` pascal
9595unit UMain;
9696
9797{$mode objfpc}{$H+}
9898
9999interface
100100
101101uses
102102 Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
103103 BGRABitmap, BGRABitmapTypes;
104104
105105type
106106 { TForm1 }
107107
108108 TForm1 = class(TForm)
109109 procedure FormCreate(Sender: TObject);
110110 procedure FormDestroy(Sender: TObject);
111111 procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
112112 Shift: TShiftState; X, Y: Integer);
113113 procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
114114 procedure FormPaint(Sender: TObject);
115115 private
116116 { private declarations }
117117 image: TBGRABitmap;
118118 procedure DrawBrush(X, Y: Integer);
119119 procedure PaintImage;
120120 public
121121 { public declarations }
122122 end;
123123
124124var
125125 Form1: TForm1;
126126
127127implementation
128128
129129{ TForm1 }
130130
131131procedure TForm1.FormCreate(Sender: TObject);
132132begin
133133 image := TBGRABitmap.Create(640,480,BGRAWhite);
134134end;
135135
136136procedure TForm1.FormDestroy(Sender: TObject);
137137begin
138138 image.Free;
139139end;
140140
141141procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
142142 Shift: TShiftState; X, Y: Integer);
143143begin
144144 if Button = mbLeft then DrawBrush(X,Y);
145145end;
146146
147147procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
148148 Y: Integer);
149149begin
150150 if ssLeft in Shift then DrawBrush(X,Y);
151151end;
152152
153153procedure TForm1.FormPaint(Sender: TObject);
154154begin
155155 PaintImage;
156156end;
157157
158158procedure TForm1.DrawBrush(X, Y: Integer);
159159const radius = 20;
160160begin
161161 image.GradientFill(X-radius,Y-radius, X+radius,Y+radius,
162162 BGRABlack,BGRAPixelTransparent,gtRadial,
163163 PointF(X,Y), PointF(X+radius,Y), dmDrawWithTransparency);
164164
165165 PaintImage;
166166end;
167167
168168procedure TForm1.PaintImage;
169169begin
170170 image.Draw(Canvas,0,0,True);
171171end;
172172
173173initialization
174174 {$I UMain.lrs}
175175
176176end.
177177```
178178
179179### Run the program
180180
181181You should be able to draw on the form.
182182
183-<figure>
184-<img src="BGRATutorial3.png" title="BGRATutorial3.png" />
185-<figcaption>BGRATutorial3.png</figcaption>
186-</figure>
183+![](/wiki-images/a/aa/BGRATutorial3.png)
187184
188185### Continuous drawing
189186
190187To have a continuous drawing, we need additionnal variables:
191188
192189``` pascal
193190
194191TForm1 = class(TForm)
195192 ...
196193 private
197194 { private declarations }
198195 image: TBGRABitmap;
199196 mouseDrawing: boolean;
200197 mouseOrigin: TPoint;
201198```
202199
203200mouseDrawing will be True during the drawing (with left button pressed) and mouseOrigin will be the starting point of the segment being drawn.
204201
205202The clicking handler becomes a little bit more complicated:
206203
207204``` pascal
208205procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
209206 Shift: TShiftState; X, Y: Integer);
210207begin
211208 if Button = mbLeft then
212209 begin
213210 mouseDrawing := True;
214211 mouseOrigin := Point(X,Y);
215212 DrawBrush(X,Y,True); // or DrawBrush(X,Y);
216213 end;
217214end;
218215```
219216
220217It 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:
221218
222-<figure>
223-<img src="BGRATutorial3b.png" title="BGRATutorial3b.png" />
224-<figcaption>BGRATutorial3b.png</figcaption>
225-</figure>
219+![](/wiki-images/b/b1/BGRATutorial3b.png)
226220
227221Little by little, we add a new part, which is an opened segment:
228222
229-<figure>
230-<img src="BGRATutorial3c.png" title="BGRATutorial3c.png" />
231-<figcaption>BGRATutorial3c.png</figcaption>
232-</figure>
223+![](/wiki-images/d/d5/BGRATutorial3c.png)
233224
234225That's why we need a new parameter for the DrawBrush function, which becomes:
235226
236227``` pascal
237228procedure TForm1.DrawBrush(X, Y: Integer; Closed: Boolean);
238229const brushRadius = 20;
239230begin
240231 image.DrawLineAntialias(X,Y,mouseOrigin.X,mouseOrigin.Y,BGRA(0,0,0,128),brushRadius,Closed);
241232 mouseOrigin := Point(X,Y);
242233
243234 PaintImage;
244235end;
245236```
246237
247238We 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.
248239
249240DrawBrush definition must be updated in the interface.
250241
251242The MouseMove handler becomes:
252243
253244``` pascal
254245procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
255246 Y: Integer);
256247begin
257248 if mouseDrawing then DrawBrush(X,Y,False);
258249end;
259250```
260251
261252Finally, we need to add a MouseUp handler to update mouseDrawing:
262253
263254``` pascal
264255procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
265256 Shift: TShiftState; X, Y: Integer);
266257begin
267258 if Button = mbLeft then
268259 mouseDrawing := False;
269260end;
270261```
271262
272263### Code
273264
274265``` pascal
275266unit UMain;
276267
277268{$mode objfpc}{$H+}
278269
279270interface
280271
281272uses
282273 Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
283274 BGRABitmap, BGRABitmapTypes;
284275
285276type
286277 { TForm1 }
287278
288279 TForm1 = class(TForm)
289280 procedure FormCreate(Sender: TObject);
290281 procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
291282 Shift: TShiftState; X, Y: Integer);
292283 procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
293284 procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
294285 Shift: TShiftState; X, Y: Integer);
295286 procedure FormPaint(Sender: TObject);
296287 private
297288 { private declarations }
298289 image: TBGRABitmap;
299290 mouseDrawing: boolean;
300291 mouseOrigin: TPoint;
301292 procedure DrawBrush(X, Y: Integer; Closed: boolean);
302293 procedure PaintImage;
303294 public
304295 { public declarations }
305296 end;
306297
307298var
308299 Form1: TForm1;
309300
310301implementation
311302
312303{ TForm1 }
313304
314305procedure TForm1.FormCreate(Sender: TObject);
315306begin
316307 image := TBGRABitmap.Create(640,480,BGRAWhite);
317308end;
318309
319310procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
320311 Shift: TShiftState; X, Y: Integer);
321312begin
322313 if Button = mbLeft then
323314 begin
324315 mouseDrawing := True;
325316 mouseOrigin := Point(X,Y);
326317 DrawBrush(X,Y,True);
327318 end;
328319end;
329320
330321procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
331322 Y: Integer);
332323begin
333324 if mouseDrawing then DrawBrush(X,Y,False);
334325end;
335326
336327procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
337328 Shift: TShiftState; X, Y: Integer);
338329begin
339330 if Button = mbLeft then
340331 mouseDrawing := False;
341332end;
342333
343334procedure TForm1.FormPaint(Sender: TObject);
344335begin
345336 PaintImage;
346337end;
347338
348339procedure TForm1.DrawBrush(X, Y: Integer; Closed: Boolean);
349340const brushRadius = 20;
350341begin
351342 image.DrawLineAntialias(X,Y,mouseOrigin.X,mouseOrigin.Y,BGRA(0,0,0,128),brushRadius,Closed);
352343 mouseOrigin := Point(X,Y);
353344
354345 PaintImage;
355346end;
356347
357348procedure TForm1.PaintImage;
358349begin
359350 image.Draw(Canvas,0,0,True);
360351end;
361352
362353initialization
363354 {$I UMain.lrs}
364355
365356end.
366357```
367358
368359### Run the program
369360
370361Now the drawing is almost continous:
371362
372-<figure>
373-<img src="BGRATutorial3d.png" title="BGRATutorial3d.png" />
374-<figcaption>BGRATutorial3d.png</figcaption>
375-</figure>
363+![](/wiki-images/9/9a/BGRATutorial3d.png)
376364
377365[[BGRABitmap tutorial 2|Previous tutorial (image loading)]] \| [[BGRABitmap tutorial 4|Next tutorial (direct pixel access)]]
378366
379367---
380368*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).*
381369Category: BGRABitmap
382370Category: Graphics

Back to history