MFC自绘控件与界面美化4

35 篇文章 0 订阅

3.3.6 NM_CUSTOMDRAW

 大家也许熟悉WM_NOTIFY,控件通过WM_NOTIFY向父窗口发送消息。在WM_NOTIFY消息体中,部分控件会发送NM_CUSTOMDRAW告诉父窗口自己需要绘图。 
可以反射NM_CUSTOMDRAW消息,如: 
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw) 
afx_msg void OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult); 
参数: 
pNMHDR 说到底只是一个指针,大多数情况下它指向一个NMHDR结构对象,NMHDR结构如下: 

[cpp] view plaincopy

  1. typedef struct tagNMHDR  
  2. {   
  3.     HWND hwndFrom;   
  4.     UINT idFrom;   
  5.     UINT code;   
  6. } NMHDR;  

[cpp] view plaincopy

  1. typedef struct tagNMHDR  
  2. {   
  3.     HWND hwndFrom;   
  4.     UINT idFrom;   
  5.     UINT code;   
  6. } NMHDR;  

其中: 
hwndFrom 发送方控件的窗口句柄 
idFrom 发送方控件的ID 
code 通知代码 
对于某些控件来说,pNMHDR则会解释成其它内容更丰富的结构对象的指针,如:对于列表控件来说,pNMHDR常常指向一个NMCUSTOMDRAW对象,NMCUSTOMDRAW结构如下: 

[cpp] view plaincopy

  1. typedef struct tagNMCUSTOMDRAWINFO  
  2. {  
  3.     NMHDR  hdr;  
  4.     DWORD  dwDrawStage;  
  5.     HDC    hdc;  
  6.     RECT   rc;  
  7.     DWORD  dwItemSpec;  
  8.     UINT   uItemState;  
  9.     LPARAM lItemlParam;  
  10. } NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;  

[cpp] view plaincopy

  1. typedef struct tagNMCUSTOMDRAWINFO  
  2. {  
  3.     NMHDR  hdr;  
  4.     DWORD  dwDrawStage;  
  5.     HDC    hdc;  
  6.     RECT   rc;  
  7.     DWORD  dwItemSpec;  
  8.     UINT   uItemState;  
  9.     LPARAM lItemlParam;  
  10. } NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;  

hdr NMHDR对象 
dwDrawStage 当前绘制状态,其取值如表7所示:
类型值 含义 
CDDS_POSTERASE 擦除循环结束 
CDDS_POSTPAINT 绘制循环结束 
CDDS_PREERASE 准备开始擦除循环 
CDDS_PREPAINT 准备开始绘制循环 
CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam参数有效 
CDDS_ITEMPOSTERASE 列表项擦除结束 
CDDS_ITEMPOSTPAINT 列表项绘制结束 
CDDS_ITEMPREERASE 准备开始列表项擦除 
CDDS_ITEMPREPAINT 准备开始列表项绘制 
CDDS_SUBITEM 指定列表子项
表7 dwDrawStage的类型值与含义
hdc指定了绘制操作所使用的设备环境。 
rc指定了将被绘制的矩形区域。 
dwItemSpec 列表项的索引 
uItemState 当前列表项的状态,其取值如表8所示:
类型值 含义 
CDIS_CHECKED 标记状态。 
CDIS_DEFAULT 默认状态。 
CDIS_DISABLED 禁止状态。 
CDIS_FOCUS 焦点状态。 
CDIS_GRAYED 灰化状态。 
CDIS_SELECTED 选中状态。 
CDIS_HOTLIGHT 热点状态。 
CDIS_INDETERMINATE 不定状态。 
CDIS_MARKED 标注状态。
表8 uItemState的类型值与含义
lItemlParam 当前列表项的绑定数据 
pResult 指向状态值的指针,指定系统后续操作,依赖于dwDrawStage: 
当dwDrawStage为CDDS_PREPAINT,pResult含义如表9所示:
类型值 含义 
CDRF_DODEFAULT 默认操作,即系统在列表项绘制循环过程不再发送NM_CUSTOMDRAW。 
CDRF_NOTIFYITEMDRAW 指定列表项绘制前后发送消息。 
CDRF_NOTIFYPOSTERASE 列表项擦除结束时发送消息。 
CDRF_NOTIFYPOSTPAINT 列表项绘制结束时发送消息。
表9 pResult的类型值与含义(一) 
当dwDrawStage为CDDS_ITEMPREPAINT,pResult含义如表10所示:
类型值 含义 
CDRF_NEWFONT 指定后续操作采用应用中指定的新字体。 
CDRF_NOTIFYSUBITEMDRAW 列表子项绘制时发送消息。 
CDRF_SKIPDEFAULT 系统不必再绘制该子项。
表10 pResult的类型值与含义(二)
以下是一个利用NM_CUSTOMDRAW消息绘制出的多色列表框的例子: 
 
