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

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
自繪按鈕的實現(xiàn)

如果你希望能夠在自己的程序中表現(xiàn)出新意,那么你一定不會僅僅滿足于MFC提供那些標(biāo)準(zhǔn)控件。這時,我們就必須自己另外多做些工作了。就改變控件外觀這一點(diǎn)來說,主要是利用控件的自繪功能(Owner Draw)實現(xiàn)的。本篇將和各位一起定義一個XP風(fēng)格的CXPButton按鈕類,目的不在于介紹CXPButton類的使用技巧,而在于向各位闡述實現(xiàn)自繪按鈕的方法。當(dāng)然如果你覺得CXPButton有用的話,也可以把它的源文件保存下來,直接加入到自己的項目中。

本篇要點(diǎn):
一、準(zhǔn)備工作
二、實現(xiàn)原理及難點(diǎn)
三、按鈕類的使用
四、小結(jié)與提示
五、附錄

一、準(zhǔn)備工作

在開始編碼之前,首先應(yīng)該確定好,更準(zhǔn)確的說應(yīng)該是設(shè)計好按鈕在各種狀態(tài)下的外觀。按鈕控件的幾中基本狀態(tài)包括:
Normal狀態(tài),就是按鈕一開始顯示時的樣子。
Over狀態(tài),鼠標(biāo)指針移動到按鈕上面時按鈕顯示的樣子。
Down狀態(tài),按下按鈕時顯示的樣子。
Focus狀態(tài),按鈕按下后松開的樣子,例如標(biāo)準(zhǔn)按鈕按下松開之后會看到按鈕內(nèi)部有一個虛線框。
Disable狀態(tài),當(dāng)然就是按鈕被設(shè)置成無效的時候的樣子啦。

我參考了一下WindowsXP中普通按鈕的實際樣子,設(shè)計出XP按鈕各種狀態(tài)的外觀,如下圖所示:


至于Down狀態(tài)主要是在Over狀態(tài)的基礎(chǔ)上將文字往右下的方向稍微平移,以實現(xiàn)下壓的效果。

二、實現(xiàn)原理及難點(diǎn)

下面我們開始類的創(chuàng)建,在Workspace的ClassView頁中右擊列表樹的根結(jié)點(diǎn),選擇New Class…



在彈出窗口中進(jìn)行派生類的定義,如下圖所示,注意,你需要填寫的只有Name和Base class兩項,其余的選項保持默認(rèn)值就可以了。



按OK按鈕退出之后,我們可以在ClassView里面看到新創(chuàng)建的類的名字。接下來我們可以為CXPButton類添加各種成員變量。因為自繪控件說穿了就是畫圖,所以在成員變量中可以看到各種與畫圖有關(guān)的數(shù)據(jù)類型,一般來說成員變量會在類的構(gòu)造函數(shù)中初始化,在類的析構(gòu)函數(shù)中銷毀。詳細(xì)代碼請參見本篇附帶的源程序。
下面簡要敘述一下按鈕的實現(xiàn)原理:

1. 在控件初始化時為按鈕添加Owner Draw的屬性。這是因為在MFC中,要想激活控件的自繪功能,要求該控件的屬性中必須包含屬性值BS_OWNERDRAW,這一步我們可以通過類向?qū)镃XPButton類添加PreSubclassWindow()函數(shù),在該函數(shù)中完成屬性值的設(shè)置。當(dāng)激活控件的自繪功能之后,每次控件狀態(tài)改變的時候都會運(yùn)行函數(shù)DrawItem(),該函數(shù)的作用就是繪制控件在各種狀態(tài)下的外觀。

2. 添加WM_MOUSELEAVE消息函數(shù),當(dāng)鼠標(biāo)指針離開按鈕時,觸發(fā)該消息函數(shù),我們在函數(shù)中添加代碼,通知DrawItem函數(shù)鼠標(biāo)指針已經(jīng)離開了,讓按鈕重繪。

3. 添加WM_MOUSEHOVER消息函數(shù),當(dāng)鼠標(biāo)指針位于按鈕之上時,觸發(fā)該消息函數(shù),我們在函數(shù)重添加代碼,通知DrawItem函數(shù)鼠標(biāo)指針現(xiàn)在正在按鈕的上面,讓按鈕重繪。

4. 添加DrawItem函數(shù)。在DrawItem中根據(jù)按鈕當(dāng)前的狀態(tài)繪制按鈕的外觀??梢哉f自繪控件的大部分功能都是在這個函數(shù)中實現(xiàn)的。DrawItem函數(shù)包含了一個LPDRAWITEMSTRUCT的指針,本篇會在稍后予以講解。

 

