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

news2024/11/28 14:33:48

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go——切片

1. 特点 slice并不是数组或数组指针。它通过内部指针和相关属性引用数组片段&#xff0c;以实现变长方案。 切片&#xff1a;切片是数组的一个引用&#xff0c;因此切片是引用类型。但自身是结构体&#xff0c;值拷贝传递。切片的长度可以改变&#xff0c;因此&#xff0c;切片…

arm 解决Rk1126 画框颜色变色问题(RGB转NV12)

在Rv1126上直接对Nv12图像进行绘制时&#xff0c;颜色是灰色。故将Nv12转BGR后绘制图像&#xff0c;绘制完成后转成Nv12&#xff0c;BGR的图像颜色是正常的&#xff0c;但是NV12的图像颜色未画全&#xff0c;如图&#xff1a; 1.排查发现是RGB转NV12的函数出现问题&#xff0c…

Springboot+vue的仓库管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的仓库管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…

深入理解栈和队列(一):栈

个人主页&#xff1a;17_Kevin-CSDN博客 专栏&#xff1a;《数据结构》 一、栈的概念 栈&#xff08;Stack&#xff09;是一种特殊的线性表&#xff0c;它遵循后进先出&#xff08;Last-In-First-Out&#xff0c;LIFO&#xff09;的原则。栈可以被看作是一个只能在一端进行操作…

记录解决问题--activiti8.2 流程图图片由png改为svg前端不显示图片问题

1.说明 如果是vue svg显示&#xff0c;请查阅其他标准资料&#xff0c;类似使用svg标签。我这里讲的另外一种情况&#xff0c;链接返回的是svg文件&#xff0c;需要用v-html显示图片。 2.activiti6流程图图片格式 ①png格式。可以查看链接返回&#xff0c;以png开头。 ②前端…

如何查看局域网内所有的ip和对应的mac地址

1、windows下查看 方法一、 按快捷键“winr”打开运行界面&#xff0c;输入“CMD”回车: 输入以下命令&#xff1a; for /L %i IN (1,1,254) DO ping -w 1 -n 1 192.168.0.%i 其中 192.168.0.%i 部分要使用要查询的网段&#xff0c;比如 192.168.1.%i 192.168.137.%i 172.16.2…

Nginx日志分割实战指南:让日志管理更轻松

Nginx默认没有提供对日志文件的分割功能&#xff0c;所以随着时间的增长&#xff0c;access.log和error.log文件会越来越大&#xff0c;尤其是access.log&#xff0c;其日志记录量比较大&#xff0c;更容易增长文件大小&#xff0c;影响日志写入性能。 分割Nginx日志的方法有很…

