1.所谓自绘button,就是button的各种不同状态都需要我们自己绘制。
button的基本状态有:
鼠标在button外面,即鼠标离开button
鼠标悬浮在button上方,没有按下
鼠标按下button
2.用WM_MOUSELEAVE和WM_MOUSEMOVE来追踪鼠标在button外,还是鼠标在button里面。由于窗口是不响应 WM_MOUSELEAVE消息的,所以要使用 _TrackMouseEvent函数来激活这个消息。调用这个函数后,当鼠标离开窗口后,该函数会 Post 这个消息到指定窗口。
在 OnMouseMove 中调用 _TrackMouseEvent 函数来不停的追踪WM_MOUSELEAVE消
{
if (!isinbutton)
{
TRACKMOUSEEVENT mouseevent;
mouseevent.cbSize=sizeof(mouseevent);
mouseevent.dwFlags=TME_LEAVE;
mouseevent.dwHoverTime=10;
mouseevent.hwndTrack=m_hWnd;
_TrackMouseEvent(&mouseevent);
isinbutton=true;
Invalidate();
}
}
isinbutton来判断鼠标是否在button窗口里
4.在对话框的OnInitDialog()函数中,将button控件子类化CMyButton.h #pragma once #ifndef _H_MYBUTTON_H #define _H_MYBUTTON_H class CMyButton : public CButton { DECLARE_DYNAMIC(CMyButton) public: CMyButton(); ~CMyButton(); virtual void PreSubclassWindow(); virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); void FillRect(COLORREF color,CString text); void ButtonLoadBitmap(CBitmap *cbitmap); protected: afx_msg void OnMouseLeave(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() private: bool isinbutton; //鼠标是在button窗口里 bool isbuttondown; //button是否被按下 CRect rect; CBitmap m_bmpNormal; //初始时button的位图 CBitmap m_bmpOn; //鼠标悬浮在button上方时,button的位图 CBitmap m_bmpDown; //按下button时,button的位图 CDC *dc; }; #endif CMyButton.cpp #include "MyButtonDemo.h" #include "MyButton.h" #include <afx.h> IMPLEMENT_DYNAMIC(CMyButton, CButton) CMyButton::CMyButton() { isinbutton=false; isbuttondown=false; } CMyButton::~CMyButton() { } BEGIN_MESSAGE_MAP(CMyButton, CButton) ON_WM_MOUSEMOVE() ON_WM_MOUSELEAVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() END_MESSAGE_MAP() void CMyButton:: OnMouseMove(UINT nFlags, CPoint point) { if (!isinbutton) { TRACKMOUSEEVENT mouseevent; mouseevent.cbSize=sizeof(mouseevent); mouseevent.dwFlags=TME_LEAVE; mouseevent.dwHoverTime=10; mouseevent.hwndTrack=m_hWnd; _TrackMouseEvent(&mouseevent); isinbutton=true; Invalidate();//刷新button窗口,调用DrawItem函数来进行button重绘 } void CMyButton::OnMouseLeave() { isinbutton=false; isbuttondown=false; Invalidate();//刷新button窗口,DrawItem函数来进行button重绘 } void CMyButton::PreSubclassWindow() { this->ModifyStyle(0, BS_OWNERDRAW);//修改为自绘button GetClientRect(&rect); m_bmpNormal.LoadBitmap(IDB_BITMAP_NORMAL1); m_bmpDown.LoadBitmap(IDB_BITMAP_ON2); m_bmpOn.LoadBitmap(IDB_BITMAP_ON2); dc=GetDC(); CButton::PreSubclassWindow(); } void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CString text=_T(""); if (isbuttondown) //button被按下 { isbuttondown=true; ButtonLoadBitmap(&m_bmpDown); text=_T("hover"); FillRect(RGB(255,0,0),text); } else if(isinbutton) //鼠标悬浮在button上方 { ButtonLoadBitmap(&m_bmpOn); text=_T("hover"); FillRect(RGB(0,255,0),text); } else //鼠标在button窗口外 { ButtonLoadBitmap(&m_bmpNormal); text=_T("intal"); FillRect(RGB(0,0,255),text); } } void CMyButton::FillRect(COLORREF color,CString text) { //设置文字背景为透明 SetBkMode(dc->GetSafeHdc(),TRANSPARENT); if (isbuttondown) { CRect rectdown=rect; rectdown.OffsetRect(0,1); //button被按下,字体向下偏移1 dc->DrawText (text,&rectdown,DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; } else dc->DrawText(text,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; } void CMyButton::ButtonLoadBitmap(CBitmap *cbitmap) { CDC dcMem; dcMem.CreateCompatibleDC(dc); BITMAP bitmap; cbitmap->GetBitmap(&bitmap); CBitmap *pbmpOld=dcMem.SelectObject(cbitmap); dc->SetStretchBltMode(HALFTONE); dc->StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY); dcMem.SelectObject(pbmpOld); } void CMyButton::OnLButtonDown(UINT nFlags, CPoint point) { isbuttondown=true; Invalidate();//刷新button窗口,调用DrawItem函数来进行button重绘 } void CMyButton::OnLButtonUp(UINT nFlags, CPoint point) { isbuttondown=FALSE; Invalidate();//刷新button窗口,调用DrawItem函数来进行button重绘 }
mybtn=new CMyButton; //mybtn已经定义为CMyButton*类型
mybtn->SubclassWindow(GetDlgItem(IDC_BUTTON_1)->GetSafeHwnd());
SubclassWindow函数非常重要,它将IDC_BUTTON_1窗口子类化,这样IDC_BUTTON_1窗口的消息,以后由CMyButton类来处理
5.完成以上几步,button就自绘成功啦