Delphi Programming
mNo edit summary
(Replacing page with '{{Propose Delete}} Reason: see full article Create Your Own Paint Program')
 
Line 1: Line 1:
  +
{{Propose Delete}}
[[Create Your Own Paint Program|back to page 1]]
 
   
 
Reason: see full article [[Create Your Own Paint Program]]
In this part, you will create the tool for drawing rectangles.
 
 
==The Rectangle Tool==
 
 
Set up a button on the panel for the rectangle tool. Name it boxtool. Make the '''group index''' 1 and '''enabled''' true so it will work with the other tool buttons as a group - when one button is pressed, the others un-press. You will probably want to make a glyph for it as you did for the pencil tool.
 
 
When the user draws a rectangle, the first click on the image determines the starting corner of the rectangle. We need variables to remember this and various other things. Add more to your list of variables near the top of the unit:
 
<code><pre>
 
var
 
Mainform: TMainform;
 
toolInUse: integer;
 
filename: string;
 
x1,y1,x2,y2,toolInUse: integer;
 
holdingArea: Tbitmap;
 
holdingSomething: Boolean;
 
r1,r2: Trect;
 
</pre></code>
 
Each of the Trect variables holds a set of four integer variables for the left, top, right and bottom of a rectangle.
 
 
===On Mouse DOWN===
 
Now that we are going to have more tools, we need to keep track of which one is in use. We will '''replace''' the old drawingNow variable that only has two possible values with the integer variable '''toolInUse''' which can hold any positive or negative whole number. When the user first clicks the mouse on image1, we must remember which tool button is pressed. '''Change''' your existing procedure to:
 
<code><pre>
 
procedure TMainform.Image1MouseDown(Sender: TObject;
 
Button: TMouseButton; Shift: TShiftState;
 
X, Y: Integer);
 
begin
 
with image1.canvas do moveto(x,y);
 
x1 := x; y1 := y; {remember starting point}
 
toolInUse := 0; {default: no tool in use}
 
if pencil.down then toolInUse := 1;
 
If boxtool.down then
 
begin {-- box tool chosen --}
 
toolInUse := 2;
 
image1.canvas.brush.style := bsClear; {no fill}
 
end;
 
end;
 
</pre></code>
 
 
Notice that the procedure header shows what information is available from Windows on entry - the state of the mouse button and x,y coordinates of the mouse pointer. Thus we can copy the starting coordinates to our own variables, x1 and y1. The line ending in "bsClear" sets the brush (for filling the interior of the rectangle) to clear or no fill color at all. We programmers must remember that the pencil tool is number 1 and the open box tool is number 2.
 
 
===On Mouse MOVE===
 
Now '''change''' procedure '''Image1MouseMove''' to use the new toolInUse variable, and do some things when we are using the new rectangle tool.
 
<code><pre>
 
If toolInUse = 1 then With image1.canvas do lineto(x,y);
 
If toolInUse = 2 then
 
begin {-- rectangle tool --}
 
if holdingSomething then
 
begin {restore the area captured last move}
 
with image1.canvas do copyrect(R1,holdingArea.canvas,R2);
 
holdingArea.free;
 
end;
 
Capture(x1,y1,x,y); {capture the are to be used this time}
 
image1.canvas.rectangle(x1,y1,x2,y2); {draw the rectangle}
 
end;
 
</pre></code>
 
The '''Capture''' statement makes a copy of the rectangular area where we temporarily draw a rectangle. This is done so that when the mouse moves on to a new place, we can restore whatever was covered up by the temporary rectangle - that’s what the copyrect statement does. The capture and rectangle statements need 4 numbers to specify their rectangular areas: left,top,right,bottom. A new Boolean variable (true or false) '''holdingSomething''' remembers whether or not we have copied all the pixels in a rectangular area into a holdingArea of memory. It may not be possible to understand all this just now!
 
 
===Capture===
 
The holdingArea is just a Windows bitmap, and the copyRect command is built into Delphi's image component, but we must write our own '''Capture''' procedure to copy the pixels in a rectangular area into the holdingArea. Begin by typing
 
<code><pre>
 
Procedure Capture(x1,y1,x,y: integer);
 
</pre></code>
 
in the list of procedures at the top of the unit (just before the word '''private''' would be fine).
 
 
Now type the new procedure, at the end of the unit (but before the final end). This is difficult typing; you must be very careful to get it exactly right or your rectangle tool will do weird things. I assure you I have copied & pasted the code from a tested program so it does work.
 
<code><pre>
 
Procedure TMainform.Capture(x1,y1,x,y: integer);
 
begin
 
x2 := x; y2 := y; {remember this spot}
 
{allocate memory for the holding area and set generous width and height}
 
holdingArea := Tbitmap.create;
 
holdingArea.width := abs(x2-x1) + 2;
 
holdingArea.height := abs(y2-y1) + 2;
 
 
With R1 do {R1 is a rectangle in Image1}
 
begin
 
{find left & right sides of Image rectangle to capture}
 
if x1 < x2 then begin left := x1; right := x2+1 end
 
else begin left := x2; right := x1+1 end;
 
{find top & bottom of rectangle to capture}
 
if y1 < y2 then begin top := y1-1; bottom := y2+1 end
 
else begin top := y2-1; bottom := y1+1 end;
 
end;
 
With R2 do {R2 is a rectangle in the holdingArea}
 
begin
 
left := 0; top := 0; right := R1.right-R1.left; bottom := R1.bottom-R1.top
 
end;
 
{copy the area from Image1 to the holdingArea}
 
With holdingArea.canvas do copyrect(R2,Image1.canvas,R1);
 
holdingSomething := true;
 
end;
 
</pre></code>
 
Don’t worry if you do not understand this one! It really should be part of the invisible inner workings of Delphi. Basically, it just copies a rectangle of pixels from Image1 to the holdingArea but there is some tricky work figuring out the exact dimensions.
 
 
===On Mouse UP===
 
When the user releases the mouse after completing a rectangle, we need to restore the last temporary rectangular area and draw the final one. Your procedure Image1MouseUp should look like this:
 
<code><pre>
 
if toolInUse = 2 then
 
begin
 
if holdingSomething then
 
begin
 
with image1.canvas do copyrect(R1,holdingArea.canvas,R2);
 
holdingArea.free; holdingsomething := false;
 
end;
 
Image1.canvas.rectangle(x1,y1,x2,y2);
 
end;
 
toolInUse := 0;
 
</pre></code>
 
 
To complete the rectangle tool, we need to make sure that when the program first runs it doesn’t think it has already captured a rectangular area. In the FormCreate procedure put:
 
<code><pre>
 
holdingSomething := false;
 
</pre></code>
 
That was quite a lengthy write, and you will no doubt have some errors to fix before you get it all working. However, we have developed a way of temporarily drawing a figure on the image as the mouse moves and restoring the image afterward. You can use this to do several other tools with much less work.
 
 
[[Create Your Own Paint Program 5|go to the next page]]
 

Latest revision as of 14:34, 14 January 2009

Reason: see full article Create Your Own Paint Program