My event handler is as follows:
procedure TfrmCanvasMethods.btnShapesClick(Sender: TObject);
begin
Canvas.Rectangle(40, 40, 400, 200);
Canvas.Rectangle(80, 80, 360, 160);
Canvas.Ellipse(150, 50, 290, 190);
Canvas.Ellipse(100, 100, 340, 140);
end;
I am using Mac OS X
You have to read fundamentals about graphic windowing systems. Be it Windows, MacOS or UNIX X Window.
Almost universally that is not the application who decides when, what and where to draw. It is Operating System that decides so and asks the application when to do it. All an application can do - is to invalidate some part of its window - that is to inform the OS that some part of the window is no more valid, and then wait until the OS would want that part repainted (maybe it would be never, if the invalidated window got minimized or covered by another window) and then - and only then - do the drawing.
So how can you do it?
Method 1: resources-savvy and close to real OS workflow.
You put a TPaintbox
over your whole form
.
You keep your rectangles and circles as non-visible records or classes inside your form's variables. When those figures are changed (example: you added yet another rectangle, or you increased some circle diameter) you call MyForm.MyPaintBox.Invalidate
to inform the operating system that the image of that painboxt is no more valid. When OS would consider it is timely to refresh the image, it would call MyForm.MyPaintBox.OnPaint
event and in that event you would make your calls like MyPaintBox.Canvas.Rectangle(40, 40, 400, 200);
. Notice - you would repaint the paintbox's canvas, not the form's one!
procedure TfrmCanvasMethods.btnShapesClick(Sender: TObject);
begin
MyPaintBox.Invalidate();
end;
procedure TfrmCanvasMethods.MyPaintBoxPaint(Sender: TObject);
var Canvas: TCanvas;
begin
Canvas := MyPaintbox.Canvas;
Canvas.Rectangle(40, 40, 400, 200);
Canvas.Rectangle(80, 80, 360, 160);
Canvas.Ellipse(150, 50, 290, 190);
Canvas.Ellipse(100, 100, 340, 140);
end;
Method 2: lazy and resources-bloating
You put a TImage
over your whole form
.
That image would have the implicit bitmap having any picture you would like. More so, it would track your drawing of that picture and would automagically call Invalidate
and would automagically handle OS's repaint requests.
procedure TfrmCanvasMethods.btnShapesClick(Sender: TObject);
var Canvas: TCanvas;
begin
MyImage.Picture.Bitmap.SetSize( MyImage.ClientWidth, MyImage.ClientHeight );
Canvas := MyImage.Picture.Bitmap.Canvas;
Canvas.Rectangle(40, 40, 400, 200);
Canvas.Rectangle(80, 80, 360, 160);
Canvas.Ellipse(150, 50, 290, 190);
Canvas.Ellipse(100, 100, 340, 140);
end;
The price however would be that you would allocate maybe as much as few megabytes of memory for nothing more than keeping your picture for those relatively rare cases when OS would need to refresh the picture of your form.