【发布时间】:2021-03-11 00:16:09
【问题描述】:
我想做一个基本程序,在任何控件(按钮、面板等)的画布上绘制一些东西(为了简单起见,我们说一个三角形):
procedure DrawTriangle(Control: TCustomControl);
在这个函数中,我需要使用 Control.Width 和 Control.Height 来知道控件有多大。 事实证明比想象的要困难,因为 Canvas 受到保护。
一种解决方案是在过程中获取控件的画布:
VAR
ParentControl: TWinControl;
canvas: TCanvas;
begin
ParentControl:= Control.Parent;
Canvas:= TCanvas.Create;
TRY
Canvas.Handle:= GetWindowDC(ParentControl.Handle);
WITH Canvas DO
xyz
FINALLY
FreeAndNil(canvas);
END;
end;
但是每次我想画东西时创建和销毁画布似乎都浪费了 CPU...
所以,我的问题是:
- 为什么画布被设计隐藏(保护)?
- 如何在不浪费 CPU 的情况下优雅地解决这个问题(一个参数)?
现在我重写了 Paint 方法,但这意味着在多个地方重复绘制代码。当然,DrawTriangle 可以接收更多参数(Canvas、Control Width/Height 等),....但好吧...使用暴露的 Paint 方法,一切都会更加优雅。
【问题讨论】:
-
你不应该那样做。控件应该自己绘制。
-
恐怕奥利维尔是对的。 什么时候你在控件上绘图?通常,只有在收到
WM_PAINT消息时才能绘制窗口。在其他时间(例如在OnClick事件处理程序中)在画布上绘制是不可行的(没有很多问题)。据我们所知,控件可能会在您添加三角形后的毫秒内选择重绘自身。此外,很多 Win32 控件一开始就很难自定义绘制。 -
这里的想法是,如果我有一个包含大量代码的绘画程序,我需要在几个自定义控件中复制所有这些代码......这与“代码的可重用性”概念。
-
@InTheNameOfScience:现在我明白你的意思了。然后解决方案是有一个过程
DrawTriangle(ACanvas: TCanvas; const ARect: TRect),它在ARect的ACanvas画布中绘制三角形。事实上,这就是所有 GDI 在 Win32 中的幕后工作方式。例如,参见Rectangle函数:它采用 HDC,其功能等效于TCanvas。 (本质上:您不是在控件上绘图,而是在“画布”上绘图。)我经常有 s fcns 能够在 scn 上和打印机的 cvs 上绘图。 -
@InTheNameOfScience:我明白。我可以想到一些“解决方案”,但它们都需要比简单地传递两个附加参数更多的工作! :)