了解了基本的設(shè)計思路之后,剩下就看我們怎么去實現(xiàn)了。我本人覺得這里有兩個難點(diǎn),首先是WM_MOUSELEAVE和WM_MOUSEHOVER不是標(biāo)準(zhǔn)的Windows消息函數(shù),它們不能通過類向?qū)硖砑樱械奶砑庸ぷ鞫夹枰ㄟ^手工輸入代碼來完成。另一個難點(diǎn)是DrawItem中的LPDRAWITEMSTRUCT指針,它指向了一個DRAWITEMSTRUCT的結(jié)構(gòu),這個結(jié)構(gòu)中包含了控件的各種細(xì)節(jié),為我們提供了實現(xiàn)自繪功能的必要信息。

難點(diǎn)一:
事實上WM_MOUSELEAVE和WM_MOUSEHOVER兩個Windows消息是通過WM_MOUSEMOVE消息觸發(fā)的,而WM_MOUSEMOVE是標(biāo)準(zhǔn)的Windows消息,因此我們可以通過類向?qū)頌镃XPButton類添加WM_MOUSEMOVE消息函數(shù)。



函數(shù)的代碼見如下,這段代碼非常有用,在其它的自繪控件中,如果想觸發(fā)WM_MOUSELEAVE和WM_MOUSEHOVER消息,也是使用類似的方法實現(xiàn)的。

void CXPButton::OnMouseMove(UINT nFlags, CPoint point) {       // TODO: Add your message handler code here and/or call default       if (!m_bTracking)       {              TRACKMOUSEEVENT tme;              tme.cbSize = sizeof(tme);              tme.hwndTrack = m_hWnd;              tme.dwFlags = TME_LEAVE | TME_HOVER;              tme.dwHoverTime = 1;              m_bTracking = _TrackMouseEvent(&tme);       }       CButton::OnMouseMove(nFlags, point);}
我們接著添加WM_MOUSELEAVE和WM_MOUSEHOVER消息消息函數(shù)。在CXPButton類的聲明中(即在XPButton.h文件中)找到afx_msg void OnMouseMove(UINT nFlags, CPoint point);的函數(shù)聲明,緊接其下輸入
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);
然后在XPButton.cpp文件中找到ON_WM_MOUSEMOVE(),緊接其后輸入
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
當(dāng)然最后還有函數(shù)的實現(xiàn)了,詳細(xì)代碼可見本篇提供的源程序,這里就不再重復(fù)了。

難點(diǎn)二:
下面我們看看DRAWITEMSTRUCE結(jié)構(gòu)為我們提供了哪些有用信息呢?
DRAWITEMSTRUCT結(jié)構(gòu)的定義如下:
typedef struct tagDRAWITEMSTRUCT {    UINT   CtlType;                       //控件類型    UINT   CtlID;                          //控件ID    UINT   itemID;                        //菜單項、列表框或組合框中某一項的索引值    UINT   itemAction;                   //控件行為    UINT   itemState;                     //控件狀態(tài)    HWND   hwndItem;                 //父窗口句柄或菜單句柄    HDC    hDC;                           //控件對應(yīng)的繪圖設(shè)備句柄    RECT   rcItem;                        //控件所占據(jù)的矩形區(qū)域    DWORD  itemData;                  //列表框或組合框中某一項的值} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;
其實不僅是按鈕控件,其它控件,如ComboBox、ListBox、StaticText等都是通過DRAWITEMSTRUCT來記錄控件信息的。關(guān)于這個結(jié)構(gòu)的詳細(xì)文檔可參考本篇的附錄。

也許你早已看到許多自繪按鈕的例子,實際上自繪按鈕本身的函數(shù)結(jié)構(gòu)都是差不多的,它們顯示效果的區(qū)別主要取決于代碼編寫者對GDI作圖函數(shù)的運(yùn)用與掌握程度。有興趣的朋友可以研究一下CXPButton類中DrawItem函數(shù)的數(shù)據(jù)結(jié)構(gòu),其實只要修改一下其中GDI繪圖函數(shù)的部分代碼,馬上又能做出另一個自繪按鈕控件了。

三、按鈕類的使用

下面演示CXPButton類的使用。往對話框中添加一個按鈕控件,假設(shè)它的ID值為IDC_BUTTON1。進(jìn)入類向?qū)В–lass Wizard)的Member Variables屬性頁,為IDC_BUTTON1添加一個變量m_btnNormal。確定退出后再進(jìn)行編譯,就可以看到重新定義過XP風(fēng)格按鈕了。



如果你是之間把CXPButton的源文件引入自己的工程中的,那么在上圖的Variable type中是看不到CXPButton選項的。但是可以通過以下方法加入:

