zoukankan      html  css  js  c++  java
  • 终于懂了:TWinControl与TCustomControl真正区别之处(TWinControl系统自绘,TCustomControl是Delphi自绘)

    关键在于TWinControl都是系统自绘,而TCustomControl都是Delphi自绘

    真正区别之处,我觉得是在这里:

    procedure TWinControl.WMPaint(var Message: TWMPaint);
    var
      DC, MemDC: HDC;
      MemBitmap, OldBitmap: HBITMAP;
      PS: TPaintStruct;
      str: String;
    begin
      // 这里第一次处理WM_PAINT消息
      // 注意,这里是重画句柄控件,重画图形控件不在这里
      // fixme 有空检测一下这个消息的DC是否为0 即系统发来的 WM_PAINT消息的参数内容是什么?一般是当前控件的HDC句柄
    
      // 不是双缓冲就立即绘制
      // FDoubleBuffered一共就两处使用,还有一处在WMEraseBkgnd
      if not FDoubleBuffered or (Message.DC <> 0) then
      begin
        // 不支持自绘,且没有图形子控件的那些控件,执行这里。
        // 主要指Windows自带控件,比如Button,Edit等等,整个StdCtrls里的标准控件都不自绘,但TForm自绘
        // important7 TCustomControl与TWinControl实际分家的地方
        if not (csCustomPaint in ControlState) and (ControlCount = 0) then // 注意csCustomPaint这个风格,即自绘。只有这里判断使用。
        begin// super 其父类根本没有这个函数,所以这里会调用消息索引函数,如果还找不到,就调用子类或者TWinControl.DefaultHandler来处理消息(事实上就是如此)。
          // fixme 这里超级复杂,执行Button1.Update会来到这里,会重绘TForm1。再次实验,确实如此。值得写一篇文章
          // 最后执行CallWindowProc(FDefWndProc)会调用TButton的WndProc来处理消息。一共7个消息分别处理,把WM转成CN消息。最后会传递到 CNCtlColorBtn
          // http://hi.baidu.com/bakyman/item/2a426ba5c6251d37020a4d42
          // TWinControl走这里(没有继承TCustomControl),比如TButton。它会调用 fixme2 好复杂哦
          inherited // fixme 会调用子类的WM_PAINT的消息索引函数?不是很确定
        end
        // 一般走这里(带canvas的控件)
        else
          PaintHandler(Message); // TCustomControl走这里,给所有子控件做剪裁并重画(挨个发送WM_PAINT消息)
      end
      else
      begin
        // 双缓冲,准备内存画板,此时还没有Canvas,所以用API旧方法
        // fixme 不清楚,到底是在用谁的句柄绘制?
        DC := GetDC(0);   // 参数0代表取得整个屏幕的DC
        MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom); // 创建当前DC的画板(大概是为了保留除了当前窗口以外的显示内容,跟画板的底板一样)
        ReleaseDC(0, DC); // 留下MemBitmap,然后释放整个屏幕的DC
        MemDC := CreateCompatibleDC(0); // 创建当前DC的兼容DC
        OldBitmap := SelectObject(MemDC, MemBitmap); // 把MemBitmap画板放到MemDC里去,就可以准备在MemDC里画了
        try
          DC := BeginPaint(Handle, PS); // 返回值是指定Window的DC
          // 双缓冲工作真正开始
          Perform(WM_ERASEBKGND, MemDC, MemDC); // 当前控件使用MemDC擦除背景。fixme 一般来说,擦除背景应该发生在重绘之前
          Message.DC := MemDC;  // 构建一个消息,把MemDC传入,当前控件和子控件都在MemDC上画
          // 注意是虚函数,图形控件和CustomControl都覆盖了它。CustomControl一定会调用这个父类虚函数,但图形控件一定不调用它。
          WMPaint(Message); // 递归调用函数(构建了一个消息,但不是发生消息),而且此时的DC不等于0,因此条件成立,进入块执行PaintHandler
          Message.DC := 0;  // 消息使用完毕,消息参数复位,但是通过消息得到的MemDC所有数据都在
          // 画完了内存画板,准备切换
          BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY); // 把画好所有控件的MemDC一次性拷贝到指定Window的DC
          EndPaint(Handle, PS); // 结束画图过程
        finally
          SelectObject(MemDC, OldBitmap); // API,退回到旧图形
          DeleteDC(MemDC);
          DeleteObject(MemBitmap);
        end;
      end;
    end;

    另外还有

    procedure TCustomControl.WMPaint(var Message: TWMPaint);
    begin
      // important TForm覆盖了它,因为多了一种情况:最小化时的画图只需画图标即可,与正常状态不是一回事
      // 但好笑的是,那里用的不是Include语法,而是+-,难道这两个类不是同一个人写的?
      Include(FControlState, csCustomPaint); // 标准控件里,没有一处使用这个标记
      inherited; // 因为TCustomControl可以包含子控件,因此必须发消息给所有子控件重画,整个调用框架已经在TWinControl里都准备好了
      Exclude(FControlState, csCustomPaint);
    end;
  • 相关阅读:
    Python3基础 函数 未指定返回值,返回NONE
    Python3基础 函数 有参数有返回值 对传入的参数加1
    Python3基础 函数 无参数无返回值 调用会输出hello world的函数
    Python3基础 函数 收集参数(tuple)+普通参数 的示例
    MVC中几种常用ActionResult
    sqlserver 中存储过程的基础知识记录
    常用的正则表达式方法2
    常用的正则表达式方法1
    vs2012运行项目报未能加载文件或程序集“System.Web.Mvc, Version=4.0.0.1,Culture=neutral”问题和解决方法
    怎样解决PowerDesigner15出现许可证过期问题?
  • 原文地址:https://www.cnblogs.com/findumars/p/2559142.html
Copyright © 2011-2022 走看看