/************************************************************************/ /* CXPButton.h */ /************************************************************************/ #if !defined(AFX_XPBUTTON_H__44CD5B2A_756E_4939_9261_E0034E0F2DEF__INCLUDED_) #define AFX_XPBUTTON_H__44CD5B2A_756E_4939_9261_E0034E0F2DEF__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // XPButton.h : header file // / // CXPButton window class CXPButton : public CButton { // Construction public: CXPButton(); // Attributes protected: //按钮的外边框 CPen m_BoundryPen; //鼠标指针置于按钮之上时按钮的内边框 CPen m_InsideBoundryPenLeft; CPen m_InsideBoundryPenRight; CPen m_InsideBoundryPenTop; CPen m_InsideBoundryPenBottom; //按钮获得焦点时按钮的内边框 CPen m_InsideBoundryPenLeftSel; CPen m_InsideBoundryPenRightSel; CPen m_InsideBoundryPenTopSel; CPen m_InsideBoundryPenBottomSel; //按钮的底色,包括有效和无效两种状态 CBrush m_FillActive; CBrush m_FillInactive; //按钮的状态 BOOL m_bOver; //鼠标位于按钮之上时该值为true,反之为flase BOOL m_bTracking; //在鼠标按下没有释放时该值为true BOOL m_bSelected; //按钮被按下是该值为true BOOL m_bFocus; //按钮为当前焦点所在时该值为true // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CXPButton) protected: virtual void PreSubclassWindow(); //}}AFX_VIRTUAL // Implementation public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); virtual void DoGradientFill(CDC *pDC, CRect* rect); virtual void DrawInsideBorder(CDC *pDC, CRect* rect); virtual ~CXPButton(); // Generated message map functions protected: //{{AFX_MSG(CXPButton) afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam); afx_msg BOOL OnEraseBkgnd(CDC* pDC); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; / //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_XPBUTTON_H__44CD5B2A_756E_4939_9261_E0034E0F2DEF__INCLUDED_) // XPButton.cpp : implementation file // #include "stdafx.h" #include "XPButton.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif / // CXPButton CXPButton::CXPButton() { m_BoundryPen.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(55, 98, 6)); m_InsideBoundryPenLeft.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(159,175,127)); m_InsideBoundryPenRight.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(160,180,130)); m_InsideBoundryPenTop.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(161,190,143)); m_InsideBoundryPenBottom.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(140,155,0)); m_FillActive.CreateSolidBrush(RGB(236,233,216)); m_FillInactive.CreateSolidBrush(RGB(235, 234, 216)); m_InsideBoundryPenLeftSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(153, 198, 252)); 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; } CXPButton::~CXPButton() { 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(CXPButton, CButton) //{{AFX_MSG_MAP(CXPButton) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) ON_WM_ERASEBKGND() //}}AFX_MSG_MAP END_MESSAGE_MAP() / // CXPButton message handlers //添加Owner Draw属性 void CXPButton::PreSubclassWindow() { // TODO: Add your specialized code here and/or call the base class CButton::PreSubclassWindow(); ModifyStyle(0, BS_OWNERDRAW); //设置按钮的有效区域 CRgn rgn; CRect rc; GetClientRect(&rc); //有效区域为一个角半径为5的圆角矩形 rgn.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,5,5); SetWindowRgn(rgn,TRUE); rgn.DeleteObject(); } 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); } LRESULT CXPButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) { m_bOver = FALSE; m_bTracking = FALSE; InvalidateRect(NULL, FALSE); return 0; } LRESULT CXPButton::OnMouseHover(WPARAM wParam, LPARAM lParam) { m_bOver = TRUE; InvalidateRect(NULL); return 0; } void CXPButton::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); //获取按钮的状态 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))); //根据按钮的状态填充按钮的底色 CBrush* pOldBrush; if (m_bOver) { pOldBrush = pDC->SelectObject(&m_FillActive); DoGradientFill(pDC, &rect); } else { pOldBrush = pDC->SelectObject(&m_FillInactive); DoGradientFill(pDC, &rect); } //根据按钮的状态绘制内边框 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 CXPButton::DoGradientFill(CDC *pDC, CRect* rect) { CBrush brBk[64]; int nWidth = rect->Width(); int nHeight = rect->Height(); CRect rct; int i; for (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(); } //绘制按钮的内边框 void CXPButton::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); } BOOL CXPButton::OnEraseBkgnd(CDC* pDC) { //禁止绘制底色 return TRUE; }