图12 利用NM_CUSTOMDRAW消息美化界面 
对应代码如下: 

[cpp] view plaincopy

  1. void CCoolList::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     //类型安全转换   
  4.     NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR);  
  5.     *pResult = 0;  
  6.       
  7.     //指定列表项绘制前后发送消息   
  8.     if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)  
  9.     {  
  10.         *pResult = CDRF_NOTIFYITEMDRAW;  
  11.     }  
  12.     else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)  
  13.     {  
  14.         //奇数行   
  15.         if(pLVCD->nmcd.dwItemSpec % 2)  
  16.             pLVCD->clrTextBk = RGB(255, 255, 128);  
  17.         //偶数行   
  18.         else  
  19.             pLVCD->clrTextBk = RGB(128, 255, 255);  
  20.         //继续   
  21.         *pResult = CDRF_DODEFAULT;  
  22.     }  
  23. }  

[cpp] view plaincopy

  1. void CCoolList::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     //类型安全转换  
  4.     NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR);  
  5.     *pResult = 0;  
  6.       
  7.     //指定列表项绘制前后发送消息  
  8.     if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)  
  9.     {  
  10.         *pResult = CDRF_NOTIFYITEMDRAW;  
  11.     }  
  12.     else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)  
  13.     {  
  14.         //奇数行  
  15.         if(pLVCD->nmcd.dwItemSpec % 2)  
  16.             pLVCD->clrTextBk = RGB(255, 255, 128);  
  17.         //偶数行  
  18.         else  
  19.             pLVCD->clrTextBk = RGB(128, 255, 255);  
  20.         //继续  
  21.         *pResult = CDRF_DODEFAULT;  
  22.     }  
  23. }  

注意到上例采取了3.1所推荐的第2种实现方法,派生了一个新类CCoolList。 
 
 
3.4 使用MFC类的虚函数机制

 
 
修改Windows界面,除了从Windows消息机制下功夫,也可以从MFC类下功夫,这应该得益于类的虚函数机制。为了防止诸如“面向对象技术”等术语在此泛滥,以下仅举一段代码作为例子: 

[cpp] view plaincopy

  1. void CView::OnPaint()  
  2. {  
  3.  // standard paint routine   
  4.  CPaintDC dc(this);  
  5.  OnPrepareDC(&dc);  
  6.  OnDraw(&dc);  
  7. }  

[cpp] view plaincopy

  1. void CView::OnPaint()  
  2. {  
  3.  // standard paint routine  
  4.  CPaintDC dc(this);  
  5.  OnPrepareDC(&dc);  
  6.  OnDraw(&dc);  
  7. }  

这是MFC中viewcore.cpp中的源代码,很多读者总不明白OnDraw()和OnPaint()之间的关系,从以上的代码中很容易看出,CView的WM_PAINT消息响应函数OnPaint()会自动调用CView::OnDraw()。而作为开发者的用户,可以通过简单的OnDraw()的重载实现对WM_PAINT的处理。所以说,对MFC类的虚函数的重载是对消息机制的扩展。 
以下列出了与界面美化相关的虚函数,参数说明略去: 
CButton::DrawItem 
CCheckListBox::DrawItem 
CComboBox::DrawItem 
CHeaderCtrl::DrawItem 
CListBox::DrawItem 
CMenu::DrawItem 
CStatusBar::DrawItem 
CStatusBarCtrl::DrawItem 
CTabCtrl::DrawItem
virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ); 
Owner draw元素自绘函数 
很显然,位图菜单都是通过这个DrawItem画出来的。限于篇幅,在此不再附以例程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值