CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。

如何给按钮添加图片,显示三种状态,点击、盘旋、初始状态(不点击也不盘旋状态)。

首先准备好3张不同状态的bmp格式图片。

例如:
CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。  CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。  CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。
CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。  CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。  CButton控件:MFC如何给按钮添加图片,显示三种状态,分别是点击、盘旋、初始状态(不点击也不盘旋状态)。
以下我利用vs2013示范一下。
1.创建MFC工程(基本对话框),我这里新建名为MFCApplication5Dlg:点击两个按钮(确定,取消这两个按钮)设置属性,Onwer Drawn属性设置为True(在vc是“所有者绘制”,打钩),作用是自定义按钮窗口。
2.新建一个继承于CButton类的类,我这里新建名为CPicButton。
CPicButton.h

#pragma once

// CPicButton
class CPicButton : public CButton
{
DECLARE_DYNAMIC(CPicButton)

public:
CPicButton();
virtual ~CPicButton();
//------------------------------------------添加的代码-------------------------------------------------------
void SetBitmapId(int nOver, int nNormal, int nPressed, int nFocus);//设置图片状态
//int nOver(鼠标在按钮上的状态),int nNormal(初始状态),int nPressed(按下状态),int nFocus(焦点)
BOOL m_bOver; //鼠标位于按钮之上时该值为true,反之为flase
BOOL m_bTracking; //在鼠标按下没有释放时,该值为true
BOOL m_bSelected; //按钮被按下时,该值为true
BOOL m_bFocus; //按钮为当前焦点所在时,该值为true

CBitmap m_NormalBitmap;//加载初始状态的图片
CBitmap m_PressedBitmap;//按下状态的图片
CBitmap m_FocusBitmap;//焦点状态的图片
CBitmap m_OverBitmap;//盘旋状态的图片

///----------------------------------------------------------------------------------
protected:
DECLARE_MESSAGE_MAP()
public:
//3.在类向导添加消息响应函数
这里的消息函数,在类向导添加3个消息函数:OnMouseMove(),OnMouseLeave(),OnMouseHover()。
注意:有些IDE版本的类向导并没有OnMouseLeave(),OnMouseHover()这两个消息函数。我是用vs2013(update5)版本的,所以会有这两个函数。
你的IDE(比如vc6.0,vs2012等)没有这些消息函数的话,可以手动自定义,效果一样。
手动添加:
 afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
 afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);

添加这两行代码之后,还没有完,要在CPciButton.cpp里面找到BEGIN_MESS_MAP开头的这行代码,如下:
BEGIN_MESSAGE_MAP(CControlButton, CButton)
//{{AFX_MSG_MAP(CControlButton)
// NOTE - the ClassWizard will add and remove mapping macros here.
//ON_WM_MOUSEMOVE()

//----------------------以下就是手动添加的代码------------------------------------
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)

///---------------------------------------------------------------------------------------------
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//-----------------------------------------------以下是我用vs2013版本直接在类向导添加的消息函数,以上是自定义添加的方法。------------------------
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnMouseLeave();
afx_msg void OnMouseHover(UINT nFlags, CPoint point);

//----------------------------------------------------------------------------------------------------------
//4.在类向导添加虚函数DrawItem。
virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
};

// PicButton.cpp : 实现文件
//

#include "stdafx.h"
#include "MFCApplication5.h"
#include "PicButton.h"


// CPicButton

IMPLEMENT_DYNAMIC(CPicButton, CButton)

CPicButton::CPicButton()
{
m_bOver/*(鼠标位于按钮之上)*/ = FALSE;
m_bSelected/*(按钮被按下)*/ = FALSE;
m_bTracking/*(在鼠标按下释放)*/ = FALSE;
m_bFocus /*按钮为当前焦点*/ = FALSE;

}

CPicButton::~CPicButton()
{
}
BEGIN_MESSAGE_MAP(CPicButton, CButton)
ON_WM_MOUSEMOVE()
ON_WM_MOUSELEAVE()
ON_WM_MOUSEHOVER()
END_MESSAGE_MAP()
// CPicButton 消息处理程序

void CPicButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);//cbSize 定义TRACKMOUSEEVENT结构体的大小;
tme.hwndTrack = m_hWnd;//hwndTrack 待跟踪窗口的句柄
tme.dwFlags = TME_LEAVE | TME_HOVER;//服务请求,鼠标移动位置,离开和盘旋按钮的事件消耗时间,也就是改变状态的失效和生效性
tme.dwHoverTime = 100;//光标在按钮上,改变状态的时间,以1毫秒为单位
m_bTracking = _TrackMouseEvent(&tme);
} CButton::OnMouseMove(nFlags, point);


}
//手动添加的是
LRESULT CControlButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
 m_bOver = FALSE; // 鼠标没位于按钮之上
m_bTracking = FALSE; //鼠标离开按钮
 InvalidateRect(NULL, FALSE); //让按钮重画
 return 0;//注意要返回值。
}

void CPicButton::OnMouseLeave()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_bOver = FALSE; // 鼠标没有位于按钮之上
m_bTracking = FALSE; //鼠标离开按钮
InvalidateRect(NULL, FALSE); //让按钮重画

CButton::OnMouseLeave();
}

//手动添加的是
LRESULT CControlButton::OnMouseHover(WPARAM wParam, LPARAM lParam)
{

 m_bOver = TRUE; //鼠标盘旋在按钮上空
InvalidateRect(NULL); //重画!
 return 0;
}

void CPicButton::OnMouseHover(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值

m_bOver = TRUE; //鼠标盘旋在按钮上空
InvalidateRect(NULL); //重画!

CButton::OnMouseHover(nFlags, point);
}


void CPicButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CRect rect = lpDrawItemStruct->rcItem;
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
int nSaveDC = pDC->SaveDC();
UINT state = lpDrawItemStruct->itemState;


//根据按钮的状态贴图
//(以下贴按钮状态图,分以下几种情况来贴,,,和我们平常贴背景图片一样的做法)
//鼠标停留按钮的状态
if (m_bOver)
{


//(以下按钮贴图,,可以用我们自己以前贴背景图的方法去做)

CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp;
pOldBmp = MemDC.SelectObject(&m_OverBitmap);//加载停留状态
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);

}

else
{

//初始状态
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp;
pOldBmp = MemDC.SelectObject(&m_NormalBitmap);//加载最初状态
BITMAP bmp;
m_NormalBitmap.GetObject(sizeof(bmp), &bmp);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);
}


//按钮被按下(选中)
if (state & ODS_SELECTED)
{
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp;
pOldBmp = MemDC.SelectObject(&m_PressedBitmap);
BITMAP bmp;
//pOldBmp->GetBitmap(&bmp);
m_PressedBitmap.GetObject(sizeof(bmp), &bmp);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);
}


// TODO: 添加您的代码以绘制指定项
}
//按钮图片的ID加载函数,在下面步骤的主对话框那里会被调用
void CPicButton::SetBitmapId(int nOver, int nNormal, int nPressed, int nFocus)
{
m_NormalBitmap.LoadBitmap(nNormal);
m_PressedBitmap.LoadBitmap(nPressed);
m_FocusBitmap.LoadBitmap(nFocus);
m_OverBitmap.LoadBitmap(nOver);


}
6.
在资源视图,引入Bitmap六张图片:
“确定”按钮的3张图片,我这里设置他们的ID是IDB_ok(初始状态),IDB_ok2(盘旋状态),IDB_ok2(按下状态)。
“取消”按钮的3张图片,我这里设置他们的ID是IDB_cancel1(初始状态),IDB_okcancel2(盘旋状态),IDB_cancel3(按下状态)。
7.
在主对话框MFCApplication5Dlg,在建立类向导为两个按钮添加成员变量,我这里把“确定”按钮的变量设置为m_ok,把“取消”按钮设置为m_cancel。
在MFCApplication5Dlg.h,添加#include "PicButton.h"这行代码,然后再把之前新添加的按钮成员变量的类名改掉,CButton改成CPicButton.
例如:
public:
CPicButton m_cancel;
CPicButton m_ok;

8.
在MFCApplication5Dlg.cpp中的OnInitDialog()中添加以下代码:

BOOL CMFCApplication5Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。
......
......
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码
-------------------------按钮自绘添加的代码-----------------------------------------
m_ok.SetBitmapId(IDB_ok2, IDB_ok, IDB_ok3, IDB_ok);
m_cancel.SetBitmapId(IDB_cancel2, IDB_cancel1, IDB_cancel3, IDB_cancel1);

-------------------------------------------------------------------------------------
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
做完以上步骤之后,运行程序,如下图效果: