MFC編程中系統(tǒng)提供的一些樣式,一般都比較難看,所以有的時候為了美觀,需要自己定義些樣式,現(xiàn)那Button按鈕來舉例. 首先新建一名為XPButton的MFC Application的對話框應用程序,在Class View中新增加一個自定義樣式的MFC Class類,類名為CNewButton,基類為CButton. NewButton.h的代碼如下: class CNewButton : public CButton { public: CNewButton(); protected: CPen m_BoundryPen; //按鈕的外邊框 //鼠標指針置于按鈕之上時按鈕的內(nèi)邊框 CPen m_InsideBoundryPenLeft; CPen m_InsideBoundryPenRight; CPen m_InsideBoundryPenTop; CPen m_InsideBoundryPenBottom; //按鈕獲得焦點時按鈕的內(nèi)邊框 CPen m_InsideBoundryPenLeftSel; CPen m_InsideBoundryPenRightSel; CPen m_InsideBoundryPenTopSel; CPen m_InsideBoundryPenBottomSel; //按鈕的底色,包括有效和無效兩種狀態(tài) CBrush m_FillActive; CBrush m_FillInactive; //按鈕的狀態(tài) BOOL m_bOver; //鼠標位于按鈕之上時該值為true,反之為flase BOOL m_bTracking; //在鼠標按下沒有釋放時該值為true BOOL m_bSelected; //按鈕被按下是該值為true BOOL m_bFocus; //按鈕為當前焦點所在時該值為true public: protected: virtual voidPreSubclassWindow(); public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); virtual void DoGradientFill(CDC *pDC, CRect* rect); virtual void DrawInsideBorder(CDC *pDC, CRect* rect); virtual ~CNewButton(); protected: afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() }; NewButton.cpp的代碼如下: #include "stdafx.h" #include "NewButton.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CNewButton::CNewButton() //構造函數(shù) { m_BoundryPen.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0, 0, 0));//按鈕的外邊框畫筆 m_InsideBoundryPenLeft.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(61, 97, 88)); m_InsideBoundryPenRight.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(61, 137, 106)); m_InsideBoundryPenTop.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(102, 167, 114)); m_InsideBoundryPenBottom.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(102, 167, 114)); //按鈕的背景色 m_FillActive.CreateSolidBrush(RGB(223, 222, 236)); m_FillInactive.CreateSolidBrush(RGB(222, 223, 236)); m_InsideBoundryPenLeftSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(139, 189, 157)); m_InsideBoundryPenTopSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255)); m_InsideBoundryPenRightSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(162, 189, 252)); m_InsideBoundryPenBottomSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255)); m_bOver = m_bSelected = m_bTracking = m_bFocus = FALSE; } CNewButton::~CNewButton() { m_BoundryPen.DeleteObject(); m_InsideBoundryPenLeft.DeleteObject(); m_InsideBoundryPenRight.DeleteObject(); m_InsideBoundryPenTop.DeleteObject(); m_InsideBoundryPenBottom.DeleteObject(); m_FillActive.DeleteObject(); m_FillInactive.DeleteObject(); m_InsideBoundryPenLeftSel.DeleteObject(); m_InsideBoundryPenTopSel.DeleteObject(); m_InsideBoundryPenRightSel.DeleteObject(); m_InsideBoundryPenBottomSel.DeleteObject(); } BEGIN_MESSAGE_MAP(CNewButton, CButton) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) END_MESSAGE_MAP() //添加Owner Draw屬性 void CNewButton::PreSubclassWindow() { CButton::PreSubclassWindow(); ModifyStyle(0, BS_OWNERDRAW); } void CNewButton::OnMouseMove(UINT nFlags, CPoint point) { 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); } LRESULT CNewButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) { m_bOver = FALSE; m_bTracking = FALSE; InvalidateRect(NULL, FALSE); return 0; } LRESULT CNewButton::OnMouseHover(WPARAM wParam, LPARAM lParam) { m_bOver = TRUE; InvalidateRect(NULL); return 0; } void CNewButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { //從lpDrawItemStruct獲取控件的相關信息 CRect rect = lpDrawItemStruct->rcItem; CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC); int nSaveDC=pDC->SaveDC(); UINT state = lpDrawItemStruct->itemState; POINT pt ; TCHAR strText[MAX_PATH + 1]; ::GetWindowText(m_hWnd, strText, MAX_PATH); //畫按鈕的外邊框,它是一個半徑為5的圓角矩形 pt.x =5; pt.y =5; CPen* hOldPen = pDC->SelectObject(&m_BoundryPen); pDC->RoundRect(&rect, pt); //獲取按鈕的狀態(tài) if (state & ODS_FOCUS) { m_bFocus = TRUE; m_bSelected = TRUE; } else { m_bFocus = FALSE; m_bSelected = FALSE; } if (state & ODS_SELECTED || state & ODS_DEFAULT) { m_bFocus = TRUE; } pDC->SelectObject(hOldPen); rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE))); //根據(jù)按鈕的狀態(tài)填充按鈕的底色 CBrush* pOldBrush; if (m_bOver) { pOldBrush = pDC->SelectObject(&m_FillActive); DoGradientFill(pDC, &rect); } else { pOldBrush = pDC->SelectObject(&m_FillInactive); DoGradientFill(pDC, &rect); } //根據(jù)按鈕的狀態(tài)繪制內(nèi)邊框 if (m_bOver || m_bSelected) DrawInsideBorder(pDC, &rect); pDC->SelectObject(pOldBrush); //顯示按鈕的文本 if (strText!=NULL) { CFont* hFont = GetFont(); CFont* hOldFont = pDC->SelectObject(hFont); CSize szExtent = pDC->GetTextExtent(strText, lstrlen(strText)); CPoint pt( rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2); if (state & ODS_SELECTED) pt.Offset(1, 1); int nMode = pDC->SetBkMode(TRANSPARENT); if (state & ODS_DISABLED) pDC->DrawState(pt, szExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL); else pDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL); pDC->SelectObject(hOldFont); pDC->SetBkMode(nMode); } pDC->RestoreDC(nSaveDC); } //繪制按鈕的底色 void CNewButton::DoGradientFill(CDC *pDC, CRect* rect) { CBrush brBk[64]; int nWidth = rect->Width(); int nHeight = rect->Height(); CRect rct; for (int i = 0; i < 64; i ++) { if (m_bOver) { if (m_bFocus) brBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 3))); else brBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 5))); } else { if (m_bFocus) brBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 4))); else brBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 5))); } } for (i = rect->top; i <= nHeight + 2; i ++) { rct.SetRect(rect->left, i, nWidth + 2, i + 1); pDC->FillRect(&rct, &brBk[((i * 63) / nHeight)]); } for (i = 0; i < 64; i ++) brBk[i].DeleteObject(); } //繪制按鈕的內(nèi)邊框 void CNewButton::DrawInsideBorder(CDC *pDC, CRect* rect) { CPen *pLeft, *pRight, *pTop, *pBottom; if (m_bSelected && !m_bOver) { pLeft = & m_InsideBoundryPenLeftSel; pRight = &m_InsideBoundryPenRightSel; pTop = &m_InsideBoundryPenTopSel; pBottom = &m_InsideBoundryPenBottomSel; } else { pLeft = &m_InsideBoundryPenLeft; pRight = &m_InsideBoundryPenRight; pTop = &m_InsideBoundryPenTop; pBottom = &m_InsideBoundryPenBottom; } CPoint oldPoint = pDC->MoveTo(rect->left, rect->bottom - 1); CPen* pOldPen = pDC->SelectObject(pLeft); pDC->LineTo(rect->left, rect->top + 1); pDC->SelectObject(pRight); pDC->MoveTo(rect->right - 1, rect->bottom - 1); pDC->LineTo(rect->right - 1, rect->top); pDC->SelectObject(pTop); pDC->MoveTo(rect->left - 1, rect->top); pDC->LineTo(rect->right - 1, rect->top); pDC->SelectObject(pBottom); pDC->MoveTo(rect->left, rect->bottom); pDC->LineTo(rect->right - 1, rect->bottom); pDC->SelectObject(pOldPen); pDC->MoveTo(oldPoint); if (m_bSelected && !m_bOver) DrawFocusRect(pDC->m_hDC,rect); } 3.設置某個按鈕為上面所定義的樣式,只需右鍵點擊該按鈕,添加變量,變量的類型CNewButton,變量名為m_Button.編譯運行,就可以看到自己定義的按鈕.
|
|