• TGraphicControl和TCustomControl自绘过程的理论解释


    TGraphicControl = class(TControl) // 这个类实在是简单,因为所有事情都已经委托给它的父Win控件了,只要管自己即可
    private
    FCanvas: TCanvas; // 私有内部画板,不用程序员申请就有了
    // 注意区别,其实图形控件没有画自己一说(但仍然接受WM_PAINT消息),直接响应消息并绘画即可。
    // 其父类已经在VCL体系中搭好了框架绘制当前图形控件,它会调用Paint函数执行程序员的画图动作。
    // Graphic控件自绘过程:
    // 0. Windows发消息给其父Win控件
    // 1. 如果父控件是WinControl,那么流程是:WMPaint, PaintHandler, PaintWindow, PaintWindows,其中最后一个函数PaintWindows会绘制所有图形子控件
    // 2. PaintWindows 给所有图形子控件执行 Perform(WM_PAINT, DC, 0) 消息,其中DC是父控件的句柄
    // 3. Graphic控件会通过WMPaint函数响应WM_PAINT消息,程序员不必改动这个函数,
    // 4. WMPaint函数调用虚函数Paint,程序员改写Paint可被准确应用上而不必对整个VCL框架有任何改动,甚至不用理解这件事情,只需填写Paint函数即可
    // 5. 如果父控件是CustomControl,那么会再多绕一道弯:先执行CustomControl的WMPaint,目的是加上自绘状态,再调用WinControl的WMPaint
    // 总结:整个过程特简单,就是父控件发来WM_Paint消息,对应的WMPaint函数已经写好,程序员自己填上Paint函数的内容即可
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
    protected
    procedure Paint; virtual; // 虚函数,空函数。注意一定是要虚函数才符合面向对象的精神,才能正确被调用。
    property Canvas: TCanvas read FCanvas;
    public
    constructor Create(AOwner: TComponent); override; // 简单创建Canvas并连接当前图形控件
    destructor Destroy; override; // 销毁内部画板和自己,取消自己的焦点 fixme 图形控件也可以有焦点?
    end;

    --------------------------------------------------------------------------------------------------

    TCustomControl = class(TWinControl) // 这个类的主要框架都在TWinControl里搭好了框架,所以才会出现最简单的三明治风格
    private
    FCanvas: TCanvas; // 私有内部画板,不用程序员申请就有了
    // Custom控件自绘过程:
    // 0. Windows发消息给CustomControl控件自己(也是Win控件,具有句柄)
    // 1. 响应绘制自己控件的源头,还是从CustomControl控件的WMPaint函数开始
    // 2. 三明治风格,加上csCustomPaint自绘风格后,调用父类同名WMPaint函数,这样可以把自己和所有子控件都管起来(有现成的VCL框架代码在其父类中准备好了)
    // 3. 父类同名函数根据四种不同情况:双缓冲,DC句柄,子控件数量,自绘标记,分别作出不同的判断后进行绘制
    // 4. 先绘制自己,再绘制所有子图形控件(如果有的话)
    // 5. 绘制自己的时候,父类的管理函数(一般是PaintHandler)会调用本类的PaintWindow覆盖函数(虚函数)
    // PaintWindow又会调用Paint函数,程序员通过改写Paint函数的内容,达到在框架内被自动调用的目的
    // 6. 图形子控件的绘制过程是通过父控件给它发送WM_PAINT消息,其中包含了父控件的DC句柄,然后委托给图形子控件自己进行绘制
    // 总结1:Custom控件的整个绘制过程道理与Graphic控件非常类似,只是少绕一些弯子(不必通过父控件来重绘)
    // WMPaint直接调用本类的Paint函数,而程序员通过改写Paint函数的内容,达到在框架内被自动调用的目的
    // 总结2:与直接继承自TWinControl的控件有所区别,后者直接覆盖PaintWindow函数,而不必响应WM_PAINT消息就可以达到被调用的目的了:http://www.cnblogs.com/findumars/p/3931703.html
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT; // 加Custom风格后重绘,调用TWinControl.WMPaint函数,因为要重画所有子控件
    protected
    // 此函数只被PaintHandler调用,后者又会被WMPaint WMPrintClient调用
    procedure PaintWindow(DC: HDC); override; // 虚函数,在VCL体系中搭好了框架画自己,它会调用Paint;函数执行程序员的画图动作。
    procedure Paint; virtual; // 虚函数,空函数。等待程序员填写画板的真正内容。框架已经由PaintWindow搭好了。
    property Canvas: TCanvas read FCanvas;
    public
    constructor Create(AOwner: TComponent); override; // 创建并设置内部画板
    destructor Destroy; override; // 销毁内部画板和自己
    end;

  • 相关阅读:
    SVG前戏—让你的View多姿多彩
    分享几个Android很强势的的开源框架
    终于,我还是下决心学Java后台了
    金9银10,分享几个重要的Android面试题
    django-多表操作2
    python基础-文件操作
    django-单表操作
    django-多表操作
    django-模板层基础2
    djano-模板层基础知识
  • 原文地址:https://www.cnblogs.com/findumars/p/3922064.html
Copyright © 2020-2023  润新知