// CMybutton.cpp : implementation file // #include "stdafx.h" #include "Mybutton.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMybutton CMybutton::CMybutton() { m_nColor = GetSysColor(COLOR_BTNFACE); m_sColor = m_nColor; m_hColor = m_nColor; m_dColor = m_nColor; m_nBorder = 1; m_pNormal = NULL; m_pSelected = NULL; m_pHover = NULL; m_pDisabled = NULL; m_hRgn = 0; m_bHover = false; m_bCapture = false; m_bMouseDown = false; m_bNeedBitmaps = true; } CMybutton::~CMybutton() { delete m_pNormal; delete m_pSelected; delete m_pHover; delete m_pDisabled; DeleteObject(m_hRgn); } BEGIN_MESSAGE_MAP(CMybutton, CButton) //{{AFX_MSG_MAP(CMybutton) ON_WM_ERASEBKGND() ON_WM_MOUSEMOVE() ON_WM_CREATE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMybutton message handlers BOOL CMybutton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID) { // store region in member variable DeleteObject(m_hRgn); m_hRgn = CreateRectRgn(0, 0, 31, 31); CRect box(0, 0, 0, 0); if (m_hRgn != 0) CombineRgn(m_hRgn, hRgn, 0, RGN_COPY); // make sure that region bounding rect is located in (0, 0) GetRgnBox(m_hRgn, &box); OffsetRgn(m_hRgn, -box.left, -box.top); GetRgnBox(m_hRgn, &box); // update position of region center for caption output m_CenterPoint = CPoint(box.left + box.Width() /2 , box.top + box.Height() /2); box.OffsetRect(point); return CButton::Create(lpszCaption, dwStyle, box, pParentWnd, nID); } BOOL CMybutton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID, COLORREF color) { m_sColor = color; m_hColor = color; // call another constructor return Create(lpszCaption, dwStyle, point, hRgn, pParentWnd, nID); } BOOL CMybutton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID, UINT nBorder, COLORREF nColor, COLORREF sColor, COLORREF hColor, COLORREF dColor) { // change default colors m_nBorder = nBorder; m_nColor = nColor; m_sColor = sColor; m_hColor = hColor; m_dColor = hColor; // call another constructor return Create(lpszCaption, dwStyle, point, hRgn, pParentWnd, nID); } void CMybutton::PreSubclassWindow() { // change window style to allow owner draw ModifyStyle(0, BS_OWNERDRAW | BS_PUSHBUTTON); CButton::PreSubclassWindow(); } int CMybutton::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CButton::OnCreate(lpCreateStruct) == -1) return -1; // assign new region to a window m_bNeedBitmaps = true; SetWindowRgn(m_hRgn, true); return 0; } void CMybutton::OnLButtonDown(UINT nFlags, CPoint point) { // record that mouse is down m_bMouseDown = true; if (!m_bCapture) { SetCapture(); m_bCapture = true; } CButton::OnLButtonDown(nFlags, point); } void CMybutton::OnLButtonUp(UINT nFlags, CPoint point) { // 标识鼠标已抬起 CButton::OnLButtonUp(nFlags, point); m_bMouseDown = false; if (m_bCapture) { ReleaseCapture(); m_bCapture = false; } CheckHover(point); } void CMybutton::OnMouseMove(UINT nFlags, CPoint point) { // Test if mouse is above the button. if (!m_bMouseDown) CheckHover(point); CButton::OnMouseMove(nFlags, point); } void CMybutton::CheckHover(CPoint point) { if (HitTest(point)) { if (!m_bCapture) { SetCapture(); m_bCapture = true; } if (!m_bHover) { m_bHover = true; RedrawWindow(); } } else { if (m_bCapture) { ReleaseCapture(); m_bCapture = false; } m_bHover = false; RedrawWindow(); } } BOOL CMybutton::HitTest(CPoint point) { BOOL result = false; // Obtain handle to window region. HRGN hRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hRgn); CRect rgnRect; GetRgnBox(hRgn, &rgnRect); // First check if point is in region bounding rect. // Then check if point is in the region in adition to being in the bouding rect. result = PtInRect(&rgnRect, point)&& PtInRegion(hRgn, point.x, point.y); // Clean up and exit. DeleteObject(hRgn); return result; } BOOL CMybutton::OnEraseBkgnd(CDC* pDC) { // do not erase background return 1; } //////////////////////// DRAWING ROUTINES //////////////////////////// void CMybutton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // prepare DC CDC* pDC = CDC::FromHandle(lpDrawItemStruct -> hDC); CRect rect; GetClientRect(rect); // prepare bitmaps they need to be prepared if (m_bNeedBitmaps) PrepareStateBitmaps(pDC, &rect); // draw button to the screen DrawButton(pDC, &rect, lpDrawItemStruct -> itemState); } void CMybutton::PrepareStateBitmaps(CDC * pDC, CRect * pRect) { // 准备DC CDC * pMemDC; pMemDC = new CDC; pMemDC -> CreateCompatibleDC(pDC); //为按钮的各种状态准备位图 PrepareNormalState(pDC, pMemDC, pRect); PrepareSelectedState(pDC, pMemDC, pRect); PrepareHoverState(pDC, pMemDC, pRect); PrepareDisabledState(pDC, pMemDC, pRect); // 释放资源 delete pMemDC; m_bNeedBitmaps = false; } void CMybutton::PrepareNormalState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_NORMAL state bitmap delete m_pNormal; m_pNormal = new CBitmap; PaintRgn(pDC, pMemDC, m_pNormal, m_nColor, pRect, true, false); } void CMybutton::PrepareSelectedState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_SELECTED state bitmap delete m_pSelected; m_pSelected = new CBitmap; PaintRgn(pDC, pMemDC, m_pSelected, m_sColor, pRect, true, true); } void CMybutton::PrepareHoverState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_HOVER state bitmap delete m_pHover; m_pHover = new CBitmap; PaintRgn(pDC, pMemDC, m_pHover, m_hColor, pRect, true, false); } void CMybutton::PrepareDisabledState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_DISABLED state bitmap delete m_pDisabled; m_pDisabled = new CBitmap; PaintRgn(pDC, pMemDC, m_pDisabled, m_dColor, pRect, false, false); } void CMybutton::PaintRgn(CDC * pDC, CDC * pMemDC, CBitmap * pBitmap, COLORREF color, CRect * pRect, BOOL bEnabled, BOOL bSunken) { // c创建位图 pBitmap -> CreateCompatibleBitmap(pDC, pRect -> Width(), pRect -> Height()); CBitmap * pOldBitmap = pMemDC -> SelectObject(pBitmap); // 准备路径 HRGN hRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hRgn); // 用传进来的颜色填充按钮路径区域 HBRUSH hBrush = CreateSolidBrush(color); pMemDC -> FillSolidRect(pRect, RGB(0, 0, 0)); FillRgn(pMemDC -> GetSafeHdc(), hRgn, hBrush); DeleteObject(hBrush); // 绘制按钮标题及3D边框 DrawButtonCaption(pMemDC -> GetSafeHdc(), pRect, bEnabled, bSunken); FrameRgn3D(pMemDC -> GetSafeHdc(), hRgn, bSunken); // 释放资源 DeleteObject(hRgn); pMemDC -> SelectObject(pOldBitmap); } void CMybutton::DrawButtonCaption(HDC hDC, CRect * pRect, BOOL bEnabled, BOOL bSunken) { //选择父窗体的字体 int nOldMode = SetBkMode(hDC, TRANSPARENT); CString text; GetWindowText(text); LOGFONT lf; GetParent() -> GetFont() -> GetLogFont(&lf); HFONT hFont = CreateFontIndirect(&lf); HFONT hOldFont = (HFONT) SelectObject(hDC, hFont); // 计算表条输出的位置 TEXTMETRIC tm; GetTextMetrics(hDC, &tm); CPoint p = CPoint(m_CenterPoint.x, m_CenterPoint.y + tm.tmHeight/ 2); if (bSunken) p.Offset(m_nBorder, m_nBorder); //根据按钮的状态绘制按钮标题 if (bEnabled ) { if(m_bHover || m_bCapture) { SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT)); SetTextAlign(hDC, TA_CENTER | TA_BOTTOM); TextOut(hDC, p.x, p.y, text, text.GetLength()); } else { SetTextColor(hDC, GetSysColor(COLOR_3DHILIGHT)); SetTextAlign(hDC, TA_CENTER | TA_BOTTOM); TextOut(hDC, p.x, p.y, text, text.GetLength()); } } else { SetTextColor(hDC, GetSysColor(COLOR_3DHILIGHT)); TextOut(hDC, p.x + 1, p.y + 1, text, text.GetLength()); SetTextColor(hDC, GetSysColor(COLOR_3DSHADOW)); TextOut(hDC, p.x, p.y, text, text.GetLength()); } SelectObject(hDC, hOldFont); DeleteObject(hFont); SetBkMode(hDC, nOldMode); } void CMybutton::FrameRgn3D(HDC hDC, const HRGN hRgn, BOOL bSunken) { // we need two differenr regions to keep base region and border region HBRUSH hBrush; HRGN hBaseRgn = CreateRectRgn(0, 0, 0, 0); COLORREF ltOuter; //左上外侧边框的颜色 COLORREF ltInner; //左上内存边框的颜色 COLORREF rbOuter; //右下外侧边框的颜色 COLORREF rbInner; //右下内侧边框的颜色 //边框颜色配置 if (!bSunken) { ltOuter = GetSysColor(COLOR_3DLIGHT); ltInner = GetSysColor(COLOR_3DHILIGHT); rbOuter = GetSysColor(COLOR_3DDKSHADOW); rbInner = GetSysColor(COLOR_3DSHADOW); } else { rbInner = GetSysColor(COLOR_3DLIGHT); rbOuter = GetSysColor(COLOR_3DHILIGHT); ltInner = GetSysColor(COLOR_3DDKSHADOW); ltOuter = GetSysColor(COLOR_3DSHADOW); } // 移动3D边框,将其与基本区域分离 switch (m_nBorder) { case 2: CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, 2, 2); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(ltInner); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, -2, -2); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(rbInner); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, 1, 1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(ltOuter); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, -1, -1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(rbOuter); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); break; default: CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, 1, 1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(ltInner); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, -1, -1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(rbOuter); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); break; } //释放资源 DeleteObject(hBaseRgn); } void CMybutton::DrawButton(CDC * pDC, CRect * pRect, UINT state) { // 创建内存设备 CDC * pMemDC = new CDC; pMemDC -> CreateCompatibleDC(pDC); CBitmap * pOldBitmap; //获取按钮路径 HRGN hRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hRgn); //根据按钮状态为按钮选择状态位图 if (state & ODS_DISABLED) pOldBitmap = pMemDC -> SelectObject(m_pDisabled); else { if (state & ODS_SELECTED) pOldBitmap = pMemDC -> SelectObject(m_pSelected); else { if (m_bHover) pOldBitmap = pMemDC -> SelectObject(m_pHover); else pOldBitmap = pMemDC -> SelectObject(m_pNormal); } } //绘制按钮的裁剪区域 ::SelectClipRgn(pDC -> GetSafeHdc(), hRgn); pDC -> BitBlt(0, 0, pRect -> Width(), pRect -> Height(), pMemDC, 0, 0, SRCCOPY); ::SelectClipRgn(pDC -> GetSafeHdc(), NULL); //释放资源 DeleteObject(hRgn); pMemDC -> SelectObject(pOldBitmap); delete pMemDC; }