好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

终于懂了:TWinControl与TCustomControl真正区别之处(TWinControl系

终于懂了: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测试数据/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 ;

查看更多关于终于懂了:TWinControl与TCustomControl真正区别之处(TWinControl系的详细内容...

  阅读:38次