题记:此文谨献给和我一样的C++初学者,欢迎高手指正。

两种情况下实现按钮自绘:1.界面中已有按钮控件,我们修改它的形状。 2.界面中没有按钮控件,我们动态创建并修改它的形状。

这里只讲第一种情况的按钮自绘,以后有机会再研究第二种。

原理:    1.MFC默认的按钮控件是一个矩形

2.在矩形区域内画一个内切椭圆,当矩形为正方形时,椭圆即为圆,然后切掉矩形内椭圆的补集部分,即四个边角都要切掉。

步骤:

1.创建基于对话框的MFC项目,命名”RoundButtonDemo“,此处不啰嗦;

2.先在窗口设计视图中添一个按钮控件,这里不修改它的属性,采用默认。 如下图

3.打开类向导添加一个类CRoundButton,基类为CButton,新添加的类只有一个构造函数和析构函数

4.在类向导中为CRoundButton类添加两个虚函数DrawItem()和PreSubclassWindow();这两个函数的作用在下面有简单说明。

5.PreSubclassWindow()该函数可以初始化子类窗口,做一些绘制子类窗口之前要做的事情,如按钮风格的修改,按钮形状的修改。

这里我们修改按钮的风格,改为ODS_OWNERDRAW风格,即自绘风格,这点很关键,不然什么效果都没有。当然如果这里不修改按钮自绘风格,一定要在按钮控件属性中将Owner Draw 设置为True;

还有在原理部分我们说过要切掉多余的四个边角,也在这里进行。下面是代码:

void CRoundButton::PreSubclassWindow()
{// TODO:  在此添加专用代码和/或调用基类ModifyStyle(0, BS_OWNERDRAW);//改为自绘风格// 绘制按钮可用区域,切掉四个边角CRgn rgn;CRect rct;GetClientRect(&rct);rgn.CreateEllipticRgnIndirect(&rct);//在按钮矩形内创建椭圆区域::SetWindowRgn(GetSafeHwnd(), (HRGN)rgn, true);//将椭圆区域应用到按钮上CButton::PreSubclassWindow();
}

6.上一步我们设置了按钮的可用区域,这一步我们就要绘制按钮,包括按钮边框,按钮在不同状态下的颜色,简单起见,我们只绘制按钮正常状态和按下状态下的颜色。

这些事情我们在DrawItem()函数中完成。先看下代码,再来分析。

void CRoundButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)//记得要把/*lpDrawItemStruct*/的注释去掉
{// TODO:  添加您的代码以绘制指定项CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);int nSaveDC = pDC->SaveDC();//存储当前设备环境,以便绘图结束时恢复原来状态</span>pDC->SelectObject(&m_normalBrush);//选择按钮正常状态(默认状态)下的画刷pDC->SelectObject(&m_Pen);//选择画笔CRect rct = lpDrawItemStruct->rcItem;//获取按钮矩形区域if (lpDrawItemStruct->itemState&ODS_SELECTED)//绘制按钮按下时的颜色{pDC->SelectObject(&m_activeBrush);}pDC->Ellipse(&rct);//画椭圆按钮,这一步用了之前选择的画笔和画刷//重绘字体pDC->SetBkMode(TRANSPARENT);//重绘文本时不擦除背景即透明模式,如果选择OPAQUE(不透明),在文本四周有白色矩形边框,十分之难看CString strText{};//c++11版本以下不支持此方法GetWindowText(strText);//获取按钮文本pDC->DrawText(strText, rct, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//重绘按钮文本//恢复设备环境pDC->RestoreDC(nSaveDC);
}

现在一句句来分析

(1)  CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

int nSaveDC = pDC->SaveDC();

这里有一个CDC类,这个类就是用来绘图的。CDC每一个C是C++类名前缀,DC是 Device Context的缩写。  DC一般译为设备环境或设备上下文,似乎有些难以理解。

举个例子,你开了汽车修理店,同时在旁边屋里又搞手机修理。现在你正拿着大扳手修汽车,你周边的所有都是设备环境DC,如地上有些机油的车库,你的扳手,还有你修理的车子,除了你自己之外都是设备环境,甚至干活的你都可算做是设备环境。这时有人来找你修手机,那么你得把扳手放好,把车库门关好,免得有不明情况的人来弄坏现场,偷东西。那么修手机的地方又是另一个设备环境,桌子,台灯,焊枪,镊子,小螺丝刀……都是修手机的设备环境。修完手机,我们回来继续修车子,那得要打开车库,拿出扳手,继续干活。

