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窗口里
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重绘
}
4.在对话框的OnInitDialog()函数中,将button控件子类化 mybtn=new CMyButton; //mybtn已经定义为CMyButton*类型
mybtn->SubclassWindow(GetDlgItem(IDC_BUTTON_1)->GetSafeHwnd());
SubclassWindow函数非常重要,它将IDC_BUTTON_1窗口子类化,这样IDC_BUTTON_1窗口的消息,以后由CMyButton类来处理
5.完成以上几步,button就自绘成功啦