国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VC美化原理補充

3.3.4 WM_DRAWITEM

OnCtlColor只能修改元素的顏色,但不能修改元素的界面框架,WM_DRAWITEM則可以。

當一個具有Owner draw風格的元素(包括按鈕、組合框、列表框和菜單等)需要顯示外觀時,該元素會發(fā)送一條WM_DRAWITEM消息至它的隸屬窗口(Owner)。

WM_DRAWITEM的映射函數(shù)原型如下:

afx_msg void OnDrawItem( int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct );

參數(shù):

nIDCtl 該控件的ID,如果該元素為菜單,則nIDCtl為0

lpDrawItemStruct 指向DRAWITEMSTRUCT結(jié)構(gòu)對象的指針,DRAWITEMSTRUCT的結(jié)構(gòu)定義如下:

  1. typedef struct tagDRAWITEMSTRUCT   
  2. {   
  3.     UINT    CtlType;   
  4.     UINT    CtlID;   
  5.     UINT    itemID;   
  6.     UINT    itemAction;   
  7.     UINT    itemState;   
  8.     HWND    hwndItem;   
  9.     HDC     hDC;   
  10.      RECT    rcItem;   
  11.     DWORD   itemData;   
  12. }DRAWITEMSTRUCT;   
typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; }DRAWITEMSTRUCT;

CtlType指定了控件的類型,其取值如表3所示:

類型值 含義

ODT_BUTTON 按鈕控件

ODT_COMBOBOX 組合框控件

ODT_LISTBOX 列表框控件

ODT_LISTVIEW 列表視圖

ODT_MENU 菜單項

ODT_STATIC 靜態(tài)文本控件

ODT_TAB Tab控件

表3 CtlType的類型值與含義

CtlID 指定自繪控件的ID值,該成員不適用于菜單項

itemID表示菜單項ID,也可以表示列表框或者組合框中某項的索引值。對于一個空的列表框或組合框,該成員的值為?C1。這時應用程序只繪制焦點矩形(該矩形的坐標由rcItem 成員給出)雖然此時控件中沒有需要顯示的項,但是繪制焦點矩形還是很有必要的,因為這樣做能夠提示用戶該控件是否具有輸入焦點。當然也可以設(shè)置itemAction 成員為合適值,使得無需繪制焦點。

itemAction 指定繪制行為,其取值為表4中所示值的一個或者多個的聯(lián)合:

類型值 含義

ODA_DRAWENTIRE 當整個控件都需要被繪制時,設(shè)置該值。

ODA_FOCUS 如果控件需要在獲得或失去焦點時被繪制,則設(shè)置該值。此時應該檢查itemState成員,以確定控件是否具有輸入焦點。

ODA_SELECT 如果控件需要在選中狀態(tài)改變時被繪制,則設(shè)置該值。此時應該檢查itemState 成員,以確定控件是否處于選中狀態(tài)。

表4 itemAction的類型值與含義

itemState 指定了當前繪制項的狀態(tài)。例如,如果菜單項應該被灰色顯示,則可以指定ODS_GRAYED狀態(tài)標志。其取值為表5中所示值的一個或者多個的聯(lián)合:

類型值 含義

ODS_CHECKED 標記狀態(tài),僅適用于菜單項。

ODS_DEFAULT 默認狀態(tài)。

ODS_DISABLED 禁止狀態(tài)。

ODS_FOCUS 焦點狀態(tài)。

ODS_GRAYED 灰化狀態(tài),僅適用于菜單項。

ODS_SELECTED 選中狀態(tài)。

ODS_HOTLIGHT 僅適用于Windows 98/Me/Windows 2000/XP,熱點狀態(tài):如果鼠標指針位于控件之上,則設(shè)置該值,這時控件會顯示高亮顏色。

ODS_INACTIVE 僅適用于Windows 98/Me/Windows 2000/XP,非激活狀態(tài)。

