程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 自繪按鈕的實現

自繪按鈕的實現

編輯:vc教程

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

  一、准備工作

  在開始編碼之前,首先應該確定好,更准確的說應該是設計好按鈕在各種狀態下的外觀。按鈕控件的幾中基本狀態包括:

  Normal狀態,就是按鈕一開始顯示時的樣子。

  Over狀態,鼠標指針移動到按鈕上面時按鈕顯示的樣子。

  Down狀態,按下按鈕時顯示的樣子。

  Focus狀態,按鈕按下後松開的樣子,例如標准按鈕按下松開之後會看到按鈕內部有一個虛線框。

  Disable狀態,當然就是按鈕被設置成無效的時候的樣子啦。

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

  至於Down狀態主要是在Over狀態的基礎上將文字往右下的方向稍微平移,以實現下壓的效果。

  二、實現原理及難點

  下面我們開始類的創建,在Workspace的ClassView頁中右擊列表樹的根結點,選擇New Class…

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

  按OK按鈕退出之後,我們可以在ClassView裡面看到新創建的類的名字。接下來我們可以為CXPButton類添加各種成員變量。因為自繪控件說穿了就是畫圖,所以在成員變量中可以看到各種與畫圖有關的數據類型,一般來說成員變量會在類的構造函數中初始化,在類的析構函數中銷毀。詳細代碼請參見本篇附帶的源程序。

  下面簡要敘述一下按鈕的實現原理:

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

  2. 添加WM_MOUSELEAVE消息函數,當鼠標指針離開按鈕時,觸發該消息函數,我們在函數中添加代碼,通知DrawItem函數鼠標指針已經離開了,讓按鈕重繪。

  3. 添加WM_MOUSEHOVER消息函數,當鼠標指針位於按鈕之上時,觸發該消息函數,我們在函數重添加代碼,通知DrawItem函數鼠標指針現在正在按鈕的上面,讓按鈕重繪。

  4. 添加DrawItem函數。在DrawItem中根據按鈕當前的狀態繪制按鈕的外觀。可以說自繪控件的大部分功能都是在這個函數中實現的。DrawItem函數包含了一個LPDRAWITEMSTRUCT的指針,本篇會在稍後予以講解。

  了解了基本的設計思路之後,剩下就看我們怎麼去實現了。我本人覺得這裡有兩個難點,首先是WM_MOUSELEAVE和WM_MOUSEHOVER不是標准的Windows消息函數,它們不能通過類向導來添加,所有的添加工作都需要通過手工輸入代碼來完成。另一個難點是DrawItem中的LPDRAWITEMSTRUCT指針,它指向了一個DRAWITEMSTRUCT的結構,這個結構中包含了控件的各種細節,為我們提供了實現自繪功能的必要信息。

  難點一:

  事實上WM_MOUSELEAVE和WM_MOUSEHOVER兩個Windows消息是通過WM_MOUSEMOVE消息觸發的,而WM_MOUSEMOVE是標准的Windows消息,因此我們可以通過類向導來為CXPButton類添加WM_MOUSEMOVE消息函數。

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

  

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消息消息函數。在CXPButton類的聲明中(即在XPButton.h文件中)找到afx_msg void OnMouseMove(UINT nFlags, CPoint point);的函數聲明,緊接其下輸入

本文示例代碼或素材下載

  • 首頁
  • 上一頁
  • 1
  • 2
  • 下一頁
  • 尾頁
  • 共2頁
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved