




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、利用按鈕自繪制作圖形按鈕 - VC2007-06-29 09:02:12| 分類: vc+,c+,c | 標簽:按鈕 vc+ 編程 |字號大中小 訂閱 利用按鈕自繪制作圖形按鈕 我們要舉的例子是利用一張包含按鈕的三種狀態(鼠標移動,鼠標離開,鼠標單擊)的位圖來繪制按鈕,因為三種狀態在一張位圖上,所以每種狀態的圖片高度都相等,而寬度是位圖總長度的1/3。 1.首先創建一個CBitmapButton的子類CHoverButton,并創建四個類成員變量:/指示鼠標是否在
2、按鈕上面BOOL m_bHover;/按鈕是否跟蹤到鼠標BOOL m_bTracking;/保存圖片的變量CBitmap mybitmap;/按鈕尺寸CSize m_ButtonSize;2.在類的構造函數中,初始化和鼠標相關的變量CHoverButton:CHoverButton()m_bHover = FALSE; m_bTracking = FALSE; 3.創建一個載入位圖的成員函數,參數為位圖的資源標識符。在按鈕自繪之前,必須有相應的位圖已經載入。BOOL LoadBitmap(UINT bitmapid); 其實現為:BOOL CHoverButton:LoadBitmap(UIN
3、T bitmapid)/載入圖片mybitmap.Attach(:LoadImage(:AfxGetInstanceHandle(),MAKEINTRESOURCE(bitmapid), IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);BITMAP bitmapbits;/獲取位圖信息并存入bitmapbits結構中mybitmap.GetBitmap(&bitmapbits);/取位圖相應的高度和1/3寬度。m_ButtonSize.cy=bitmapbits.bmHeight;m_ButtonSize.cx=bitmapbits.bmWidth/3;Set
4、WindowPos( NULL, 0,0, m_ButtonSize.cx,m_ButtonSize.cy,SWP_NOMOVE |SWP_NOOWNERZORDER );return TRUE;4.重載按鈕的虛擬函數DrawItem()成員函數當一個自繪按鈕的外觀發生變化時由框架調用.其函數原型為:virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct );DRAWITEMSTRUCT結構包含被繪制項目的信息。下面是該函數的實現void CHoverButton:DrawItem(LPDRAWITEMSTRUCT lpDrawItemS
5、truct)/獲取保存在DRAWITEMSTRUCT結構中且在繪制按鈕時必須使用的設備上下文CDC* mydc=CDC:FromHandle(lpDrawItemStruct->hDC);/創建兼容的設備上下文CDC* pMemDC = new CDC;pMemDC -> CreateCompatibleDC(mydc);/保存舊對象CBitmap * pOldBitmap;pOldBitmap = pMemDC -> SelectObject(&mybitmap);CPoint point(0,0); /判斷按鈕是否處于選擇狀態,如果是則繪制選擇狀態的按鈕位圖,在我
6、們提供的位圖中,選中狀態的按鈕圖片是第二個if(lpDrawItemStruct->itemState & ODS_SELECTED)mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx,0,SRCCOPY);else /判斷鼠標是否離開還是在按鈕上面,以便繪制相應的位圖if(m_bHover)mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx*2,0,SRCCOPY);elsemydc-
7、>BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,0,0,SRCCOPY); / clean uppMemDC -> SelectObject(pOldBitmap);delete pMemDC;tme.cbSize = sizeof(tme);tme.hwndTrack = m_hWnd;tme.dwFlags = TME_LEAVE|TME_HOVER;tme.dwHoverTime = 1;m_bTracking = _TrackMouseEvent(&tme);CBitmapButton:OnMouseMove(n
8、Flags, point);LRESULT CHoverButton:OnMouseLeave(WPARAM wparam, LPARAM lparam)m_bTracking = FALSE;m_bHover=FALSE;/重畫按鈕Invalidate(TRUE);return 0;LRESULT CHoverButton:OnMouseHover(WPARAM wparam, LPARAM lparam) m_bHover=TRUE;Invalidate(TRUE);return 0;6.我們把這個按鈕放入對話框進行測試,首先在基于對話框的應用程序中加入一個按鈕,設置其Owner Draw
9、的屬性為true。然后添加一個按鈕控件變量,然后用CHoverButton類代替CButton類CHoverButton m_HoverButton;最后在對話框的OnInitDialog()處理函數中加入下面一行代碼來為按鈕的自繪作準備:m_HoverButton.LoadBitmap(IDB_BITMAP1);自繪按鈕的實現如果你希望能夠在自己的程序中表現出新意,那么你一定不會僅僅滿足于MFC提供那些標準控件。這時,我們就必須自己另外多做些工作了。就改變控件外觀這一點來說,主要是利用控件的自繪功能(Owner Draw)實現的。本篇將和各位一起定義一個XP風格的CXPButton按鈕類,目
10、的不在于介紹CXPButton類的使用技巧,而在于向各位闡述實現自繪按鈕的方法。當然如果你覺得CXPButton有用的話,也可以把它的源文件保存下來,直接加入到自己的項目中。 本篇要點: 一、準備工作 二、實現原理及難點 三、按鈕類的使用 四、小結與提示 五、附錄 一、準備工作 在開始編碼之前,首先應該確定好,更準確的說應該是設計好按鈕在各種狀態下的外觀。按鈕控件的幾中基本狀態包括: Normal狀態,就是按鈕一開始顯示時的樣子。 Over狀態,鼠標指針移動到按鈕上面時按鈕顯示的樣子。 Down狀態,按下按鈕時顯示的樣子。 Focus狀態,按鈕按下后松開的樣子,例如標準按鈕按下松
11、開之后會看到按鈕內部有一個虛線框。 Disable狀態,當然就是按鈕被設置成無效的時候的樣子啦。 我參考了一下WindowsXP中普通按鈕的實際樣子,設計出XP按鈕各種狀態的外觀,如下圖所示: 至于Down狀態主要是在Over狀態的基礎上將文字往右下的方向稍微平移,以實現下壓的效果。 二、實現原理及難點 下面我們開始類的創建,在Workspace的ClassView頁中右擊列表樹的根結點,選擇New Class 在彈出窗口中進行派生類的定義,如下圖所示,注意,你需要填寫的只有Name和Base class兩項,其余的選項保持默認值就可以了。 按OK按鈕退出之后,我們
12、可以在ClassView里面看到新創建的類的名字。接下來我們可以為CXPButton類添加各種成員變量。因為自繪控件說穿了就是畫圖,所以在成員變量中可以看到各種與畫圖有關的數據類型,一般來說成員變量會在類的構造函數中初始化,在類的析構函數中銷毀。詳細代碼請參見本篇附帶的源程序。 下面簡要敘述一下按鈕的實現原理: 1. 在控件初始化時為按鈕添加Owner Draw的屬性。這是因為在MFC中,要想激活控件的自繪功能,要求該控件的屬性中必須包含屬性值BS_OWNERDRAW,這一步我們可以通過類向導為CXPButton類添加PreSubclassWindow()函數,在該函數中完成屬性值的設置。當激
13、活控件的自繪功能之后,每次控件狀態改變的時候都會運行函數DrawItem(),該函數的作用就是繪制控件在各種狀態下的外觀。 2. 添加WM_MOUSELEAVE消息函數,當鼠標指針離開按鈕時,觸發該消息函數,我們在函數中添加代碼,通知DrawItem函數鼠標指針已經離開了,讓按鈕重繪。 3. 添加WM_MOUSEHOVER消息函數,當鼠標指針位于按鈕之上時,觸發該消息函數,我們在函數重添加代碼,通知DrawItem函數鼠標指針現在正在按鈕的上面,讓按鈕重繪。 4. 添加DrawItem函數。在DrawItem中根據按鈕當前的狀態繪制按鈕的外觀。可以說自繪控件的大部分功能都是在這個函數中實現的。
14、DrawItem函數包含了一個LPDRAWITEMSTRUCT的指針,本篇會在稍后予以講解。 了解了基本的設計思路之后,剩下就看我們怎么去實現了。我本人覺得這里有兩個難點,首先是WM_MOUSELEAVE和WM_MOUSEHOVER不是標準的Windows消息函數,它們不能通過類向導來添加,所有的添加工作都需要通過手工輸入代碼來完成。另一個難點是DrawItem中的LPDRAWITEMSTRUCT指針,它指向了一個DRAWITEMSTRUCT的結構,這個結構中包含了控件的各種細節,為我們提供了實現自繪功能的必要信息。 難點一:事實上WM_MOUSELEAVE和WM_MOUSEHOVER兩個Wi
15、ndows消息是通過WM_MOUSEMOVE消息觸發的,而WM_MOUSEMOVE是標準的Windows消息,因此我們可以通過類向導來為CXPButton類添加WM_MOUSEMOVE消息函數。 函數的代碼見如下,這段代碼非常有用,在其它的自繪控件中,如果想觸發WM_MOUSELEAVE和WM_MOUSEHOVER消息,也是使用類似的方法實現的。 view source print?01.void CXPButton:OnMouseMove(UINT nFlags, CPoint point) 02. 03.
16、 / TODO: Add your message handler code here and/or call default 04. if (!m_bTracking) 05. 06. TRACKMOUSEEVENT tme; 07.
17、; tme.cbSize = sizeof(tme); 08. tme.hwndTrack = m_hWnd; 09.
18、60;tme.dwFlags = TME_LEAVE | TME_HOVER; 10. tme.dwHoverTime = 1; 11. m_bTracking = _TrackMouseEvent(&tme); 12.
19、160; 13. CButton:OnMouseMove(nFlags, point); 14.我們接著添加WM_MOUSELEAVE和WM_MOUSEHOVER消息消息函數。在CXPButton類的聲明中(即在XPButton.h文件中)找到afx_msg void OnMouseMove(UINT nFlags, CPoint point);的函數聲明,緊接其下輸入 view source print?1.afx_msg LRESULT OnMouseLeave(WPARA
20、M wParam, LPARAM lParam); 2.afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);然后在XPButton.cpp文件中找到ON_WM_MOUSEMOVE(),緊接其后輸入 view source print?1.ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) 2.ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)當然最后還有函數的實現了,詳細代碼可見本篇提供的源程序,這里就不再重復了。 難點二: 下面我們看看DRAWITEMSTRUCE結構為我
21、們提供了哪些有用信息呢? DRAWITEMSTRUCT結構的定義如下: view source print?01.typedef struct tagDRAWITEMSTRUCT 02. UINT CtlType; /控件類型 03.
22、0; UINT CtlID; /控件ID 04. UINT itemID; &
23、#160; /菜單項、列表框或組合框中某一項的索引值 05. UINT itemAction; /控件行為 06. UINT
24、 itemState; /控件狀態 07. HWND hwndItem;
25、/父窗口句柄或菜單句柄 08. HDC hDC; /控件對應的繪圖設備句柄 09. RECT rcItem;
26、160; /控件所占據的矩形區域 10. DWORD itemData; /列表框或組合框中某一項
27、的值 11. DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;其實不僅是按鈕控件,其它控件,如ComboBox、ListBox、StaticText等都是通過DRAWITEMSTRUCT來記錄控件信息的。關于這個結構的詳細文檔可參考本篇的附錄。 也許你早已看到許多自繪按鈕的例子,實際上自繪按鈕本身的函數結構都是差不多的,它們顯示效果的區別主要取決于代碼編寫者對GDI作圖函數的運用與掌握程度。有興趣的朋友可以研究一下CXPButton類中DrawItem函數的數據結構,其實只要修改一下其中GDI繪圖函數的部分代碼,馬上又能做出另一個自繪按鈕
28、控件了。 三、按鈕類的使用 下面演示CXPButton類的使用。往對話框中添加一個按鈕控件,假設它的ID值為IDC_BUTTON1。進入類向導(Class Wizard)的Member Variables屬性頁,為IDC_BUTTON1添加一個變量m_btnNormal。確定退出后再進行編譯,就可以看到重新定義過XP風格按鈕了。 如果你是之間把CXPButton的源文件引入自己的工程中的,那么在上圖的Variable type中是看不到CXPButton選項的。但是可以通過以下方法加入: 1. 首先保存工程后退出。 2. 在工程的目錄下找到一個后綴名為.clw的文件,將其刪除。但是
29、為了以防萬一還是建議你實現備份一下。 3. 重新打開工程,進入類向導,此時會看到一下一個彈出對話框,我們選擇“是(Yes)”。 4. 再選擇“Add All”,這樣我們就可以在類向導中使用CXPButton的變量類型了。 四、小結與提示 對于按鈕來說,當按鈕上面任何可見的部分發生變換的時候,都要調用DrawItem函數進行重繪。自繪制按鈕必須設定BS_OWNERDRAW的屬性,設置的代碼在PreSubclassWindows函數中完成。另外為了防止系統字體設置的變化影響控件的表達效果,還可以在該函數中為控件指定某種固定的字體。但是要注意的是這個 讓我們來回顧一下實現自繪按鈕的基本
30、步驟: a. 確定設計方案; b. 初始化,但是記得要在函數退出前恢復先前的GDI對象,并釋放所占領的資源; c. 添加相應消息函數; d. 添加繪圖函數DrawItem,在DrawItem中作圖的順序一般是先畫外邊框,再上底色,接著寫文字,最后是畫內邊框。不過有些人也喜歡把邊框放到最后畫,這問題不大。 五、附錄 DRAWITEMSTRUCT結構文檔(根據Msdn翻譯) DRAWITEMSTRUCT DRAWITEMSTRUCT 為需要自繪的控件或者菜單項提供了必要的信息。在需要繪制的控件或者菜單項對應的WM_DRAWITEM消息函數中得到一個指向該結構的指針。 DRAWITEMSTRUCT結
31、構的定義如下: view source print?01.typedef struct tagDRAWITEMSTRUCT 02.UINT CtlType; 03.UINT CtlID; 04.UINT itemID; 05.UINT itemAction; 06.UINT itemState; 07.HWND hwndItem; 08.HDC hDC; 09.RECT rcItem; 10.ULONG_PTR itemData; 11. DRAWITEMSTRUCT;結構成員: Ctl
32、Type 指定了控件的類型,其取值如下表所示。 取值 描述 ODT_BUTTON 按鈕控件 ODT_COMBOBOX 組合框控件 ODT_LISTBOX 列表框控件 ODT_LISTVIEW 列表視圖控件 ODT_MENU 菜單項 ODT_STATIC 靜態文本控件 ODT_TAB Tab控件 CtlID 指定了自繪控件的ID值,而對于菜單項則不需要使用該成員 itemID表示菜單項ID,也可以表示列表框或者組合框中某項的索引值。對于一個空的列表框或組合框,該成員的值為1。這時應用程序只繪制焦點矩形(該矩形的坐標由rcItem 成員給出)雖然此時控件中沒有需要顯示的項,但是繪制焦點矩形還是很有必要的,因為這樣做能夠提示用戶該控件是否具有輸入焦點。當然也可以設置itemAction 成員為合適值,使得無需繪制焦點。itemAction 指定繪制行為,其取值可以為下表中所示值的一個或者多個的聯合。取值描述ODA_DRAWENTIRE當整個控件都需要被繪制時,設置該值ODA_FOCUS如果控件需要在獲得或失去焦點時被繪制,則設置該值。此時應該檢查itemS
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 筆的制造生產過程優化與仿真技術考核試卷
- 紙板容器工廠環境噪聲治理考核試卷
- 石棉水泥制品的國內外質量標準對比考核試卷
- 外科個案護理專題分析
- 新生兒高膽紅素血癥業務查房
- 腦癱患者麻醉管理規范
- Heneicomycin-生命科學試劑-MCE
- 湖北省2025年中考第三次模擬考試道德與法治試卷(解析版)
- 房地產行業深度報告-“好房子”系列專題一:四代宅崛起政策紅利與產品創新驅動居住升級
- 2025年下半年食品飲料行業寒來暑往結構破局
- 醫務人員職業暴露防護與處置流程
- 人工智能技術在市場營銷咨詢中的應用研究-洞察闡釋
- 2025-2030中國壽險行業市場現狀供需分析及投資評估規劃分析研究報告
- 鈑金加工設備安全操作
- 國家職業技能標準-半導體分立器件和集成電路裝調工
- 醫療質量醫療安全十八項核心制度培訓課件
- 托育管理制度
- 2025年部編版語文小學四年級下冊課內閱讀專項復習題(有答案)
- ISO27001:2022信息安全管理體系全套文件+表單
- 2025年河南省洛陽市澗西區九年級中考招生一模道法試題卷(含答案)
- 2025年高考語文備考之小說精讀:凌叔華《搬家》(附習題+答案)
評論
0/150
提交評論