ODS_NOACCEL 僅適用于Windows 2000/XP,控件是否有快速鍵。

ODS_COMBOBOXEDIT 在自繪組合框控件中只繪制選擇區(qū)域。

ODS_NOFOCUSRECT 僅適用于Windows 2000/XP,不繪制捕獲焦點的效果。

表5 itemState的類型值與含義

hwndItem 指定了組合框、列表框和按鈕等自繪控件的窗口句柄;如果自繪的對象為菜單項,則表示包含該菜單項的菜單句柄。

hDC 指定了繪制操作所使用的設(shè)備環(huán)境。

rcItem 指定了將被繪制的矩形區(qū)域。這個矩形區(qū)域就是上面hDC的作用范圍。系統(tǒng)會自動裁剪組合框、列表框或按鈕等控件的自繪制區(qū)域以外的部分。也就是說rcItem中的坐標點(0,0)指的就是控件的左上角。但是系統(tǒng)不裁剪菜單項,所以在繪制菜單項的時候,必須先通過一定的換算得到該菜單項的位置,以保證繪制操作在我們希望的區(qū)域中進行。

itemData

對于菜單項,該成員的取值為由CMenu::AppendMenu、CMenu::InsertMenu、CMenu::ModifyMenu等函數(shù)傳遞給菜單的值。

對于列表框或這組合框,該成員的取值為由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等函數(shù)傳遞給控件的值。

如果ctlType 的取值是ODT_BUTTON或者ODT_STATIC,itemData的取值為0。

圖5是個相應的例子,它修改了按鈕的界面:

圖8 利用WM_DRAWITEM消息美化界面

實現(xiàn)代碼如下:

  1. BOOL CUi6Dlg::OnInitDialog()   
  2. {   
  3.     //…   
  4.     //創(chuàng)建字體   
  5.     //CFont CUi1View::m_Font   
  6.      m_Font.CreatePointFont(120, "Impact");   
  7.     //…   
  8. }   
  9.   
  10. void CUi6Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)   
  11. {   
  12.     if(nIDCtl == IDC_HELLO_CFAN)   
  13.      {   
  14.         //繪制按鈕框架   
  15.   
  16.         UINT uStyle = DFCS_BUTTONPUSH;   
  17.         //是否按下去了?   
  18.         if (lpDrawItemStruct->itemState & ODS_SELECTED)   
  19.              uStyle |= DFCS_PUSHED;   
  20.   
  21.          CDC dc;   
  22.          dc.Attach(lpDrawItemStruct->hDC);   
  23.          dc.DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle);   
  24.   
  25.         //輸出文字   
  26.          dc.SelectObject(&m_Font);   
  27.          dc.SetTextColor(RGB(0, 0, 255));   
  28.          dc.SetBkMode(TRANSPARENT);   
  29.   
  30.         CString sText;   
  31.          m_HelloCFan.GetWindowText(sText);   
  32.          dc.TextOut(lpDrawItemStruct->rcItem.left + 20, lpDrawItemStruct->rcItem.top + 20, sText);   
  33.   
  34.         //是否得到焦點   
  35.         if(lpDrawItemStruct->itemState & ODS_FOCUS)   
  36.          {   
  37.             //畫虛框   
  38.              CRect rtFocus = lpDrawItemStruct->rcItem;   
  39.              rtFocus.DeflateRect(3, 3);   
  40.              dc.DrawFocusRect(&rtFocus);   
  41.          }   
  42.   
  43.         return;   
  44.      }   
  45.      CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);   
  46. }   
