XpButton.h
#pragma once // CXpButton class CXpButton : public CButton { DECLARE_DYNAMIC(CXpButton) public: CXpButton(); virtual ~CXpButton(); protected: virtual void PreSubclassWindow(); virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); DECLARE_MESSAGE_MAP() 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); public: virtual void DoGradientFill(CDC *pDC, CRect* rect); virtual void DrawInsideBorder(CDC *pDC, CRect* rect); protected: //按钮的外边框 CPen m_penBoundry; //鼠标指针置于按钮之上时按钮的内边框 CPen m_penInsideBoundryLeft; CPen m_penInsideBoundryRight; CPen m_penInsideBoundryTop; CPen m_penInsideBoundryBottom; //按钮获得焦点时按钮的内边框 CPen m_penInsideBoundryLeftSel; CPen m_penInsideBoundryRightSel; CPen m_penInsideBoundryTopSel; CPen m_penInsideBoundryBottomSel; //按钮的底色,包括有效和无效两种状态 CBrush m_brActive; CBrush m_brInactive; //按钮状态 BOOL m_bOver; //鼠标位于按钮之上时该值为true,反之为flase BOOL m_bTracking; //在鼠标按下没有释放时该值为true BOOL m_bSelected; //按钮被按下是该值为true BOOL m_bFocus; //按钮为当前焦点所在时该值为true };
XpButton.cpp
// XpButton.cpp : implementation file // #include "stdafx.h" #include "XpBtn.h" #include "XpButton.h" // CXpButton IMPLEMENT_DYNAMIC(CXpButton, CButton) CXpButton::CXpButton() { //按钮的外边框 m_penBoundry.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0, 0, 0)); //鼠标指针置于按钮之上时按钮的内边框 m_penInsideBoundryLeft.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(250, 196, 88)); m_penInsideBoundryRight.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(251, 202, 106)); m_penInsideBoundryTop.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(252, 210, 121)); m_penInsideBoundryBottom.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(229, 151, 0)); //按钮获得焦点时按钮的内边框 m_penInsideBoundryLeftSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(153, 198, 252)); m_penInsideBoundryRightSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(162, 189, 252)); m_penInsideBoundryTopSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255)); m_penInsideBoundryBottomSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255)); //按钮的底色,包括有效和无效两种状态 m_brActive.CreateSolidBrush(RGB(223, 222, 236)); m_brInactive.CreateSolidBrush(RGB(222, 223, 236)); m_bOver = FALSE; //鼠标位于按钮之上时该值为true,反之为flase m_bTracking = FALSE; //在鼠标按下没有释放时该值为true m_bSelected = FALSE; //按钮被按下是该值为true m_bFocus = FALSE; //按钮为当前焦点所在时该值为true } CXpButton::~CXpButton() { //按钮的外边框 m_penBoundry.DeleteObject(); //鼠标指针置于按钮之上时按钮的内边框 m_penInsideBoundryLeft.DeleteObject(); m_penInsideBoundryRight.DeleteObject(); m_penInsideBoundryTop.DeleteObject(); m_penInsideBoundryBottom.DeleteObject(); //按钮获得焦点时按钮的内边框 m_penInsideBoundryLeftSel.DeleteObject(); m_penInsideBoundryRightSel.DeleteObject(); m_penInsideBoundryTopSel.DeleteObject(); m_penInsideBoundryBottomSel.DeleteObject(); //按钮的底色,包括有效和无效两种状态 m_brActive.DeleteObject(); m_brInactive.DeleteObject(); } BEGIN_MESSAGE_MAP(CXpButton, CButton) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) END_MESSAGE_MAP() // CXpButton message handlers void CXpButton::PreSubclassWindow() { __super::PreSubclassWindow(); ModifyStyle(0, BS_OWNERDRAW); } void CXpButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { //从lpDrawItemStruct获取控件的相关信息 CRect rect = lpDrawItemStruct->rcItem; CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); int nSaveDc = pDC->SaveDC(); UINT uState = lpDrawItemStruct->itemState; POINT pt; char szText[MAX_PATH + 1] = {0}; ::GetWindowText(m_hWnd, szText, MAX_PATH); //画按钮的外边框,它是一个半径为5的圆角矩形 pt.x = 5; pt.y = 5; CPen* pPenOld = pDC->SelectObject(&m_penBoundry); pDC->RoundRect(&rect, pt); //获取按钮的状态 if (ODS_FOCUS & uState) { m_bFocus = TRUE; m_bSelected = TRUE; } else { m_bFocus = FALSE; m_bSelected = FALSE; } if (uState & ODS_SELECTED || uState & ODS_DEFAULT) { m_bFocus = TRUE; } pDC->SelectObject(pPenOld); rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE))); //根据按钮的状态填充按钮的底色 CBrush* pBrushOld = NULL; if (m_bOver) { pBrushOld = pDC->SelectObject(&m_brActive); DoGradientFill(pDC, &rect); } else { pBrushOld = pDC->SelectObject(&m_brInactive); DoGradientFill(pDC, &rect); } //根据按钮的状态绘制内边框 if (m_bOver || m_bSelected) { DrawInsideBorder(pDC, &rect); } if (NULL != szText) { CFont* pFont = GetFont(); CFont* pFontOld = pDC->SelectObject(pFont); CSize szExtent = pDC->GetTextExtent(szText, strlen(szText)); CPoint pt(rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2); if (ODS_SELECTED & uState) { pt.Offset(1, 1); } int nMode = pDC->SetBkMode(TRANSPARENT); if (ODS_DISABLED & uState) { pDC->DrawState(pt, szExtent, szText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL); } else { pDC->DrawState(pt, szExtent, szText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL); } pDC->SelectObject(pFontOld); pDC->SetBkMode(nMode); } pDC->RestoreDC(nSaveDc); } void CXpButton::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); } __super::OnMouseMove(nFlags, point); } LRESULT CXpButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) { m_bOver = FALSE; m_bTracking = FALSE; InvalidateRect(NULL, FALSE); return S_OK; } LRESULT CXpButton::OnMouseHover(WPARAM wParam, LPARAM lParam) { m_bOver = TRUE; InvalidateRect(NULL, TRUE); return S_OK; } void CXpButton::DoGradientFill(CDC *pDC, CRect* rect) { CBrush brArrBk[64]; int nWidth = rect->Width(); int nHeight = rect->Height(); CRect rct; int i = 0; for (i = 0; i < 64; i++) { if (m_bOver) { if (m_bFocus) { brArrBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 3))); } else { brArrBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 5))); } } else { if (m_bFocus) { brArrBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 4))); } else { brArrBk[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, &brArrBk[i * 63 / nHeight]); } for (i = 0; i < 64; i++) { brArrBk[i].DeleteObject(); } } void CXpButton::DrawInsideBorder(CDC *pDC, CRect* rect) { CPen* pPenLeft = NULL; CPen* pPenRight = NULL; CPen* pPenTop = NULL; CPen* pPenBottom = NULL; if (m_bSelected && !m_bOver) { pPenLeft = &m_penInsideBoundryLeftSel; pPenRight = &m_penInsideBoundryRightSel; pPenTop = &m_penInsideBoundryTopSel; pPenBottom = &m_penInsideBoundryBottomSel; } else { pPenLeft = &m_penInsideBoundryLeft; pPenRight = &m_penInsideBoundryRight; pPenTop = &m_penInsideBoundryTop; pPenBottom = &m_penInsideBoundryBottom; } CPoint ptOld = pDC->MoveTo(rect->left, rect->bottom - 1); CPen* pPenOld = pDC->SelectObject(pPenLeft); pDC->LineTo(rect->left, rect->top + 1); pDC->SelectObject(pPenRight); pDC->MoveTo(rect->right - 1, rect->bottom - 1); pDC->LineTo(rect->right - 1, rect->top); pDC->SelectObject(pPenTop); pDC->MoveTo(rect->left - 1, rect->top); pDC->LineTo(rect->right - 1, rect->top); pDC->SelectObject(pPenBottom); pDC->MoveTo(rect->left, rect->bottom); pDC->LineTo(rect->right - 1, rect->bottom); pDC->SelectObject(pPenOld); pDC->MoveTo(ptOld); if (m_bSelected && !m_bOver) { DrawFocusRect(pDC->m_hDC, rect); } }