本文使用vc6.0 MFC程式實現自訂的多狀態button。vc9.0(即vs2008)下,去掉stdafx.h檔案中的#define _WIN32_WINNT 0x0400 也可以運行(有個warning)。
由於只是樣本,並沒有注意介面,您可以自己改;自己的美工水平不行,您可以自己更改bitmap資源。
介紹了三種多狀態按鈕 :
1)三狀態按鈕
滑鼠在button上;滑鼠在button外;滑鼠按下button
2)六狀態按鈕
在1)的基礎上增加了對應的獲得焦點的三種情況
3)MFC內建的CBitmapButton類
有四種狀態:up,down,focus,disabled。控制項風格不同,狀態個數不同,具體可看msdn。
代碼可到此處下載:
http://download.csdn.net/source/986965
(一)三狀態按鈕
1)定義繼承自CButton的子類CyctBitmapButton。
2)三狀態需要三個位元影像資源
裝在和卸載位元影像資源:
int CyctBitmapButton::Init()<br />{<br />//(視窗建立後的)初始化</p><p>m_hIn = ::LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BITMAP_IN));<br />m_hOut = ::LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BITMAP_OUT));<br />m_hDown = ::LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BITMAP_DOWN));</p><p>ASSERT(m_hIn != NULL);<br />ASSERT(m_hOut != NULL);<br />ASSERT(m_hDown != NULL);</p><p>//SetButtonStyle( BS_BITMAP | GetButtonStyle() );<br />ModifyStyle(0,BS_BITMAP);//增加BS_BITMAP風格<br />SetBitmap(m_hOut);</p><p>return 0;<br />}</p><p>void CyctBitmapButton::OnDestroy()<br />{<br />CButton::OnDestroy();</p><p>//卸載Bitmap資源<br />#ifdef _DEBUG<br />ASSERT(0 != DeleteObject(m_hIn));<br />ASSERT(0 != DeleteObject(m_hOut));<br />ASSERT(0 != DeleteObject(m_hDown));<br />#else<br />DeleteObject(m_hIn);<br />DeleteObject(m_hOut);<br />DeleteObject(m_hPutdown);<br />#endif<br />}
3)初始化button
視窗初始化後需要調用Init()函數。布爾值變數m_fIsInit確保button只初始化一次。
void CyctBitmapButton::PreSubclassWindow()<br />{<br />//初始化<br />if(!m_fIsInit)<br />{<br />//AfxMessageBox(_T("CyctBitmapButton::PreSubclassWindow"));<br />Init();<br />m_fIsInit = TRUE;<br />}</p><p>CButton::PreSubclassWindow();<br />}</p><p>int CyctBitmapButton::OnCreate(LPCREATESTRUCT lpCreateStruct)<br />{<br />if (CButton::OnCreate(lpCreateStruct) == -1)<br />return -1;</p><p>//初始化<br />if(!m_fIsInit)<br />{<br />//AfxMessageBox(_T("CyctBitmapButton::OnCreate"));<br />Init();<br />m_fIsInit = TRUE;<br />}<br />return 0;<br />}
4)處理滑鼠響應函數(這是關鍵的)
處理了四種滑鼠訊息WM_MOUSEMOVE,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_MOUSELEAVE:
void CyctBitmapButton::OnMouseMove(UINT nFlags, CPoint point)<br />{<br />if(m_MouseState.GetCurState() == _mouse_out)<br />{<br />SetBitmap(m_hIn);<br />return;<br />}</p><p>//當滑鼠離開時觸發WM_MOUSELEAVE事件<br />TRACKMOUSEEVENT tme;<br /> tme.cbSize = sizeof(tme);<br /> tme.dwFlags = TME_LEAVE;<br /> tme.hwndTrack = m_hWnd;<br /> tme.dwHoverTime = HOVER_DEFAULT;<br /> ::TrackMouseEvent(&tme);</p><p>CButton::OnMouseMove(nFlags, point);<br />}</p><p>void CyctBitmapButton::OnLButtonDown(UINT nFlags, CPoint point)<br />{<br />SetBitmap(m_hDown);</p><p>CButton::OnLButtonDown(nFlags, point);<br />}</p><p>void CyctBitmapButton::OnLButtonUp(UINT nFlags, CPoint point)<br />{<br />SetBitmap(m_hIn);</p><p>CButton::OnLButtonUp(nFlags, point);<br />}</p><p>LRESULT CyctBitmapButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)<br />{<br />SetBitmap(m_hOut);</p><p>return 0;<br />}
其中WM_MOUSELEAVE訊息響應映射是手工添加的。
在標頭檔中DECLARE_MESSAGE_MAP()前添加一句:
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);//手工添加
在對應的cpp檔案中BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間添加一句:
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)//手工添加
WM_MOUSELEAVE訊息是由函數TrackMouseEvent產生的,當滑鼠離開button控制項就會觸發此訊息。
函數SetBitmap定義如下(具體的看原始碼吧):
HBITMAP CyctBitmapButton::SetBitmap(HBITMAP hBitmap)<br />{<br />//設定按鈕的位元影像</p><p>ASSERT(m_hIn == hBitmap || m_hOut == hBitmap || m_hDown == hBitmap);<br />if(m_hIn == hBitmap)<br />m_MouseState.SetCurState( _mouse_in );<br />else if(m_hOut == hBitmap)<br />m_MouseState.SetCurState(_mouse_out );<br />else if(m_hDown == hBitmap)<br />m_MouseState.SetCurState( _mouse_down );</p><p>return CButton::SetBitmap(hBitmap);<br />}
5)如果想去掉按鈕button在獲得焦點時的虛框,重載WM_SETFOCUS訊息,並且置函數體為空白即可。
(二)六狀態按鈕
與(一)類似,不再敘述。
(三)MFC內建的CBitmapButton類
使用很簡單,在對話方塊類的OnInitDialog內裝載四個位元影像資源即可:
//初始化CBitmapButton<br />m_BitmapButton.LoadBitmaps(IDB_BITMAP_UP,IDB_BITMAP_DOWN2<br />,IDB_BITMAP_FOCUS,IDB_BITMAP_DISABLED);
總結:多狀態按鈕主要是使用函數TrackMouseEvent函數實現的。本文只是樣本,很簡陋。你也可以下載CButtonST來看看,方法基本一樣。下載區有:
http://search.download.csdn.net/search/cbuttonst