BOOL CUi6Dlg::OnInitDialog() { //… //創(chuàng)建字體 //CFont CUi1View::m_Font m_Font.CreatePointFont(120, "Impact"); //… } void CUi6Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) { if(nIDCtl == IDC_HELLO_CFAN) { //繪制按鈕框架 UINT uStyle = DFCS_BUTTONPUSH; //是否按下去了? if (lpDrawItemStruct->itemState & ODS_SELECTED) uStyle |= DFCS_PUSHED; CDC dc; dc.Attach(lpDrawItemStruct->hDC); dc.DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle); //輸出文字 dc.SelectObject(&m_Font); dc.SetTextColor(RGB(0, 0, 255)); dc.SetBkMode(TRANSPARENT); CString sText; m_HelloCFan.GetWindowText(sText); dc.TextOut(lpDrawItemStruct->rcItem.left + 20, lpDrawItemStruct->rcItem.top + 20, sText); //是否得到焦點 if(lpDrawItemStruct->itemState & ODS_FOCUS) { //畫虛框 CRect rtFocus = lpDrawItemStruct->rcItem; rtFocus.DeflateRect(3, 3); dc.DrawFocusRect(&rtFocus); } return; } CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct); }

別忘了標記Owner draw屬性:

圖9 指定按鈕的Owner draw屬性

值得一提的是,CWnd內(nèi)部截獲了WM_DRAWITEM、WM_MEASUREITEM等消息,并映射成子元素的相應虛函數(shù)的調(diào)用,如CButton::DrawItem()。所以,以上例子也可以通過派生出一個CButton的派生類,并重載該類的DrawItem()函數(shù)來實現(xiàn)。使用虛函數(shù)機制實現(xiàn)界面美化參見3.4章節(jié)。

3.3.5 WM_MEASUREITEM

僅僅WM_DRAWITEM還是不夠的,對于一些特殊的控件,如ListBox,系統(tǒng)在發(fā)送WM_DRAWITEM消息前,還發(fā)送WM_MEASUREITEM消息,需要你設(shè)置ListBox中每個項目的高度。

WM_DRAWITEM的映射函數(shù)原型如下:

afx_msg void OnMeasureItem( int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct );

nIDCtl 該控件的ID,如果該元素為菜單,則nIDCtl為0

lpMeasureItemStruct指向MEASUREITEMSTRUCT結(jié)構(gòu)對象的指針,MEASUREITEMSTRUCT的結(jié)構(gòu)定義如下:

  1. typedef struct tagMEASUREITEMSTRUCT   
  2. {   
  3.     UINT    CtlType;   
  4.     UINT    CtlID;   
  5.     UINT    itemID;   
  6.     UINT    itemWidth;   
  7.     UINT    itemHeight;   
  8.     DWORD   itemData   
  9. } MEASUREITEMSTRUCT;   
typedef struct tagMEASUREITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemWidth; UINT itemHeight; DWORD itemData } MEASUREITEMSTRUCT;

CtlType指定了控件的類型,其取值如表6所示:

類型值 含義

ODT_COMBOBOX 組合框控件

ODT_LISTBOX 列表框控件

ODT_MENU 菜單項

表6 CtlType的類型值與含義

CtlID 指定自繪控件的ID值,該成員不適用于菜單項

itemID表示菜單項ID,也可以表示可變高度的列表框或組合框中某項的索引值。該成員不適用于固定高度的列表框或組合框。

itemWidth 指定菜單項的寬度

itemHeight指定菜單項或者列表框中某項的的高度,最大值為255

itemData

對于菜單項,該成員的取值為由CMenu::AppendMenu、CMenu::InsertMenu、CMenu::ModifyMenu等函數(shù)傳遞給菜單的值。

對于列表框或這組合框,該成員的取值為由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等函數(shù)傳遞給控件的值。

圖示出了OnMeasureItem的效果:

圖10 利用WM_MEASUREITEM消息美化界面

相應的OnMeasureItem()實現(xiàn)如下:

  1. void CUi7Dlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
  2. {   
  3.     if(nIDCtl == IDC_COLOR_PICKER)   
  4.      {   
  5.         //設(shè)定高度為30   
  6.          lpMeasureItemStruct->itemHeight = 30;   
  7.         return;   
  8.      }   
  9.      CDialog::OnMeasureItem(nIDCtl, lpMeasureItemStruct);   
  10. }   
