Archived

This topic is now archived and is closed to further replies.

Delphi : TCanvas Component

This topic is 5577 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

After hours of help files, and trying to solve my problem I am resorting to asking for help here. Basically, I feel I have an ok grasp of the delphi environment so I downloaded the source codefor some games (Tetris, Breakout, Pacman) and they all involve basic shapes such as rectangles drawn and moved around on the TCanvas object. I have searched and searched, read all sorts of tutorials but cannot find how to create and use and instance of TCanvas. After searching many help files I am stuck as to how I will progress. If anyone can help, it is greatly appreciated. What about me? What about Raven?

Share this post


Link to post
Share on other sites
The (rather unwanted) answer is that "usually, you don''t create TCanvas objects." Oops!

TCanvas provides a (*very*) nice wrapper around ''Device Contexts'' from the Windows GDI. This lets you do drawing very easily. You can create them (I''ll explain how in a little while) but first you have to know about some other things...

First of all, many objects contain a TCanvas as a property (called "Canvas"). For example, your form has a Canvas property, which you can then use to draw your lovely stuff. If you want double buffering for it then you can set the canvas'' DoubleBuffered property to true, which will reduce flickering during the OnPaint method.

However, the Canvas isn''t limited to just your forms. For example, you can dump down a TPaintBox object (from the System tab, IIRC). This contains a canvas for you and clips out any objects outside. In effect, it''s an easy way to get a canvas - dump down a TPaintBox, write code for the OnPaint handler, and you''re flying!

PaintBox1.Canvas.TextOut(0, 0, ''Some text''); 


...bung that in your Paintbox''s OnPaint and you''ll see what I mean.

There''s a better way to do this, though - you can create TBitmaps and use their associated Canvas property. You do all your drawing onto the bitmap and copy the results to the screen using another canvas''s Draw method (meaning you''re doing double-buffering, which is a very good idea...):


  procedure DisplayYourBmp(const Filename: String; x,y: Integer);
var
Bmp: TBitmap;
begin
if not FileExists(Filename) then Exit;

Bmp := TBitmap.Create;
try
Bmp.LoadFromFile(Filename);

// draw onto the bitmap''s canvas here

Bmp.Canvas.Textout(20, 30, ''Some text'');

Paintbox1.Canvas.Draw(x,y, Bmp); // draw the bmp onto some canvas

finally
Bmp.Free;
end;
end;

// write a handler for your paintbox, for example...

procedure TForm1.Paintbox1Paint(Sender: TObject);
begin
DisplayYourBmp(''somefile.bmp'', 10, 20); // draw stuff

end;


(Normally you''d create the bitmap once when your program starts and free it at the end, perhaps using FormCreate and FormDestroy. This would be more efficient.)

Note that the bitmap has a canvas for you to play around - as can be seen with the "Bmp.Canvas.Textout(...)" line.

This means that whenever you want a TCanvas, you usually *use one that''s sitting as a property elsewhere*. For example, your form, a paintbox, a TImage component, a TBitmap...

If you *really* want to create a TCanvas then you have to be aware of a wrinkle - it needs to be associated with a handle. Each object in Windows (hiding away at a level below the VCL) has a "handle", which is a way to identify the object. You pass this into most Windows API functions so that it knows what object to change.

Now, you can use GetDC() and ReleaseDC() to get and release device contexts for a window, which lets you draw onto them. This is what TCanvas wraps up nicely.

After all that, here''s some code:


  procedure Funky;
var
Canv: TCanvas;
begin
Canv := TCanvas.Create;
try
Canv.Handle := GetDC(0); // associate with the desktop handle(!)

try
Canv.TextOut(20, 40, ''SomeText''); // look closely at your screen ;)

finally
ReleaseDC(0, Canv.Handle);
end;
finally
Canv.Free;
end;
end;


That example is actually slightly perverse - you''re drawing *to the screen(!)* rather than your app. It depends entirely on the handle you pass in to GetDC. Most of your components have a "Handle" property, so you could, for example, say "Canv.Handle := GetDC(Button1.Handle);"

In most cases, though, it''s pointless - a canvas is already exposes, so you could just use that instead.

Also, note that you have to assign the handle for the canvas before using it, because if you don''t then it doesn''t know where to draw! This will result in an exception being thrown when you first use it.

Share this post


Link to post
Share on other sites
Hi

A Delphi form (TForm component) has a canvas property which is an instance of TCanvas, you can use directly, no need to create a new instance, eg

form1.Canvas.LineTo(x,y)

Here''s an example of how to draw a bitmap to the canvas, from the Delphi Help files:


  procedure TForm1.Button1Click(Sender: TObject);

var
Bitmap : TBitMap;
begin
Bitmap := TBitmap.Create;
try
with Bitmap do begin
LoadFromFile(''C:\Program Files\Common Files\Borland Shared\Images\Splash\256color\factory.bmp'');
Transparent := True;
TransParentColor := BitMap.canvas.pixels[50,50];
Form1.Canvas.Draw(0,0,BitMap);
TransparentMode := tmAuto;
Form1.Canvas.Draw(50,50,BitMap);
end;
finally
Bitmap.Free;

end;
end;


Hope this answers your question

______________________________

Don''t ask me, I''m just the code monkey

Share this post


Link to post
Share on other sites