MFC界面美化第三篇----自绘按钮(重绘按钮)

1.前言

最近发现读者对我的mfc美化的专栏比较感兴趣,因此在这里进行续写,这里我会计划写几个连续的篇章,包括对MFC按钮的美化,菜单栏的美化,标题栏的美化,list列表的美化,直到最后形成一个完整的成品效果。

2.最终效果展示

点击启动按钮之后,能响应功能。

博主不会UI设计图片显示的效果比较差,用更好的图片贴上去,就能显示更好的效果的

3.思路分析

1.使用我们设计好的图片,来美化按钮。把图片贴到按钮上

2.创建一个按钮类,继承CButton,来重绘按钮

3.核心还是重写了 DrawItem,函数来实现重绘的效果

4.实现过程

1.在MFC的界面那里,创建两个按钮,启动和停止按钮。

2.找到按钮的属性那里,把所有者描述改成true,不然重绘是不能成功的,这一步是一定要做的

3.核心代码

头文件里面声明按钮变量

public:
	CMyButton m_button_start;
	CMyButton m_button_stop;
	afx_msg void OnBnClickedButton2();
	afx_msg void OnBnClickedButton1();

OnInitDialog()函数

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

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	//退出按钮绘制
	CRect rtBtnClo;
	GetClientRect(&rtBtnClo);
	rtBtnClo.left = rtBtnClo.right - 20;
	m_btnExit.SetImagePath(_T(".\\res\\icon_popup_off.png"), _T(".\\res\\icon_popup_off.png"), _T(".\\res\\icon_popup_off.png"));
	m_btnExit.InitMyButton(rtBtnClo.left, 5, 16, 16, true);
	//最大化按钮绘制
	GetClientRect(&rtBtnClo);
	rtBtnClo.left = rtBtnClo.right - 50;
	m_btnMax.SetImagePath(_T(".\\res\\icon_square.png"), _T(".\\res\\icon_square.png"), _T(".\\res\\icon_square.png"));
	m_btnMax.InitMyButton(rtBtnClo.left, 5, 16, 16, true);
	//最小化按钮
	// GetClientRect(&rtBtnClo);
	rtBtnClo.left = rtBtnClo.right - 80;
	m_btnMin.SetImagePath(_T(".\\res\\icon_minimiz.png"), _T(".\\res\\icon_minimiz.png"), _T(".\\res\\icon_minimiz.png"));
	m_btnMin.InitMyButton(rtBtnClo.left, 5, 16, 16, true);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

5.button重绘的头文件和cpp文件

mybutton.h

pch.h, 和framework.h这两个文件的路径,可以改的。根据你的项目文件实际放置情况

#pragma once

#include <afxwin.h>
#include "../pch.h"
#include "../framework.h"
// CMyButton

class CMyButton : public CButton
{
	DECLARE_DYNAMIC(CMyButton)

public:
	CMyButton();
	virtual ~CMyButton();

protected:
	//正常状态图像路径
	CString m_strNormalImgPath;
	//按下状态图像路径
	CString m_strPressImgPath;
	//悬浮状态图像路径
	CString m_strFloatImgPath;

	//正常状态图像
	CImage m_imgNormal;
	//按下状态图像
	CImage m_imgPress;
	//悬浮状态图像
	CImage m_imgFloat;

	//窗口背景图片
	CImage m_BkImg;

public:

	//设置按钮图片路径
	void SetImagePath(CString strNoramlImgPath, CString strPressImgPath, CString strFloatImgPath);
	//初始化按钮,主要是调整按钮的位置,处理透明色  
	bool InitMyButton(int nX/*左上角X坐标*/, int nY/*左上角Y坐标*/, int nW/*图像宽*/, int nH/*图像高*/, bool bIsPng/*是否是PNG图片*/);
	//自绘制函数  
	void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

	//初始化窗口背景
	void SetBkImg(CString strBkImg);
	//释放图片资源,方便最大化 
	void ReleaseImg();
protected:
	//光标是否在窗口内
	BOOL m_bIsInWnd;
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnMouseHover(UINT nFlags, CPoint point);
	afx_msg void OnMouseLeave();

	
};