void CUi7Dlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if(nIDCtl == IDC_COLOR_PICKER) { //設(shè)定高度為30 lpMeasureItemStruct->itemHeight = 30; return; } CDialog::OnMeasureItem(nIDCtl, lpMeasureItemStruct); }

同樣別忘了指定列表框的Owner draw屬性:

圖11 指定下拉框的Owner draw屬性

3.3.6 NM_CUSTOMDRAW

大家也許熟悉WM_NOTIFY,控件通過WM_NOTIFY向父窗口發(fā)送消息。在WM_NOTIFY消息體中,部分控件會發(fā)送NM_CUSTOMDRAW告訴父窗口自己需要繪圖。

可以反射NM_CUSTOMDRAW消息,如:

ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)

afx_msg void OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult);

參數(shù):

pNMHDR 說到底只是一個指針,大多數(shù)情況下它指向一個NMHDR結(jié)構(gòu)對象,NMHDR結(jié)構(gòu)如下:

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

其中:

hwndFrom 發(fā)送方控件的窗口句柄

idFrom 發(fā)送方控件的ID

code 通知代碼

對于某些控件來說,pNMHDR則會解釋成其它內(nèi)容更豐富的結(jié)構(gòu)對象的指針,如:對于列表控件來說,pNMHDR常常指向一個NMCUSTOMDRAW對象,NMCUSTOMDRAW結(jié)構(gòu)如下:

  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;   
typedef struct tagNMCUSTOMDRAWINFO { NMHDR hdr; DWORD dwDrawStage; HDC hdc; RECT rc; DWORD dwItemSpec; UINT uItemState; LPARAM lItemlParam; } NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;

hdr NMHDR對象

dwDrawStage 當前繪制狀態(tài),其取值如表7所示:

類型值 含義

CDDS_POSTERASE 擦除循環(huán)結(jié)束

CDDS_POSTPAINT 繪制循環(huán)結(jié)束

CDDS_PREERASE 準備開始擦除循環(huán)

CDDS_PREPAINT 準備開始繪制循環(huán)

CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam參數(shù)有效

CDDS_ITEMPOSTERASE 列表項擦除結(jié)束

CDDS_ITEMPOSTPAINT 列表項繪制結(jié)束

CDDS_ITEMPREERASE 準備開始列表項擦除

CDDS_ITEMPREPAINT 準備開始列表項繪制

CDDS_SUBITEM 指定列表子項

表7 dwDrawStage的類型值與含義

hdc指定了繪制操作所使用的設(shè)備環(huán)境。

rc指定了將被繪制的矩形區(qū)域。

dwItemSpec 列表項的索引

uItemState 當前列表項的狀態(tài),其取值如表8所示:

類型值 含義

CDIS_CHECKED 標記狀態(tài)。

CDIS_DEFAULT 默認狀態(tài)。

CDIS_DISABLED 禁止狀態(tài)。

CDIS_FOCUS 焦點狀態(tài)。

CDIS_GRAYED 灰化狀態(tài)。

CDIS_SELECTED 選中狀態(tài)。

CDIS_HOTLIGHT 熱點狀態(tài)。

CDIS_INDETERMINATE 不定狀態(tài)。

CDIS_MARKED 標注狀態(tài)。

表8 uItemState的類型值與含義

lItemlParam 當前列表項的綁定數(shù)據(jù)

pResult 指向狀態(tài)值的指針,指定系統(tǒng)后續(xù)操作,依賴于dwDrawStage:

當dwDrawStage為CDDS_PREPAINT,pResult含義如表9所示:

類型值 含義

CDRF_DODEFAULT 默認操作,即系統(tǒng)在列表項繪制循環(huán)過程不再發(fā)送NM_CUSTOMDRAW。

CDRF_NOTIFYITEMDRAW 指定列表項繪制前后發(fā)送消息。

