首先写这篇文章的时候要感谢 CRongQ 以及 csdndenglu 两位博主
尤其是后者,本文实现的代码类基本是源自于
这篇博文,改进而来
https://blog.csdn.net/csdndenglu/article/details/80499556?spm=1001.2014.3001.5502
增添的是按照不同IDC对应的控件如何添加不同的点击前后的值
以及利用指针绕开 CDC CBITMAP等 CObject类无法直接复制而显得代码臃肿的问题 具体修改结合代码来说。
运行环境 VS2010
首先 :
1、建立基于对话框的MFC程序QR code,对话框上添加三个按钮,
对应按钮的ID为IDC_CREAT,IDC_PRINT,IDC_CANCEL。
到resource.h文件中查看这三个控件对应的define值
我这里是1000,1001,1004为例。
2、项目名上右击->添加->类,添加MFC类(选MFC类非C++类),派生于CButton 的名为CMyButton的类。
3、分别给IDC_CREAT,IDC_PRINT,IDC_CANCEL添加CMyButton类型的变量m_creat,m_print,m_cancel。
(右键对话框上的控件选择添加成员变量,成员类的类名手动输入你创建的类 我的是CMyButton)
顺便把这几个控件的属性里的 onwer draw 改成 true。
4、添加六个.bmp位图,ID分别为IDB_BITMAP1,IDB_BITMAP2,IDB_BITMAP3,IDB_BITMAP4,IDB_BITMAP5,IDB_BITMAP6。
5、项目,类向导中查看我们创建的CMyButton这个类,
选择虚函数成员里的drawitem 重载该函数并进行修改即可
仿照下面的CMyButton.h,CMyButton.cpp修改你添加的类代码即可。
CMyButton.h
#pragma once
//添加的一个MFC类 基于CButton类 创建的MFC类
// CMyButton
class CMyButton : public CButton
{
DECLARE_DYNAMIC(CMyButton)
public:
CMyButton();
virtual ~CMyButton();
protected:
DECLARE_MESSAGE_MAP()
public:
//向控件填入图片 点击之前点击之后
//对应的UINT均为resource.h对应的图片IDB IDC值
//第二个参数表示当前按钮状态 选中或者未选中
//bmp_before和bmp_after对应resource.h里面的位图
//为选中前后的图片 带*的指针传递避免复制CObject报错
void idc_load_bmp(UINT idc_control,
UINT now,
UINT bmp_before,
UINT bmp_after,
CDC* ButtonDC,
CBitmap* bitmapTrans,
CDC* mem,
CRect rc);
//CMyButton类中重载 DRAWItem函数
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
};
// MyButton.cpp : 实现文件
#include "stdafx.h"
#include "QR code.h"
#include "MyButton.h"
// CMyButton
IMPLEMENT_DYNAMIC(CMyButton, CButton)
CMyButton::CMyButton()
{
}
CMyButton::~CMyButton()
{
}
BEGIN_MESSAGE_MAP(CMyButton, CButton)
END_MESSAGE_MAP()
// CMyButton 消息处理程序
//重载函数DrawItem的具体内容
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* ButtonDC=new CDC ; //指针引用
CDC* mem=new CDC ; //指针引用
CBitmap* bitmapTrans=new CBitmap; //指针引用
CRect rc; //得到用于绘制按钮的DC
//获取lpDrawItemStruct内所需要的值
ButtonDC->Attach(lpDrawItemStruct->hDC);
mem->CreateCompatibleDC(ButtonDC);
//获取按钮自身大小用于修改bmp位图大小
rc=lpDrawItemStruct->rcItem;
//获取按钮的状态 这里不选择focus而选择select用于修改贴图
UINT state = lpDrawItemStruct->itemState;
//获取控件对应的 IDC 资源列表的值 以IDC_CREAT为例应为1000
UINT ID = lpDrawItemStruct->CtlID;
switch (ID)
{
case IDC_CREAT: //1000 为IDC_CREAT的值 下同
//类中自己写的一个成员函数 定义在下面
idc_load_bmp(ID,state,IDB_BITMAP1,IDB_BITMAP2,
ButtonDC,bitmapTrans,mem,rc);
break;
case IDC_PRINT: // IDC_PRINT 的值
idc_load_bmp(ID,state,IDB_BITMAP3,IDB_BITMAP4,
ButtonDC,bitmapTrans,mem,rc);
break;
case IDC_CANCEL: // IDC_CANCEL 的值
idc_load_bmp(ID,state,IDB_BITMAP5,IDB_BITMAP6,
ButtonDC,bitmapTrans,mem,rc);
break;
default:
break;
}
}
//类中自己定义的一个函数成员 参数含义参考头文件函数定义处
void CMyButton::idc_load_bmp(UINT idc_control,
UINT now,
UINT bmp_before,
UINT bmp_after,
CDC* ButtonDC,
CBitmap* bitmapTrans,
CDC* mem,
CRect rc)
{
//成员函数开始
BITMAP bmp; //预备加载位图
//选中按钮 没有选中该按钮时重置该按钮
//实现效果比ODS_FOCUS要好
if (now&ODS_SELECTED) //如果点击中按钮
{
bitmapTrans->LoadBitmap(bmp_after); //加载点中后图片
bitmapTrans->GetBitmap(&bmp);
//向按钮位置传输位图
CBitmap *old = mem->SelectObject(bitmapTrans);
//使用StretchBlt使得位图按按钮大小变换 照抄就行了
ButtonDC->StretchBlt(rc.left,rc.top,rc.right,rc.bottom,
mem,0,0,
bmp.bmWidth,
bmp.bmHeight,
SRCCOPY);
mem->SelectObject(old); //载入该位图
bitmapTrans->DeleteObject(); //释放
}
else //参照上面的注释
{
bitmapTrans->LoadBitmap(bmp_before);
CBitmap *old2 = mem->SelectObject(bitmapTrans);
bitmapTrans->GetBitmap(&bmp);
CBitmap *old = mem->SelectObject(bitmapTrans);
ButtonDC->StretchBlt(rc.left,rc.top,rc.right,rc.bottom,
mem,0,0,
bmp.bmWidth,
bmp.bmHeight,
SRCCOPY);
mem->SelectObject(old2);
bitmapTrans->DeleteObject();
}
}
大功告成,收工。再次感谢二位博主的文章学习,让我获益匪浅。