首先来看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();
}