看了吕鑫老师的视频,自己试着编写了一个自绘按钮控件。
YuButton.h头文件如下:
#pragma once #include "afxwin.h" class CYuButton :public CWnd { private: BOOL m_bIsDown; BOOL m_bIsMove; BOOL _bMouseTrack;//鼠标追踪状态 CString m_sCaption; CFont *m_pFont; public: CYuButton(void); virtual ~CYuButton(void); BOOL Create(LPCTSTR sCpation,DWORD dwStyle,CONST CRect & rt,CWnd * pParendWnd, UINT uId); BOOL CreateEx(DWORD dwExStyle,LPCTSTR sCaption,DWORD dwStyle,CONST CRect & rt, CWnd * pParendWnd,UINT uId); DECLARE_MESSAGE_MAP() afx_msg void OnNcPaint(); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnPaint(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); //鼠标按下 void DrawDown(CDC * pDC); //鼠标移动 void DrawMove(CDC * pDC); //字体 void SetFont(CFont * pFont); CFont * GetFont(); afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnMouseHover(UINT nFlags, CPoint point); afx_msg void OnMouseLeave(); };
YuButton.cpp文件内容如下:
#include "StdAfx.h" #include "YuButton.h" CYuButton::CYuButton(void) { WNDCLASS wd={CS_VREDRAW|CS_HREDRAW,::DefWindowProc}; wd.lpszClassName = _T("YUButton"); AfxRegisterClass(&wd); m_bIsDown = FALSE; m_bIsMove = FALSE; _bMouseTrack = TRUE; } CYuButton::~CYuButton(void) { } BOOL CYuButton::Create(LPCTSTR sCaption,DWORD dwStyle,CONST CRect & rt,CWnd * pParendWnd,UINT uId) { m_sCaption = sCaption; m_pFont = pParendWnd->GetFont(); return CWnd::Create(_T("YUButton"),sCaption,dwStyle|WS_CHILD,rt,pParendWnd,uId); } BOOL CYuButton::CreateEx(DWORD dwExStyle,LPCTSTR sCaption,DWORD dwStyle,CONST CRect & rt, CWnd * pParendWnd,UINT uId) { m_sCaption = sCaption; return CWnd::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() void CYuButton::OnNcPaint() { } BOOL CYuButton::OnEraseBkgnd(CDC* pDC) { return true;//CWnd::OnEraseBkgnd(pDC); } void CYuButton::OnPaint() { CPaintDC dc(this); // device context for painting CRect rt; GetClientRect(&rt); if(!m_bIsDown )//未点击填充 { CBrush brush(RGB(241,243,248)); dc.SelectObject(brush); dc.FillRect(rt,&brush); } else DrawDown(&dc); if(m_bIsMove && !m_bIsDown)//鼠标移动 { DrawMove(&dc); } CPen pen;//画边框 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); } void CYuButton::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_bIsDown = TRUE; this->SetFocus(); this->Invalidate(TRUE); CWnd::OnLButtonDown(nFlags, point); } void CYuButton::OnLButtonUp(UINT nFlags, CPoint point) { // 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); } void CYuButton::OnMouseMove(UINT nFlags, CPoint point) { if (_bMouseTrack) //若允许追踪,则。 { TRACKMOUSEEVENT csTME; 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); } void CYuButton::DrawDown(CDC * pDC) { CRect rt; GetClientRect(&rt); CBrush brush; brush.CreateSolidBrush(RGB(124,180,233)); pDC->SelectObject(brush); pDC->FillRect(rt,&brush); } void CYuButton::SetFont(CFont * pFont) { m_pFont = pFont; } CFont * CYuButton::GetFont() { return m_pFont; } void CYuButton::DrawMove(CDC * pDC) { CRect rt; GetClientRect(&rt); CBrush brush; brush.CreateSolidBrush(RGB(188,199,216)); pDC->SelectObject(brush); pDC->FillRect(rt,&brush); } void CYuButton::OnKillFocus(CWnd* pNewWnd) { CWnd::OnKillFocus(pNewWnd); m_bIsMove = FALSE; Invalidate(TRUE); } void CYuButton::OnMouseHover(UINT nFlags, CPoint point) { m_bIsMove = TRUE; Invalidate(TRUE); CWnd::OnMouseHover(nFlags, point); } void CYuButton::OnMouseLeave() { _bMouseTrack = TRUE; m_bIsMove = FALSE; Invalidate(TRUE); CWnd::OnMouseLeave(); }
在对话框窗口头文件中声明:CYuButton m_ok成员变量,然后OnInitDialog函数中创建自绘按钮:
(注意:对话框窗口头文件,须包含自绘按钮控件的.h文件YuButton.h)
BOOL CtestDlg::OnInitDialog() { ... CRect rc(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,如下:
void OnClickedOk();
编写消息处理函数代码:
void CtestDlg::OnClickedOk() { AfxMessageBox(_T("ok")); }
代码很长,很多是自动生成的,主要的自绘过程都在OnPaint消息函数中完成。
原文地址:http://9233403.blog.51cto.com/9223403/1967115