mybutton.cpp

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

#include "pch.h"
#include "MyButton.h"


// CMyButton

IMPLEMENT_DYNAMIC(CMyButton, CButton)

CMyButton::CMyButton()
{
	m_bIsInWnd = FALSE;
}

CMyButton::~CMyButton()
{
}


BEGIN_MESSAGE_MAP(CMyButton, CButton)
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSEHOVER()
	ON_WM_MOUSELEAVE()
END_MESSAGE_MAP()



// CMyButton 消息处理程序

//设置按钮图片路径
void CMyButton::SetImagePath(CString strNoramlImgPath, CString strPressImgPath, CString strFloatImgPath)
{
	m_strNormalImgPath = strNoramlImgPath;
	m_strPressImgPath = strPressImgPath;
	m_strFloatImgPath = strFloatImgPath;
}

void CMyButton::SetBkImg(CString strBkImg)
{
	if (strBkImg.IsEmpty())
		return;
	m_BkImg.Load(strBkImg);
}

//初始化按钮,主要是调整按钮的位置,处理透明色 
void CMyButton::ReleaseImg()
{
	if (m_imgNormal)
	{
		m_imgNormal.Destroy();
	}
	if (m_imgPress)
	{
		m_imgPress.Destroy();
	}
	if (m_imgFloat)
	{
		m_imgFloat.Destroy();
	}
}
bool CMyButton::InitMyButton(int nX/*左上角X坐标*/, int nY/*左上角Y坐标*/, int nW/*图像宽*/, int nH/*图像高*/, bool bIsPng/*是否是PNG图片*/)
{
	HRESULT hr = 0;

	if (m_strNormalImgPath.IsEmpty())
		return false;
	if (m_strPressImgPath.IsEmpty())
		return false;
	if (m_strFloatImgPath.IsEmpty())
		return false;

	hr = m_imgNormal.Load(m_strNormalImgPath);

	int a = GetLastError();

	if (FAILED(hr))
		return false;

	hr = m_imgPress.Load(m_strPressImgPath);

	if (FAILED(hr))
		return false;

	hr = m_imgFloat.Load(m_strFloatImgPath);

	if (FAILED(hr))
		return false;

	if (bIsPng)
	{
		if (m_imgNormal.GetBPP() == 32)
		{
			int i = 0;
			int j = 0;
			for (i = 0; i < m_imgNormal.GetWidth(); i++)
			{
				for (j = 0; j < m_imgNormal.GetHeight(); j++)
				{
					byte * pbyte = (byte *)m_imgNormal.GetPixelAddress(i, j);
					pbyte[0] = pbyte[0] * pbyte[3] / 255;
					pbyte[1] = pbyte[1] * pbyte[3] / 255;
					pbyte[2] = pbyte[2] * pbyte[3] / 255;
				}
			}
		}

		if (m_imgPress.GetBPP() == 32)
		{
			int i = 0;
			int j = 0;
			for (i = 0; i < m_imgPress.GetWidth(); i++)
			{
				for (j = 0; j < m_imgPress.GetHeight(); j++)
				{
					byte * pbyte = (byte *)m_imgPress.GetPixelAddress(i, j);
					pbyte[0] = pbyte[0] * pbyte[3] / 255;
					pbyte[1] = pbyte[1] * pbyte[3] / 255;
					pbyte[2] = pbyte[2] * pbyte[3] / 255;
				}
			}
		}

		if (m_imgFloat.GetBPP() == 32)
		{
			int i = 0;
			int j = 0;
			for (i = 0; i < m_imgFloat.GetWidth(); i++)
			{
				for (j = 0; j < m_imgFloat.GetHeight(); j++)
				{
					byte * pbyte = (byte *)m_imgFloat.GetPixelAddress(i, j);
					pbyte[0] = pbyte[0] * pbyte[3] / 255;
					pbyte[1] = pbyte[1] * pbyte[3] / 255;
					pbyte[2] = pbyte[2] * pbyte[3] / 255;
				}
			}
		}
	}

	MoveWindow(nX, nY, nW, nH);

	return true;

}
//自绘制函数  
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	if (!lpDrawItemStruct)
		return;
	HDC hMemDC;
	HBITMAP bmpMem;
	HGDIOBJ hOldObj;
	bmpMem = CreateCompatibleBitmap(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top);
	if (!bmpMem)
		return;
	hMemDC = CreateCompatibleDC(lpDrawItemStruct->hDC);
	if (!hMemDC)
	{
		if (bmpMem)
		{
			::DeleteObject(bmpMem);
			bmpMem = NULL;
		}
		return;
	}

	hOldObj = ::SelectObject(hMemDC, bmpMem);

	int nW = lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left;

	int nH = lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top;

	RECT rectTmp = { 0 };

	rectTmp = lpDrawItemStruct->rcItem;

	MapWindowPoints(GetParent(), &rectTmp);

	if (m_BkImg.IsNull() == false)
		m_BkImg.Draw(hMemDC, 0, 0, rectTmp.right - rectTmp.left, rectTmp.bottom - rectTmp.top, rectTmp.left, rectTmp.top, rectTmp.right - rectTmp.left, rectTmp.bottom - rectTmp.top);
	
	if (lpDrawItemStruct->itemState & ODS_SELECTED)
	{
		//按钮被选择  
		m_imgPress.AlphaBlend(hMemDC, 0, 0, nW, nH, 0, 0, nW, nH);
	}
	else
	{
		//默认状态  
		m_imgNormal.AlphaBlend(hMemDC, 0, 0, nW, nH, 0, 0, nW, nH);

	}

	::BitBlt(lpDrawItemStruct->hDC, 0, 0, nW, nH, hMemDC,0,0,SRCCOPY);

	SelectObject(hMemDC, hOldObj);

	if (bmpMem)
	{
		::DeleteObject(bmpMem);
		bmpMem = NULL;
	}

	if (hMemDC)
	{
		::DeleteDC(hMemDC);
		hMemDC = NULL;
	}
	return;
}

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

	CButton::OnMouseMove(nFlags, point);
	if (!m_bIsInWnd)
	{
		TRACKMOUSEEVENT       tme;
		tme.cbSize = sizeof(TRACKMOUSEEVENT);
		tme.dwFlags = TME_HOVER | TME_LEAVE;
		tme.dwHoverTime = 10;
		tme.hwndTrack = m_hWnd;
		_TrackMouseEvent(&tme);
		m_bIsInWnd = TRUE;
	}
}


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

	HDC hMemDC;
	HBITMAP bmpMem;
	HGDIOBJ hOldObj;
	HDC hDC = ::GetDC(GetSafeHwnd());
	CRect rcItem;
	GetClientRect(&rcItem);

	if (hDC)
	{
		bmpMem = CreateCompatibleBitmap(hDC, rcItem.Width(), rcItem.Height());
		if (!bmpMem)
		{
			::ReleaseDC(GetSafeHwnd(), hDC);
			return;
		}
		hMemDC = CreateCompatibleDC(hDC);
		if (!hMemDC)
		{
			if (bmpMem)
			{
				::DeleteObject(bmpMem);
				bmpMem = NULL;
			}
			::ReleaseDC(GetSafeHwnd(), hDC);
			return;
		}

		hOldObj = ::SelectObject(hMemDC, bmpMem);

		RECT rectTmp = { 0 };

		rectTmp = rcItem;

		MapWindowPoints(GetParent(), &rectTmp);

		if (m_BkImg.IsNull() == false)
			m_BkImg.Draw(hMemDC, 0, 0, rectTmp.right - rectTmp.left, rectTmp.bottom - rectTmp.top, rectTmp.left, rectTmp.top, rectTmp.right - rectTmp.left, rectTmp.bottom - rectTmp.top);

		int nW = rcItem.right - rcItem.left;

		int nH = rcItem.bottom - rcItem.top;

		m_imgFloat.AlphaBlend(hMemDC, 0, 0, nW, nH, 0, 0,nW,nH);

		::BitBlt(hDC, 0, 0, nW, nH, hMemDC, 0, 0, SRCCOPY);

		SelectObject(hMemDC, hOldObj);

		if (bmpMem)
		{
			::DeleteObject(bmpMem);
			bmpMem = NULL;
		}

		if (hMemDC)
		{
			::DeleteDC(hMemDC);
			hMemDC = NULL;
		}

		::ReleaseDC(GetSafeHwnd(), hDC);
	}

	CButton::OnMouseHover(nFlags, point);
}


