• TControl,TWinControl和TGraphicControl的显示函数


    -------------------------- 显示隐藏刷新 --------------------------

    TControl = class(TComponent)
    procedure Show; 调用 Parent.ShowControl(Self);
    procedure Refresh; 简单调用虚拟函数 Repaint,自己不直接起作用。名叫Refresh的函数就这里一个,别无分号。
    procedure Repaint; virtual; 不透明则GetDC且重画控件,透明就简单Invalidate并Update,复杂。在TWinControl里被覆盖了,因此就算被调用也是对TGraphicControl起作用而已。
    procedure Invalidate; virtual; 调用InvalidateControl类函数,后者调用InvalidateRect API函数

    procedure Update; virtual; 调用 Parenet.Update,它的Parent是TWinControl,所以这句就是一个呼叫转移作用,并不直接起作用。
    procedure WndProc(var Message: TMessage); virtual; 处理完消息一般会Exit,否则只能Dispatch(Message);
    function Perform(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): LRESULT; overload; 根据参数构建TMessage,并调用WindowProc(Message);最后取得返回值
    procedure DefaultHandler(var Message); override; 只处理WM_SETTEXT消息,并且不继续传递


    TWinControl = class(TControl)

    procedure TWinControl.CMInvalidate(var Message: TMessage);
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT; 双缓冲则调用 PaintHandler,否则调用BeginPaint,复杂
    procedure Repaint; override; 直接调用 Invalidate; Update; 特简单。自定义控件的时候,总要写这句标识无效且立即重画。注意,这里Invalidate也是类函数,不是API

    procedure Update; override; 有句柄就立即UpdateWindow(WindowHandle); 这里的UpdateWindow可是真正的API,亮真家伙了,才能真正重画,不再转移呼叫了。

    procedure PaintControls(DC: HDC; First: TControl); 重画WinControl所包含的所有子控件(TLabel等) FControls FWinControls ,发送 Perform(WM_PAINT, DC, 0);
    procedure PaintHandler(var Message: TWMPaint); 调用BeginPaint或者PaintWindow或者重画FControls 复杂
    procedure PaintWindow(DC: HDC); virtual; 构建并发送 WM_PAINT到DefaultHandler里,所以一般得覆盖,否则不起作用(无法调用程序员的Paint代码),但是仍然可以画出默认的程序界面。而且在TCustomControl里也确实被重载了。

    procedure WndProc(var Message: TMessage); override;
    procedure DefaultHandler(var Message); override; 处理了少部分消息。自己有句柄的话,会调用CallWindowProc(FDefWndProc),否则inherited DefaultHandler(Message);

    TGraphicControl = class(TControl)
    private
    FCanvas: TCanvas; 可以画图了
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT; 简单调用 Paint;
    protected
    procedure Paint; virtual; 空函数,等待重写。比如TLabel的重画,就依赖于 procedure TCustomLabel.Paint; (它的上级TWinControl给它发WM_PAINT后调用它的Paint)。具体过程如下:TLabel的Create函数根据OS版本预先指定FDrawTextProc函数指针(也是指向自定义的类函数)。它的上级TWinControl收到WM_PAINT消息后,会给所有子控件发送WM_PAINT消息(具体过程查看TWinControl.PaintControls函数),此时TLabel会收到一个WM_PAINT消息,执行WMPaint函数,WMPaint会调用Paint虚函数,因此TLabel会调用自己的Paint函数,Paint函数会调用DoDrawText函数,DoDrawText根据不同情况判断Autosize和BiDi等属性做出相应处理后,最后调用FDrawTextProc函数,最后它会调用API函数Windows.DrawTextW,完成绘制。值得注意的是,这个API所用DC是借用父控件的DC。
    property Canvas: TCanvas read FCanvas;
    public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    end;


    TCustomControl = class(TWinControl)
    private
    FCanvas: TCanvas; 可以自绘了
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT; 简单调用 inherited
    protected
    procedure Paint; virtual; 空函数,等待重写
    procedure PaintWindow(DC: HDC); override; 简单调用 Paint;
    property Canvas: TCanvas read FCanvas;
    public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    end;

    要搞清楚 TWinControl 和 TCustomControl 的区别,就要搞清楚TCustomControl为什么要覆盖 WMPaint。为什么有的控件从TWinControl继承,有的从TCustomControl继承?主要区别在于后者可以自绘,前者不需要。

    -------------------------- 从TGraphicControl和TCustomControl开始,自动创建和包含Canvas实体 --------------------------

    constructor TGraphicControl.Create(AOwner: TComponent);
    begin
    inherited Create(AOwner);
    FCanvas := TControlCanvas.Create;
    TControlCanvas(FCanvas).Control := Self;
    end;

    constructor TCustomControl.Create(AOwner: TComponent);
    begin
    inherited Create(AOwner);
    FCanvas := TControlCanvas.Create;
    TControlCanvas(FCanvas).Control := Self;
    end;

  • 相关阅读:
    c#基础加强版之方法控制流复习-3控制台打印密码
    c#基础加强版之方法控制流复习-2变量是否初始化的问题
    c#基础加强版之方法控制流复习-1关于方法的讲解
    小菜学try语句,又被trouble给catch住了
    JQuery--CSS操作
    JavaScript--DOM操作
    JavaScript--选择器
    JQuery--jQuery对象与DOM对象
    JavaScript--DOM编程
    JDBC--调用函数&存错过程
  • 原文地址:https://www.cnblogs.com/findumars/p/3650448.html
Copyright © 2020-2023  润新知