1. 首先保存工程后退出。
2. 在工程的目錄下找到一個后綴名為.clw的文件,將其刪除。但是為了以防萬一還是建議你實現(xiàn)備份一下。
3. 重新打開工程,進(jìn)入類向?qū)?,此時會看到一下一個彈出對話框,我們選擇“是(Yes)”。



4. 再選擇“Add All”,這樣我們就可以在類向?qū)е惺褂肅XPButton的變量類型了。

四、小結(jié)與提示


對于按鈕來說,當(dāng)按鈕上面任何可見的部分發(fā)生變換的時候,都要調(diào)用DrawItem函數(shù)進(jìn)行重繪。自繪制按鈕必須設(shè)定BS_OWNERDRAW的屬性,設(shè)置的代碼在PreSubclassWindows函數(shù)中完成。另外為了防止系統(tǒng)字體設(shè)置的變化影響控件的表達(dá)效果,還可以在該函數(shù)中為控件指定某種固定的字體。但是要注意的是這個
讓我們來回顧一下實現(xiàn)自繪按鈕的基本步驟:
a. 確定設(shè)計方案;
b. 初始化,但是記得要在函數(shù)退出前恢復(fù)先前的GDI對象,并釋放所占領(lǐng)的資源;
c. 添加相應(yīng)消息函數(shù);
d. 添加繪圖函數(shù)DrawItem,在DrawItem中作圖的順序一般是先畫外邊框,再上底色,接著寫文字,最后是畫內(nèi)邊框。不過有些人也喜歡把邊框放到最后畫,這問題不大。

五、附錄

DRAWITEMSTRUCT結(jié)構(gòu)文檔(根據(jù)Msdn翻譯)

DRAWITEMSTRUCT

DRAWITEMSTRUCT 為需要自繪的控件或者菜單項提供了必要的信息。在需要繪制的控件或者菜單項對應(yīng)的WM_DRAWITEM消息函數(shù)中得到一個指向該結(jié)構(gòu)的指針。 DRAWITEMSTRUCT結(jié)構(gòu)的定義如下:
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType;
UINT CtlID;
UINT itemID;
UINT itemAction;
UINT itemState;
HWND hwndItem;
HDC hDC;
RECT rcItem;
ULONG_PTR itemData;
} DRAWITEMSTRUCT;

結(jié)構(gòu)成員:

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

取值
描述

ODT_BUTTON
按鈕控件

ODT_COMBOBOX
組合框控件

ODT_LISTBOX
列表框控件

ODT_LISTVIEW
列表視圖控件

ODT_MENU
菜單項

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

ODT_TAB
Tab控件

CtlID

指定了自繪控件的ID值,而對于菜單項則不需要使用該成員

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

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

取值
描述

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

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

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

itemState
指定了當(dāng)前繪制操作完成后,所繪項的可見狀態(tài)。例如,如果菜單項應(yīng)該被灰色顯示,則可以指定ODS_GRAYED狀態(tài)標(biāo)志。其取值可以為下表中所示值的一個或者多個的聯(lián)合。

取值
描述

ODS_CHECKED
如果菜單項將被選中,則可設(shè)置該值。該值只對菜單項有用。

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

ODS_DEFAULT
默認(rèn)值。

ODS_DISABLED
如果控件將被禁止,則設(shè)置該值。

ODS_FOCUS
如果控件需要輸入焦點(diǎn),則設(shè)置該值。

ODS_GRAYED
如果控件需要被灰色顯示,則設(shè)置該值。該值只在繪制菜單時使用。

ODS_HOTLIGHT
Windows 98/Me, Windows 2000/XP: 如果鼠標(biāo)指針位于控件之上,則設(shè)置該值,這時控件會顯示高亮顏色。

ODS_INACTIVE
Windows 98/Me, Windows 2000/XP: 表示沒有激活的菜單項。

ODS_NOACCEL
Windows 2000/XP: 控件是否有快速鍵盤。

ODS_NOFOCUSRECT
Windows 2000/XP: 不繪制捕獲焦點(diǎn)的效果。

ODS_SELECTED
選中的菜單項。

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

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

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

itemData
對于菜單項,該成員的取值可以是由

CMenu::AppendMenu、
CMenu::InsertMenu或者
CMenu::ModifyMenu

等函數(shù)傳遞給菜單的值。

對于列表框或這組合框,該成員的值可以為由

ComboBox::AddString、
CComboBox::InsertString、
CListBox::AddString或者
CListBox::InsertString

等傳遞給控件的值。

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

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
白喬原創(chuàng):VC之美化界面篇
VC美化原理補(bǔ)充
自繪控件的4種方法
用VC++實現(xiàn)自繪按鈕控制
VC知識庫文章 - MFC程序員的WTL指南: Part V - 高級對話框用戶界面類
MFC按鈕自繪消息分析
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服