void CMyButton::OnMouseLeave()
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值

	CButton::OnMouseLeave();
	InvalidateRect(NULL);
	m_bIsInWnd = FALSE;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/468926.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试算法-52-对称二叉树

题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 解 class Solution {public boolean isSymmetric(TreeNode root) {return dfs(root, root);}public boolean dfs(Tr…

8年软件测试工程师感悟 —— 写给还在迷茫中的朋友

这两天和朋友谈到软件测试的发展&#xff0c;其实软件测试已经在不知不觉中发生了非常大的改变&#xff0c;前几年的软件测试行业还是一个风口&#xff0c;随着不断地转行人员以及毕业的大学生疯狂地涌入软件测试行业&#xff0c;目前软件测试行业“缺口”已经基本饱和。当然&a…

【SpringBoot】头条新闻项目实现CRUD登录注册

文章目录 一、头条案例介绍二、技术栈介绍三、前端搭建四、基于SpringBoot搭建项目基础架构4.1 数据库脚本执行4.2 搭建SprintBoot工程4.2.1 导入依赖:4.2.2 编写配置4.2.3 工具类准备 4.3 MybatisX逆向工程 五、后台功能开发5.1 用户模块开发5.1.1 jwt 和 token 介绍5.1.2 jwt…

8.发布页面

发布页面 官网 https://vkuviewdoc.fsq.pub/components/form.html 复制官网中的内容 代码 write.vue <template><view class"u-wrap u-p-l-20 u-p-r-20"><u-form :model"addModel" ref"form1"><u-form-item label&quo…

SegFormer 项目排坑记录

SegFormer 项目排坑记录 任务记录创建conda环境 准备数据库和预训练参数程序配置修改测试可视化训练 任务 需要复现SegFormer分割项目&#xff0c;似乎还有点麻烦&#xff0c;参考这几个进行复现&#xff0c;记录下过程&#xff1a; SegFormer mmsegmentation CSDN博客 知乎博…

CentOS的安装

一、打开VMware的WorkStation的软件界面。点击创建新的虚拟机。 二、我们选择自定义&#xff0c;下一步。 三、这个界面不用动&#xff0c;直接进入下一步。 四、点击稍后安装操作系统&#xff0c;下一步。 五、选择Linux操作系统&#xff0c;版本为CentOS 7 64位。 六、虚拟机…

备战蓝桥杯Day31 - 真题-管道

题目描述 解题思路 这个问题可以视为一个水波在管道中传播的问题&#xff0c;其中水波以单位速度传播。阀门在 S 时刻打开&#xff0c;水流以单位速度流向管道的右侧&#xff0c;每个传感器位于每段管道的中心。对于位于 Li 的阀门&#xff0c;在 Ti 时刻打开时&#xff0c;水…

Docker Desktop 安装 ClickHouse 超级简单教程

Docker desktop 安装 clickhouse 超级简单 文章目录 Docker desktop 安装 clickhouse 超级简单 什么是 Docker &#xff1f;安装下准备安装Docker配置安装 ClickHouse配置数据库密码DBeaver 测试创建表总结 什么是 Docker &#xff1f; 下载 Docker desktop Docker Desktop …

网络编程:多点通信+域套接字

一、多点通信 1.网络属性 getsockopt和setsockopt int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 功能&#xff1a;获取或设置套接字…

【Pt】ID贴图的基本使用

目标 将小白人样本的脸部区域填充为红色&#xff0c;如下 步骤 1. 首先这里打开一个软件自带的样本 2. 添加一个填充图层 3. 设置Base Color为红色 4. 添加黑色遮罩 5. 鼠标右键点击遮罩&#xff0c;然后添加颜色选择 6. 点击选取颜色就可以看到不同的ID部分 此时鼠标会变为滴…

个人信息的动态表单

有一系列需要勾选的内容&#xff0c;勾选完内容后&#xff0c;会根据勾选内容自动生成一个对应的表单。 不同的勾选内容&#xff0c;生成的表单内容是不一样的。 checkbox勾选方法&#xff1a; private void checkBox1_CheckedChanged(object sender, EventArgs e){this.te…

深入理解nginx连接数限制模块[下]

目录 4 源码分析4.1 配置指令源码分析4.1.1 limit_conn_zone4.1.2 limit_conn4.1.3 limit_conn_log_level4.1.4 limit_conn_status4.1.5 limit_conn_dry_run 4.2 共享内存初始化4.3 模块初始化4.4 请求处理4.5 红黑树的查找4.6 请求关闭的析构函数 关注我的微信公众号: 上接 …

DBSCAN聚类原理及Python实现

文章目录 一、相关术语二、DBSCAN原理2.1 算法思想及步骤2.2 优缺点分析2.3 Python代码 三、运行效率加速 一、相关术语 密度&#xff1a;指定半径内点的个数&#xff1b;核心点&#xff1a;如果某个点的半径邻域epsilon内至少包含minPts个点数&#xff0c;它就是核心点&#…

Spring Security的开发

文章目录 1,介绍2, 核心流程3, 核心原理3.1 过滤器链机制3.2 主体3.3 认证3.4 授权3.5 流程图4, 核心对象4.1 UserDetailsService 接口4.2 PasswordEncoder 接口4.3 hasAuthority方法4.4 hasAnyAuthority方法4.5 hasRole方法4.5 hasAnyRole方法5, 核心注解5.1 @PreAuthorize5.1…

十四、ReadWriteLock

ReadWriteLock 读写锁 又叫排他锁 如果使用互斥锁&#xff0c;一个线程在读&#xff0c;其他线程也不能读也不能写 换成读写锁的时候&#xff0c;读线程是读锁&#xff0c;写线程是写锁&#xff0c;写锁是排他的 在多线程大大提高效率&#xff0c;当一个线程在读的时候&…

MybatisPlus逆向工程

目录 &#x1f9c2;1.前提说明 &#x1f37f;2.引入依赖 &#x1f32d;3.使用导入模板 1.前提说明 注意 适用版本&#xff1a;mybatis-plus-generator 3.5.1 以下版本&#xff0c;3.5.1 及以上的请参考 3.5.1以上参考官网&#xff1a;3.5.1以上逆向工程 2.引入依赖 …

用 二层口 实现三层口 IP 通信的一个实现方法

我们一般用 undo portswitch 来将二层口转为三层口&#xff0c;但如果设备不支持的话&#xff0c;那么。。。 一、拓朴图&#xff1a; 二、实现方法&#xff1a; 起一个 vlan x&#xff0c;配置 vlanif地址&#xff0c;然后二层口划分到 vlan x 下&#xff0c;对端做同样的配置…

C语言 实用调试技巧

我们的博客已经更新到了数据结构&#xff0c;但是当我在深耕数据结构时我发现我在C语言是遗漏了一个重要的东西&#xff0c;那就是C语言的使用调试技巧。这篇博客对数据结构非常重要&#xff0c;请大家耐心观看。 1. 什么是bug&#xff1f; 第一次被发现的导致计算机错误的飞蛾…

Centos虚拟机忘记密码;重置虚机密码

虚拟机是一个好用的工具&#xff0c;在本地搭建的虚拟机可以给我们提供测试&#xff0c;但时间长了也会忘记密码&#xff1b;因此这里以centos系统的虚机为例&#xff0c;提供一个重置虚机密码的方法 1.在开机页面按“E”进入编辑模式 进入后长这样&#xff1a; 2.找到ro cras…

Python面向对象——架构设计【2】

练习1&#xff1a;打电话 请使用面向对象思想描述下列情景: 小明使用手机打电话,还有可能使用座机.... class People:def __init__(self,name):self.name namedef call_up(self,tool):print(self.name,end"")tool.call()class Tools:def __init__(self,way):self.wa…