zoukankan      html  css  js  c++  java
  • 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;

  • 相关阅读:
    printcap
    browser-ua
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode70 爬楼梯
  • 原文地址:https://www.cnblogs.com/findumars/p/3922064.html
Copyright © 2011-2022 走看看