现在我们说回CDC类,画图要画板,画笔,画刷,颜料等,这些属于绘图的环境。假如现在我们完成了主窗体的绘制,现在要绘制按钮(画笔画边框,画刷给按钮图色),那我们要先把绘制主窗体的设备环境保存起来,因为绘制按钮我们会使用不同的画笔(CPEN)和画刷(CBRUSH)。

CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);获取当前窗口(主窗体)的设备环境。

int nSaveDC = pDC->SaveDC();    保存当前设备环境,完成按钮绘制后,要恢复这个环境。

(2)pDC->SelectObject(&m_normalBrush);   选择画刷,涂颜色
pDC->SelectObject(&m_Pen);选择 画笔,画边框

SelectObject()两个参数m_normalBrush ,m_Pen和稍后用到的m_activeBrush是CRoundButton的成员变量,因以我们要先添加这些变量。打开类向导,添加自定义成员变量(创建变量时选择“私有”),如下图

#pragma once
#include "afxwin.h"
class CRoundButton :public CButton
{
public:CRoundButton();~CRoundButton();virtual void PreSubclassWindow();virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
private:CBrush m_normalBrush;CPen m_Pen;CBrush m_activeBrush;
};

在RoundButton.cpp文件中添加构造函数的代码初始化这三个变量,并在析构函数中删除。代码如下:

CRoundButton::CRoundButton()
{m_Pen.CreatePen(PS_SOLID, 1, RGB(201, 201, 233));m_normalBrush.CreateSolidBrush(RGB(231, 221, 223));//正常状态下的按钮颜色m_activeBrush.CreateSolidBrush(RGB(201, 201, 233));//按钮按下时的按钮颜色
}CRoundButton::~CRoundButton()
{m_Pen.DeleteObject();m_normalBrush.DeleteObject();m_activeBrush.DeleteObject();
}

我们接着说,SelectObject()函数是CDC的成员函数,选择画图所用的画笔,画刷,字体。用这个函数选择了画刷画笔后,之后的画图就会应用这些绘画工具。

(3)CRect rct = lpDrawItemStruct->rcItem;

if (lpDrawItemStruct->itemState&ODS_SELECTED)

{

pDC->SelectObject(&m_activeBrush);

}

pDC->Ellipse(&rct);

这一段代码有详细注释,此处就不解释了,大家可以了解下“DRAWITEMSTRUCT”相关知识,以便能够更好地理解。