上位机图像处理和嵌入式模块部署(qmacvisual图像预处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 不管大家是在读书的时候学习的图像处理&#xff0c;还是在后来的工作中&#xff0c;重新学习了图像处理&#xff0c;相信大家对图像预处理的概念并…

2024年国内彩妆行业市场数据分析:增长机会在哪?

从伊蒂之屋、菲诗小铺等平价韩妆的退出&#xff0c;到全球第一眉妆贝玲妃的落幕&#xff0c;曾经的“网红”-“全网断货选手”纷纷退出中国市场。 有人认为是国内彩妆市场不景气&#xff1f;事实上&#xff0c;国内彩妆市场线上市场规模仍在持续扩大。根据鲸参谋数据统计&…

梅森增益与劳斯稳定判据

梅森增益&#xff1a; 注意前两行的系数&#xff0c;第一行是偶次项&#xff0c;从高幂走向低幂&#xff1b;第二行是奇次项&#xff0c;从高幂走向低幂。 第一中情况&#xff1a; 第二种情况&#xff1a; 讲的真的很好&#xff0c;受益颇多&#xff1a; https://www.bilibili…

整蛊小教程|让朋友手足无措的电脑自动关机

前言 这几天讲到shutdown关机命令&#xff0c;于是就出现了整蛊类的电脑教程。 这个故事我记得很清楚&#xff1a;在2012年的春天……当时的小白对电脑还不是很熟悉。某一天跟着朋友去网吧上网&#xff0c;这时候突然有个朋友发来一个.bat的文件&#xff0c;说双击打开有惊喜…

FX-数组的使用

1一维数组 1.1一维数组的创建和初始化 1.1.1数组的创建 //代码1 int arr1[10]; char arr2[10]; float arr3[1]; double arr4[20]; //代码2 //用宏定义的方式 #define X 3 int arr5[X]; //代码3 //错误使用 int count 10; int arr6[count];//数组时候可以正常创建&#xff1…

供应链安全之被忽略的软件质量管理平台安全

背景 随着我国信息化进程加速&#xff0c;网络安全问题更加凸显。关键信息基础设施和企业单位在满足等保合规的基础上&#xff0c;如何提升网络安全防御能力&#xff0c;降低安全事件发生概率&#xff1f;默安玄甲实验室针对SonarQube供应链安全事件进行分析&#xff0c;强调供…

系统资源耗尽对服务器的影响有什么?

在当今数字化时代&#xff0c;服务器作为核心计算设备&#xff0c;为企业和组织的业务连续性提供了重要保障。然而&#xff0c;随着业务的增长和复杂性的提升&#xff0c;服务器也面临着越来越多的挑战。其中&#xff0c;系统资源耗尽是服务器面临的一个重要问题。今天德迅云安…

中间件-消息队列

消息队列基础知识 什么是消息队列 本处提到的消息队列是指各个服务以及系统组件/模块之间的通信&#xff0c;属于一种中间件。参与消息传递的双方称为生产者和消费者&#xff0c;生产者负责发送消息&#xff0c;消费者负责处理消息。 消息队列作用 通过异步处理&#xff0…

五、C#归并排序算法

简介 归并排序是一种常见的排序算法&#xff0c;它采用分治法的思想&#xff0c;在排序过程中不断将待排序序列分割成更小的子序列&#xff0c;直到每个子序列中只剩下一个元素&#xff0c;然后将这些子序列两两合并排序&#xff0c;最终得到一个有序的序列。 归并排序实现原…

JVM常用垃圾收集器

JVM 4.1 哪些对象可以作为GC ROOT? 虚拟机栈&#xff08;栈帧中的局部变量表&#xff09;中引用的对象本地方法栈中引用的对象方法区静态变量引用的对象方法区常量引用的对象被同步锁持有的对象JNI&#xff08;Java Native Interface&#xff09;引用的对象 4.2 常用垃圾收集…

2.28CACHE,虚拟存储器

主存储器,简称主存。CPU可以直接随机地对其进行访问&#xff0c;也可以和高速缓存器及辅助存储器交换数据。 2> 辅助存储器,简称辅存&#xff0c;不能与CPU直接相连&#xff0c;用来存放当前暂时不用的程序和数据 3> 高速缓冲存储器,位于主存和CPU之间&#xff0c;用来…

Cesium:按行列绘制3DTiles的等分线

作者:CSDN @ _乐多_ 本文将介绍如何使用 Cesium 引擎根据模型的中心坐标,半轴信息,绘制 3DTiles 对象的外包盒等分线。 外包盒是一个定向包围盒(Oriented Bounding Box),它由一个中心点(center)和一个包含半轴(halfAxes)组成。半轴由一个3x3的矩阵表示,这个矩阵是…

基于Spring boot食品安全信息管理系统

摘 要 食品安全信息管理系统设计的目的是为用户提供食品信息、科普专栏、食品检测、检测结果、交流论坛等方面的平台。 与PC端应用程序相比&#xff0c;食品安全信息管理系统的设计主要面向于用户&#xff0c;旨在为管理员和用户提供一个食品安全信息管理系统。用户可以通过AP…