看了吕鑫老师的视频,自己试着编写了一个自绘按钮控件。
YuButton.h头文件如下:

#pragmaonce#include"afxwin.h"classCYuButton:publicCWnd{private:BOOLm_bIsDown;BOOLm_bIsMove;BOOL_bMouseTrack;//鼠标追踪状态CStringm_sCaption;CFont*m_pFont;public:CYuButton(void);virtual~CYuButton(void);BOOLCreate(LPCTSTRsCpation,DWORDdwStyle,CONSTCRect&rt,CWnd*pParendWnd,UINTuId);BOOLCreateEx(DWORDdwExStyle,LPCTSTRsCaption,DWORDdwStyle,CONSTCRect&rt,CWnd*pParendWnd,UINTuId);DECLARE_MESSAGE_MAP()afx_msgvoidOnNcPaint();afx_msgBOOLOnEraseBkgnd(CDC*pDC);afx_msgvoidOnPaint();afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);//鼠标按下voidDrawDown(CDC*pDC);//鼠标移动voidDrawMove(CDC*pDC);//字体voidSetFont(CFont*pFont);CFont*GetFont();afx_msgvoidOnKillFocus(CWnd*pNewWnd);afx_msgvoidOnMouseHover(UINTnFlags,CPointpoint);afx_msgvoidOnMouseLeave();};

YuButton.cpp文件内容如下:

#include"StdAfx.h"#include"YuButton.h"CYuButton::CYuButton(void){WNDCLASSwd={CS_VREDRAW|CS_HREDRAW,::DefWindowProc};wd.lpszClassName=_T("YUButton");AfxRegisterClass(&wd);m_bIsDown=FALSE;m_bIsMove=FALSE;_bMouseTrack=TRUE;}CYuButton::~CYuButton(void){}BOOLCYuButton::Create(LPCTSTRsCaption,DWORDdwStyle,CONSTCRect&rt,CWnd*pParendWnd,UINTuId){m_sCaption=sCaption;m_pFont=pParendWnd->GetFont();returnCWnd::Create(_T("YUButton"),sCaption,dwStyle|WS_CHILD,rt,pParendWnd,uId);}BOOLCYuButton::CreateEx(DWORDdwExStyle,LPCTSTRsCaption,DWORDdwStyle,CONSTCRect&rt,CWnd*pParendWnd,UINTuId){m_sCaption=sCaption;returnCWnd::CreateEx(dwExStyle,_T("YUButton"),sCaption,dwStyle|WS_CHILD,rt,pParendWnd,uId);}BEGIN_MESSAGE_MAP(CYuButton,CWnd)ON_WM_NCPAINT()ON_WM_ERASEBKGND()ON_WM_PAINT()ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_WM_KILLFOCUS()ON_WM_MOUSEHOVER()ON_WM_MOUSELEAVE()END_MESSAGE_MAP()voidCYuButton::OnNcPaint(){}BOOLCYuButton::OnEraseBkgnd(CDC*pDC){returntrue;//CWnd::OnEraseBkgnd(pDC);}voidCYuButton::OnPaint(){CPaintDCdc(this);//devicecontextforpaintingCRectrt;GetClientRect(&rt);if(!m_bIsDown)//未点击填充{CBrushbrush(RGB(241,243,248));dc.SelectObject(brush);dc.FillRect(rt,&brush);}elseDrawDown(&dc);if(m_bIsMove&&!m_bIsDown)//鼠标移动{DrawMove(&dc);}CPenpen;//画边框pen.CreatePen(PS_SOLID,1,RGB(85,134,233));dc.SelectObject(pen);dc.Rectangle(rt);dc.SelectObject(m_pFont);//父窗口字体dc.SetBkMode(TRANSPARENT);dc.DrawText(m_sCaption,rt,DT_VCENTER|DT_CENTER|DT_SINGLELINE);}voidCYuButton::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值m_bIsDown=TRUE;this->SetFocus();this->Invalidate(TRUE);CWnd::OnLButtonDown(nFlags,point);}voidCYuButton::OnLButtonUp(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值m_bIsDown=FALSE;this->Invalidate(TRUE);CWnd*pWnd=this->GetParent();if(pWnd)pWnd->SendMessage(WM_COMMAND,GetDlgCtrlID(),(LPARAM)this->GetSafeHwnd());CWnd::OnLButtonUp(nFlags,point);}voidCYuButton::OnMouseMove(UINTnFlags,CPointpoint){if(_bMouseTrack)//若允许追踪,则。{TRACKMOUSEEVENTcsTME;csTME.cbSize=sizeof(csTME);csTME.dwFlags=TME_LEAVE|TME_HOVER;csTME.hwndTrack=m_hWnd;//指定要追踪的窗口csTME.dwHoverTime=10;//鼠标在按钮上停留超过10ms,才认为状态为HOVER::_TrackMouseEvent(&csTME);//开启Windows的WM_MOUSELEAVE,WM_MOUSEHOVER事件支持_bMouseTrack=FALSE;//若已经追踪,则停止追踪}CWnd::OnMouseMove(nFlags,point);}voidCYuButton::DrawDown(CDC*pDC){CRectrt;GetClientRect(&rt);CBrushbrush;brush.CreateSolidBrush(RGB(124,180,233));pDC->SelectObject(brush);pDC->FillRect(rt,&brush);}voidCYuButton::SetFont(CFont*pFont){m_pFont=pFont;}CFont*CYuButton::GetFont(){returnm_pFont;}voidCYuButton::DrawMove(CDC*pDC){CRectrt;GetClientRect(&rt);CBrushbrush;brush.CreateSolidBrush(RGB(188,199,216));pDC->SelectObject(brush);pDC->FillRect(rt,&brush);}voidCYuButton::OnKillFocus(CWnd*pNewWnd){CWnd::OnKillFocus(pNewWnd);m_bIsMove=FALSE;Invalidate(TRUE);}voidCYuButton::OnMouseHover(UINTnFlags,CPointpoint){m_bIsMove=TRUE;Invalidate(TRUE);CWnd::OnMouseHover(nFlags,point);}voidCYuButton::OnMouseLeave(){_bMouseTrack=TRUE;m_bIsMove=FALSE;Invalidate(TRUE);CWnd::OnMouseLeave();}

在对话框窗口头文件中声明:CYuButton m_ok成员变量,然后OnInitDialog函数中创建自绘按钮:
(注意:对话框窗口头文件,须包含自绘按钮控件的.h文件YuButton.h)

BOOLCtestDlg::OnInitDialog(){...CRectrc(20,20,120,43);m_ok.Create(_T("确定"),WS_VISIBLE,rc,this,1290);...}

手动添加消息映射,为什么手动,因为自绘按钮,其ID不在资源中,所以不能用类向导管理,如下:

BEGIN_MESSAGE_MAP(CtestDlg,CDialogEx)...ON_BN_CLICKED(1290,&CtestDlg::OnClickedOk)END_MESSAGE_MAP()

对话框窗口头文件中,声明相应的消息处理函数OnClickedOk,如下:

voidOnClickedOk();

编写消息处理函数代码:

voidCtestDlg::OnClickedOk(){AfxMessageBox(_T("ok"));}

代码很长,很多是自动生成的,主要的自绘过程都在OnPaint消息函数中完成。