为什么我不能使用 onClick 事件处理程序将形状绘制到 lazarus 中的表单上?

Why can I not use the onClick event handler to draw shapes onto a form in lazarus?

我的事件处理程序如下:

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;                      

我正在使用 Mac OS X

您必须阅读有关图形 windowing 系统的基础知识。无论是 Windows、MacOS 还是 UNIX X Window.

几乎普遍不是应用程序决定何时、何地绘制什么。操作系统决定并询问应用程序何时执行此操作。应用程序所能做的就是 使 其 window 的某些部分无效 - 即 通知 OS window 的某些部分不再有效,然后等到 OS 想要重新绘制该部分(如果 invalidated [可能永远不会重新绘制)window 被最小化或被另一个 window) 覆盖,然后 - 并且只有在那时 - 绘制。

那你怎么做呢?

方法 1:精通资源并接近真实的 OS 工作流程。

你把 TPaintbox 放在整个 form 上。

您将矩形和圆形作为不可见记录或 类 保存在表单变量中。当这些数字发生变化时(例如:您添加了另一个矩形,或者您增加了一些圆直径),您调用 MyForm.MyPaintBox.Invalidate 通知操作系统该 painboxt 的图像不再有效。当 OS 认为是时候刷新图像时,它会调用 MyForm.MyPaintBox.OnPaint 事件,在那种情况下你会像 MyPaintBox.Canvas.Rectangle(40, 40, 400, 200); 那样调用。注意 - 您将重新绘制颜料盒的 canvas,而不是表格的!

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;

方法二:懒惰和资源膨胀

你把 TImage 放在整个 form 上。

该图像将具有包含您想要的任何图片的隐式位图。更重要的是,它会跟踪您对该图片的绘制并自动调用 Invalidate 并自动处理 OS 的重绘请求。

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;

然而,代价是您可能会分配多达几兆字节的内存,仅用于在 OS 需要刷新表单图片的相对罕见的情况下保留您的图片。