Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 为什么画布是;“隐藏的”;在所有VCL控件中?_Delphi_Canvas_Vcl_Lazarus - Fatal编程技术网

Delphi 为什么画布是;“隐藏的”;在所有VCL控件中?

Delphi 为什么画布是;“隐藏的”;在所有VCL控件中?,delphi,canvas,vcl,lazarus,Delphi,Canvas,Vcl,Lazarus,我想做一个基本的过程,在任何控件(按钮、面板等)的画布上绘制一些东西(为了简单起见,让我们说一个三角形): 在这个函数中,我需要使用Control.Width&Control.Height来知道控件有多大。 事实证明,这比想象的要困难,因为画布是受保护的 一种解决方案是获取过程中控件的画布: VAR ParentControl: TWinControl; canvas: TCanvas; begin ParentControl:= Control.Parent; Canvas:=

我想做一个基本的过程,在任何控件(按钮、面板等)的画布上绘制一些东西(为了简单起见,让我们说一个三角形):

在这个函数中,我需要使用Control.Width&Control.Height来知道控件有多大。 事实证明,这比想象的要困难,因为画布是受保护的

一种解决方案是获取过程中控件的画布:

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
  • 现在我重写了绘画方法,但这意味着在多个地方复制绘画代码。当然,DrawTriangle可以接收更多参数(画布、控制宽度/高度等)。。。。但是。。。用暴露的油漆方法,一切都会变得更加优雅

    为什么画布被设计隐藏了

    没有真正隐藏,但在受保护的部分。要访问它,您必须从感兴趣的类派生一个新类,并将Canvas声明为public

    它是私有的,因为您不应该在应用程序级别访问它

    如果在需要的源代码中使用
    interposer
    类,则无需安装组件


    您也可以考虑重写<代码>油漆>代码>方法,并将您的绘图代码放在那里。

    < P>在对该问题的评论中发现

  • 将此解决方案限制为
    TCustomControl
    子体就足够了,并且
  • 如果绘图过程可以通过一个简单的函数调用从参数控件获得画布,这就足够“优雅”了
  • 如果是这样,可以采用以下解决方案:

    //
    //所需基础设施
    //
    类型
    TCustomControlCracker=类(TCustomControl)
    结束;
    函数CustomControlCanvas(AControl:TCustomControl):TCanvas;
    开始
    结果:=TCustomControlCracker(AControl).Canvas;
    结束;
    //
    //我的可重用绘图功能
    //(只能在TCustomControl子体中使用)
    //
    程序控制(A控制:TCustomControl);
    变量
    画布:TCanvas;
    开始
    画布:=CustomControlCanvas(AControl);
    TextOut(10,10,'Frog');
    结束;
    
    请注意,
    DrawFrog
    只接受一个参数,即控件本身。然后,它可以使用一个简单的函数调用获得控件的画布,而CPU开销非常小

    完整示例:

    单元1;
    接口
    使用
    Winapi.Windows、Winapi.Messages、System.SysUtils、System.Variants、System.Classes、Vcl.Graphics、,
    控件、窗体、对话框、ExtCtrls、StdCtrls;
    类型
    TForm1=类(TForm)
    过程表单创建(发送方:ToObject);
    私有的
    {私有声明}
    公众的
    {公开声明}
    结束;
    变量
    表1:TForm1;
    实施
    {$R*.dfm}
    类型
    TTestControl=类(TCustomControl)
    受保护的
    程序漆;推翻
    结束;
    类型
    TCustomControlCracker=类(TCustomControl)
    结束;
    函数CustomControlCanvas(AControl:TCustomControl):TCanvas;
    开始
    结果:=TCustomControlCracker(AControl).Canvas;
    结束;
    程序控制(A控制:TCustomControl);
    变量
    画布:TCanvas;
    开始
    画布:=CustomControlCanvas(AControl);
    TextOut(10,10,'Frog');
    结束;
    过程TForm1.FormCreate(发送方:TObject);
    开始
    使用TTestControl.Create(Self)do
    开始
    父母:=自我;
    顶部:=100;
    左:=100;
    宽度:=400;
    高度:=200;
    结束;
    结束;
    {TTestControl}
    程序控制。油漆;
    开始
    继承;
    Canvas.Brush.Color:=clSkyBlue;
    Canvas.FillRect(ClientRect);
    牵引蛙(自身);//使用我的可重用青蛙绘图功能
    结束;
    结束。
    

    尽管如此,我个人仍然会使用传递
    TCanvas
    (甚至是
    HDC
    )的标准方法,而不是控件,以及一些维度:

    procedure DrawFrog(ACanvas: TCanvas; const ARect: TRect);
    

    这将允许我将其用于其他控件(不仅是
    TCustomControl
    子体),以及打印机画布等。

    您不应该这样做。控件应该自己绘制。恐怕Olivier是对的。你什么时候在控件上绘图?通常,只有在收到窗口的
    WM_PAINT
    消息时,才能在其上绘制窗口。在其他时间(例如在
    OnClick
    事件处理程序中)在画布上绘制是不可行的(没有很多问题)。据我们所知,控件可能会在添加三角形后的毫秒内选择重新绘制自身。此外,许多Win32控件在一开始就很难自定义绘制。这里的想法是,如果我有一个包含大量代码的绘制过程,我需要在几个自定义控件中复制所有这些代码。。。。这与“代码的可重用性”的概念不符。@InNameofScience:现在我明白你的意思了。然后,解决方案是使用一个过程
    DrawTriangle(ACanvas:TCanvas;const-ARect:TRect)
    ,它在
    ARect
    处的
    ACanvas
    画布中绘制三角形。事实上,这就是所有GDI在Win32中的幕后工作方式。例如,请参见函数:它采用HDC,这在功能上相当于
    TCanvas
    。(本质上说:你不是在控件上画画,而是在“画布”上画画。)我通常有s FCN,以便能够在scn和打印机的简历上画画。@以科学的名义:我理解。我可以想出一些“解决方案”,但它们都需要比简单地传递两个附加参数更多的工作:)仅供参考,VCL有一个用于在任何
    t控件上绘图的类。因此,您不需要手动打开
    TCustomControl.Canvas
    。如果我出于其他原因需要画布,该怎么办?不是为了在上面画画吗?例如,我想截断带有省略号的文本。为此,我需要访问画布来测量文本大小
    procedure DrawFrog(ACanvas: TCanvas; const ARect: TRect);