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
      // fixme 这里不自绘,应该是指系统控件?
      if self is TButton then
      begin
          str:=self.Name;
//          ShowMessage(str);
//        inherited; // 奇怪啊,明明是TButton,为什么会落到TForm的WndProc去呢
      end;
      // 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里都准备好了
  // fixme 但是在哪里画自己呢?
  Exclude(FControlState, csCustomPaint);
end;
时间: 2024-10-07 16:57:44

TWinControl与TCustomControl真正的区别之处(TWinControl系统自绘,TCustomControl是Delphi自绘)的相关文章

MVC,MVP 和 MVVM 的区别之处

其实我一直以来,虽然做的是前端的工作,但是有一个疑问,就是什么是mvc模式,虽然大概知道,但是具体确实说不上来的的,今天,我就好好总结一下mvc ,mvp,mvvm模式的区别与相同. 1.MVC模式: MVC模式的意思是:M(Model) V( View)  C(Controller) 模型Model:数据保存 视图View:用户界面 控制器(Controller):业务逻辑 总结来说就是:用户界面(View) ==> 控制器*(Controller)  输入内容/点击 通过业务逻辑的更改,将内

Remoting&amp;WebService的区别之处

Remoting与Web Services的区别是:(1)既支持TCP信道又支持HTTP信道,传输速度快(2)即可传输XML的SOAP包又可传输二进制流,效率高(3)Remoteing主要用于C/S结构项目(4)不一定要依赖IIS服务器 remoting与平台相关,需要客户和服务器都支持.net framework框架,可配置特性比较好,可以自定义协议. web service可以做到跨平台通信,但必须采用SOAP协议.

TGraphicControl和TCustomControl自绘过程

TGraphicControl = class(TControl) // 这个类实在是简单,因为所有事情都已经委托给它的父Win控件了,只要管自己即可 private FCanvas: TCanvas; // 私有内部画板,不用程序员申请就有了 // 注意区别,其实图形控件没有画自己控件一说(但仍然接受WM_PAINT消息),直接响应消息并绘画即可. // 其父类已经在VCL体系中搭好了框架绘制当前图形控件,它会调用Paint;函数执行程序员的画图动作. // Graphic控件自绘过程: //

【转】escape()、encodeURI()、encodeURIComponent()区别详解

escape().encodeURI().encodeURIComponent()区别详解 原文链接:http://www.cnblogs.com/tylerdonet/p/3483836.html JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decodeURIComponent . 下面简单介绍一下它们的区别 1 escape()函数 定义和用法 e

Hibernate面试题 --- list和iterator方法的区别

Hibernate面试题  ---  list和iterator方法的区别 1.首先看两个例子来比较一下 (1)在用Query方法查询的时候,通过HQL语句来得到Query对象,并对Query对象进行操作,首先是用list方法获取到Query的List集合并输出: 1 @Test 2 public void listQuery() { 3 4 Configuration configuration = new Configuration().configure(); 5 SessionFacto

escape()、encodeURI()、encodeURIComponent()区别详解

JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decodeURIComponent . 下面简单介绍一下它们的区别 1 escape()函数 定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法 escape(string) 参数  描述  string  必需.要被转义或编码的字符串. 返回值 已编码的

深入理解静态方法和实例化方法的区别

这是一个经常被时时提出来的问题,很多时候我们以为理解了.懂了,但深究一下,我们却发现并不懂. 方法是我们每天都在写得,很多程序员大多都使用实例化方法,而很少使用静态方法,问原因也说不出来所以然,或者简单的回答两者定义的区别,静态方法不需要new就可以使用实例化方法需要new了以后才可以使用....我们真的理解了吗? 从实际项目开发说起,这里有开发项目的三种方式: 开发项目中把BLL和DAL分开,在BLL调用DAL的代码. 一.在DAL中使用静态方法,不创建实例直接调用(大概有很多人都使用这种方式

随笔之——伪类选择器:nth-child(n) 与 nth-of-type(n)的区别!!!

话不多说!直接正题!!! 一.E:nth-child(n)///选中父元素中第(n)个元素.若第n个元素为E则选中:若第n个不为E则不选中.n可以为2n(偶数).2n+1(奇数).等... 二.E:nth-of-type(n)///选中父元素中第(n)个为E的元素.n的取值同上. 三.   举个栗子>>> (1)下图可以看出两个选择符均可以达到想要的效果:没有什么区别...(往下看!)   (2).下图可以看出两者的区别之处:li:nth-child(2)直接选中父元素中第二个元素 //

jxl和POI的区别

最近两个项目中分别用到jxl和POI,因为用的都是其中的简单的功能,所以没有觉得这其中有太大的区别.有人针对他们做了比较,这里也拿出来展示一下. 首先从优缺点上来说 一.jxl 优点: Jxl对中文支持非常好,操作简单,方法看名知意. Jxl是纯javaAPI,在跨平台上表现的非常完美,代码可以再windows或者Linux上运行而无需重新编写 支持Excel 95-2000的所有版本(网上说目前可以支持Excel2007了,还没有尝试过) 生成Excel 2000标准格式 支持字体.数字.日期