首先来看MFC里面的CButton类源码。如果需要按钮跟界面能很好的匹配的话,一种方法就是设置CButton类的函数参数,另一种方法就是仿照CButton类设计一个新的类,实现Button的自绘。
CButton类源码如下:
class CButton : public CWnd { DECLARE_DYNAMIC(CButton) // Constructors public: CButton(); virtual BOOL Create(LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); // Attributes UINT GetState() const; void SetState(BOOL bHighlight); int GetCheck() const; void SetCheck(int nCheck); UINT GetButtonStyle() const; void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE); HICON SetIcon(HICON hIcon); HICON GetIcon() const; HBITMAP SetBitmap(HBITMAP hBitmap); HBITMAP GetBitmap() const; HCURSOR SetCursor(HCURSOR hCursor); HCURSOR GetCursor(); #if (_WIN32_WINNT >= 0x501) AFX_ANSI_DEPRECATED BOOL GetIdealSize(_Out_ LPSIZE psize) const; AFX_ANSI_DEPRECATED BOOL SetImageList(_In_ PBUTTON_IMAGELIST pbuttonImagelist); AFX_ANSI_DEPRECATED BOOL GetImageList(_In_ PBUTTON_IMAGELIST pbuttonImagelist) const; AFX_ANSI_DEPRECATED BOOL SetTextMargin(_In_ LPRECT pmargin); AFX_ANSI_DEPRECATED BOOL GetTextMargin(_Out_ LPRECT pmargin) const; #endif // (_WIN32_WINNT >= 0x501) #if ( _WIN32_WINNT >= 0x0600 ) && defined(UNICODE) CString GetNote() const; _Check_return_ BOOL GetNote(_Out_z_cap_(*pcchNote) LPTSTR lpszNote, _Inout_ UINT* pcchNote) const; BOOL SetNote(_In_z_ LPCTSTR lpszNote); UINT GetNoteLength() const; BOOL GetSplitInfo(_Out_ PBUTTON_SPLITINFO pInfo) const; BOOL SetSplitInfo(_In_ PBUTTON_SPLITINFO pInfo); UINT GetSplitStyle() const; BOOL SetSplitStyle(_In_ UINT nStyle); BOOL GetSplitSize(_Out_ LPSIZE pSize) const; BOOL SetSplitSize(_In_ LPSIZE pSize); CImageList* GetSplitImageList() const; BOOL SetSplitImageList(_In_ CImageList* pSplitImageList); TCHAR GetSplitGlyph() const; BOOL SetSplitGlyph(_In_ TCHAR chGlyph); BOOL SetDropDownState(_In_ BOOL fDropDown); // Sets whether the action associated with the button requires elevated permissions. // If elevated permissions are required then the button should display an elevated icon. HICON SetShield(_In_ BOOL fElevationRequired); #endif // ( _WIN32_WINNT >= 0x600 ) && defined(UNICODE) // Overridables (for owner draw only) virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); // Implementation public: virtual ~CButton(); protected: virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*); };
自绘VincentButton类如下:
#ifndef _VINCENT_BUTTON_H_ #define _VINCENT_BUTTON_H_ class VincentButton : public CButton { public: VincentButton(); virtual ~VincentButton(); // 填充按钮中间部分的渐变色 virtual void GradientFill(CDC *pDC, CRect* rect); // 绘制边框 virtual void DrawBorder(CDC *pDC, CRect* rect); // 改写自CButton类 virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); protected: virtual void PreSubclassWindow(); // MFC标准消息映射函数 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 void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); protected: DECLARE_MESSAGE_MAP() public: // 正常状态下按钮的边框 CPen m_penBorderNormal; // 按钮获得焦点时的边框或者鼠标滑过或者停留在按钮上 CPen m_penBorderOnFocus; // 按钮状态 bool m_bMouseOn; // 鼠标在按钮上 bool m_bMouseClick; // 点击鼠标 bool m_bMouseUp; // 鼠标按键抬起 bool m_bFocus; // 鼠标获得焦点 CRect m_rect; }; #endif
// VincentButton.cpp : implementation file // #include "stdafx.h" #include "VincentButton.h" #ifdef _DEBUG #define new DEBUG_NEW #endif VincentButton::VincentButton() { m_penBorderNormal.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0x23, 0xC5, 0xCE)); m_penBorderOnFocus.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0xFF, 0x00, 0xFF)); m_bMouseOn = false; m_bMouseClick = false; m_bMouseUp = true; m_bFocus = false; } VincentButton::~VincentButton() { m_penBorderNormal.DeleteObject(); m_penBorderOnFocus.DeleteObject(); } BEGIN_MESSAGE_MAP(VincentButton, CButton) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() END_MESSAGE_MAP() #pragma warning(push) #pragma warning(disable:4800) void VincentButton::OnMouseMove(UINT nFlags, CPoint point) { if (!m_bMouseUp) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE | TME_HOVER; tme.dwHoverTime = 1; m_bMouseOn = _TrackMouseEvent(&tme); } CButton::OnMouseMove(nFlags, point); } #pragma warning(pop) LRESULT VincentButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) { m_bMouseOn = false; InvalidateRect(NULL); return 0; } LRESULT VincentButton::OnMouseHover(WPARAM wParam, LPARAM lParam) { m_bMouseOn = true; InvalidateRect(NULL, FALSE); return 0; } void VincentButton::OnLButtonDown(UINT nFlags, CPoint point) { m_bMouseOn = true; m_bMouseUp = false; m_bMouseClick = true; m_bFocus = true; InvalidateRect(NULL, FALSE); CButton::OnLButtonDown(nFlags, point); } void VincentButton::OnLButtonUp(UINT nFlags, CPoint point) { m_bMouseUp = true; m_bMouseOn = false; m_bMouseClick = true; m_bFocus = true; InvalidateRect(NULL, FALSE); CButton::OnLButtonUp(nFlags, point); } void VincentButton::GradientFill(CDC *pDC, CRect* rect) { BYTE r = 34; BYTE g = 180; BYTE b = 227; CPen *temp = new CPen; CPen *pOldPen = pDC->SelectObject(temp); LONG nMiddle = (rect->bottom - rect->top) / 2; LONG i = 0; for (i = nMiddle; i > rect->top; --i) { CPen pen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(r + 10 * (nMiddle - i), g + 2 * (nMiddle - i), b + (nMiddle - i))); pDC->SelectObject(&pen); pDC->MoveTo(rect->left, i); pDC->LineTo(rect->right, i); } for (i = nMiddle; i < rect->bottom; ++i) { CPen pen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(r + 10 * (i - nMiddle), g + 2 * (i - nMiddle), b + (i - nMiddle))); pDC->SelectObject(&pen); pDC->MoveTo(rect->left, i); pDC->LineTo(rect->right, i); } delete temp; pDC->SelectObject(pOldPen); } void VincentButton::DrawBorder(CDC *pDC, CRect* rect) { CPen *pOldPen ; CPoint oldPoint = pDC->MoveTo(rect->left, rect->bottom - 1); if (m_bFocus || m_bMouseOn) { pOldPen = pDC->SelectObject(&m_penBorderOnFocus); } else { pOldPen = pDC->SelectObject(&m_penBorderNormal); } pDC->MoveTo(rect->left, rect->top); pDC->LineTo(rect->right - 1, rect->top); pDC->LineTo(rect->right - 1, rect->bottom - 1); pDC->LineTo(rect->left, rect->bottom - 1); pDC->LineTo(rect->left, rect->top); pDC->MoveTo(oldPoint); pDC->SelectObject(pOldPen); } void VincentButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CRect rect = lpDrawItemStruct->rcItem; CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC); int nSaveDC=pDC->SaveDC(); UINT state = lpDrawItemStruct->itemState; TCHAR strText[MAX_PATH + 1]; ::GetWindowText(m_hWnd, strText, MAX_PATH); CPen* hOldPen = pDC->SelectObject(&m_penBorderNormal); if (state & ODS_FOCUS) { m_bFocus = true; m_bMouseClick = true; } else { m_bFocus = false; m_bMouseClick = false; } if (state & ODS_SELECTED || state & ODS_DEFAULT) { m_bFocus = true; } pDC->SelectObject(hOldPen); if (m_bMouseOn) { hOldPen = pDC->SelectObject(&m_penBorderOnFocus); GradientFill(pDC, &rect); } else { hOldPen = pDC->SelectObject(&m_penBorderNormal); GradientFill(pDC, &rect); } pDC->SelectObject(hOldPen); DrawBorder(pDC, &m_rect); //显示按钮的文本 if (strText!=NULL) { pDC->SetTextColor(RGB(0x3A, 0x5F, 0xCD)); 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 VincentButton::PreSubclassWindow() { ModifyStyle(0, BS_OWNERDRAW); GetClientRect(&m_rect); CButton::PreSubclassWindow(); }