XP风格Button源代码

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);
	}
}
 

你可能感兴趣的:(XP)