CDRF_NOTIFYPOSTERASE 列表項擦除結(jié)束時發(fā)送消息。

CDRF_NOTIFYPOSTPAINT 列表項繪制結(jié)束時發(fā)送消息。

表9 pResult的類型值與含義(一)

當dwDrawStage為CDDS_ITEMPREPAINT,pResult含義如表10所示:

類型值 含義

CDRF_NEWFONT 指定后續(xù)操作采用應用中指定的新字體。

CDRF_NOTIFYSUBITEMDRAW 列表子項繪制時發(fā)送消息。

CDRF_SKIPDEFAULT 系統(tǒng)不必再繪制該子項。

表10 pResult的類型值與含義(二)

以下是一個利用NM_CUSTOMDRAW消息繪制出的多色列表框的例子:

圖12 利用NM_CUSTOMDRAW消息美化界面

對應代碼如下:

  1. void CCoolList::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult)   
  2. {   
  3.     //類型安全轉(zhuǎn)換   
  4.      NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);   
  5.      *pResult = 0;   
  6.        
  7.     //指定列表項繪制前后發(fā)送消息   
  8.     if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)   
  9.      {   
  10.          *pResult = CDRF_NOTIFYITEMDRAW;   
  11.      }   
  12.     else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)   
  13.      {   
  14.         //奇數(shù)行   
  15.         if(pLVCD->nmcd.dwItemSpec % 2)   
  16.              pLVCD->clrTextBk = RGB(255, 255, 128);   
  17.         //偶數(shù)行   
  18.         else  
  19.              pLVCD->clrTextBk = RGB(128, 255, 255);   
  20.         //繼續(xù)   
  21.          *pResult = CDRF_DODEFAULT;   
  22.      }   
  23. }   
void CCoolList::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult) { //類型安全轉(zhuǎn)換 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR); *pResult = 0; //指定列表項繪制前后發(fā)送消息 if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { *pResult = CDRF_NOTIFYITEMDRAW; } else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { //奇數(shù)行 if(pLVCD->nmcd.dwItemSpec % 2) pLVCD->clrTextBk = RGB(255, 255, 128); //偶數(shù)行 else pLVCD->clrTextBk = RGB(128, 255, 255); //繼續(xù) *pResult = CDRF_DODEFAULT; } }

注意到上例采取了3.1所推薦的第2種實現(xiàn)方法,派生了一個新類CCoolList。

3.4 使用MFC類的虛函數(shù)機制

修改Windows界面,除了從Windows消息機制下功夫,也可以從MFC類下功夫,這應該得益于類的虛函數(shù)機制。為了防止諸如“面向?qū)ο蠹夹g(shù)”等術(shù)語在此泛濫,以下僅舉一段代碼作為例子:

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

這是MFC中viewcore.cpp中的源代碼,很多讀者總不明白OnDraw()和OnPaint()之間的關(guān)系,從以上的代碼中很容易看出,CView的WM_PAINT消息響應函數(shù)OnPaint()會自動調(diào)用CView::OnDraw()。而作為開發(fā)者的用戶,可以通過簡單的OnDraw()的重載實現(xiàn)對WM_PAINT的處理。所以說,對MFC類的虛函數(shù)的重載是對消息機制的擴展。

以下列出了與界面美化相關(guān)的虛函數(shù),參數(shù)說明略去:

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元素自繪函數(shù)

很顯然,位圖菜單都是通過這個DrawItem畫出來的。限于篇幅,在此不再附以例程。

本文為白喬原創(chuàng),曾經(jīng)在《電腦愛好者》合訂本上發(fā)表。

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
白喬原創(chuàng):VC之美化界面篇
WM_MEASUREITEM
MFC按鈕自繪消息分析
VC MFC列表視圖(CListCtrl)控件
自繪控件的4種方法
自繪按鈕的實現(xiàn)
更多類似文章 >>
生活服務
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服