(4)pDC->SetBkMode(TRANSPARENT);//重绘文本时不擦除背景,即透明模式,如果选择OPAQUE(不透明),在文本四周有白色矩形边框,十分之难看
CString strText{};//采用列表方式初始化文本对象,c++11版本以下不支持此方法
GetWindowText(strText);//获取按钮文本
pDC->DrawText(strText, rct, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//重绘按钮文本

DT_CENTER:指定文本水平居中显示。
DT_VCENTER:指定文本垂直居中显示。该标记只在单行文本输出时有效,所以它必须与DT_SINGLELINE结合使用。
DT_SINGLELINE:单行显示文本,回车和换行符都不断行。

(5)pDC->RestoreDC(nSaveDC);最后 一步是恢复设备环境。

7.通过前面的工作,我们建立了CRoundButton类,现在我们就要将这个类应用到我在步骤2添加的按钮上。打开主窗体设计视图,右击按钮选择“添加变量”菜单项,弹出对话框:

这样我在主窗体类中定义了m_btn,它的类型是CRoundButton,关联的控件ID为IDC_BUTTON1(即我们步骤2添加的按钮)。

(8)现在我们可以编译了。执行结果如下:

       

后记:这个工程只做了基本功能,仅做学习之用。大家可以将这个类添加到自己的项目中再去完善,下面附上这个项目的下载地址,第一次写博客,用了很多时间,资源下载要1分,大家看这篇文章也可完成自绘按钮的。

项目下载地址:http://download.csdn.net/detail/yhcfsr/8373541

另外附CSDN上一篇写的好的文章,供大家参考: CDC类详解 http://blog.csdn.net/akof1314/article/details/5439866

(VC++2013)MFC自绘圆形按钮相关推荐

  1. 【界面】VC 6 MFC让窗口轻而易举变漂亮

    一.界面分析 主要是把数据放到合适的位置,并且获取窗口的pDC,用pDC->StretchBlt()函数显示图片,这里面创建了一个兼容的dc,先把数据选择到这里面,再用StrtchBlt()拷贝 ...

  2. VC++、MFC最好的开源项目

    介绍:介绍一下用VC++/MFC写的最好的开源项目. Sourceforge.net中有许多高质量的VC++开源项目,我列举了一些可以作为VC++程序员的参考. 正文: VC++.MFC中最好的开源项 ...

  3. VC++2013出现bug: 无法打开源文件“stdafx.h”

    VC++2013出现bug: 无法打开源文件"stdafx.h" 1.首先需要把#include "stdafx.h"置于最头 2.在解决方案资源管理器中添加以 ...

  4. VC用MFC开发的圆形进度条控件

    DownLoad Src VC用MFC开发的圆形进度条控件 visualsan@yahoo.cn NUAA zss 在NBA2007游戏里,还有很多科幻电影里,经常可以看到圆形进度条.有的用来显示导弹 ...

  5. 解决金仓数据库安装时安装VC++2013报错问题:不受信任提供程序信任的根证书中终止

    解决金仓数据库安装时安装VC++2013报错问题:不受信任提供程序信任的根证书中终止 安装微软的信任证书: 1.点击链接下载微软证书:http://download.microsoft.com/dow ...

  6. 2020年如何在VC++的MFC中使用CDao*库

    2020年如何在VC++的MFC中使用CDao*库 摘要 : 详细介绍如何在VC++的MFC中使用CDao库,需要安装哪些库,实现对Access 1995的mdb文件调用.选择MFC作为静态库解决CD ...

  7. C++、VC++、MFC网页自动注册、登陆、发帖、留言,QQ注册、QQ申请器源码、注册邮箱源码、自动发帖源码...

    C++.VC++.MFC网页自动注册.登陆.发帖.留言,QQ注册.QQ申请器源码.注册邮箱源码.自动发帖源码   参考资料: 自动登录yahoo邮箱http://blog.csdn.net/suisu ...

  8. VC++之MFC从零开始实现windows系统任务管理器(一、windows任务管理器界面的制作)

    VC++之MFC从零开始实现windows系统任务管理器(一.windows任务管理器界面的制作) 通过本例程从零开始使用VC++与MFC实现一个基于windows的任务管理器. 最终效果图 软件工具 ...

  9. 【181122】VC++基于MFC的图片浏览器(有多种特效)源代码

    源码下载简介 一个完整的毕业设计+论文+PPT演示,VC++基于MFC的图片浏览器,在进行图片浏览或打开.关闭.切换的时候都带有多种特效,实现PCX.BMP.TGA.GIF.JPEG的读写显示,并可以 ...

最新文章

  1. Python源码学习:Python类机制分析-用户自定义类
  2. 009_InputNumber计数器
  3. Android SQLite数据库的详细使用
  4. 【渝粤题库】国家开放大学2021春1375Matlab语言及其应用题目
  5. 中高德地图只显示某一城市_Excel实用知识:从零开始,一步步制作属于你自己的三维演示地图...
  6. centos7以普通用户开机启动某个服务或者指定脚本
  7. 嵌入式工作笔记0007---对讲机嵌入式开发记录---认识对讲机的功能--随时更新
  8. 在职工象棋赛上弃子拿下一盘
  9. element ui设置表格表头高度和每一行的高度
  10. ParticleSystem的使用
  11. asp.net mysql数据库连接字符串_如何让您的ASP.NET数据库连接字符串是安全的
  12. 5G协议下载地址及介绍
  13. 【计算机网络】信源编码——香农三大定理
  14. 六轴传感器——姿态检测(20200112)(未完)
  15. 时间管理表 - 《待办清单列表》
  16. Vue 单文件模板中覆盖引入库 CSS 样式
  17. PointOperation03_Matlab灰度gray图反色(inverting)
  18. python 操作ps_Python实现PS滤镜碎片特效功能示例
  19. OCT-视网膜分层处理
  20. jenkins 管理员邮箱配置

热门文章

  1. 微信小程序【渲染层网络层错误】解决方法
  2. balsamiq mockups 3安装
  3. HISI3559A 使用yolov3 (VI-VPSS-VO)实时目标检测
  4. 散射回波仿真Matlab,基于散射中心模型的ISAR回波仿真方法
  5. 复习2个月拿下美团offer,我都做了些啥
  6. 验证邮箱格式html代码,jquery验证邮箱格式是否正确实例讲解
  7. 那些年让人迷惑的同步、异步、阻塞、非阻塞
  8. asp.net 打开服务器文件,aspnet打开服务器文件夹
  9. 微信小程序:开心锤锤超火动态表情包微信小程序源码下载自动采集
  10. 达梦数据库 开发版试用时间限制