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

相关推荐

  1. 重排和

    2024-03-22 18:50:02       31 阅读
  2. MFC或QT中,控件的目的和实现步骤

    2024-03-22 18:50:02       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-22 18:50:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-22 18:50:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-22 18:50:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-22 18:50:02       20 阅读

热门阅读

  1. CAS(compare and swap)算法

    2024-03-22 18:50:02       20 阅读
  2. 【NLP5-RNN模型、LSTM模型和GRU模型】

    2024-03-22 18:50:02       17 阅读
  3. tomcat安装及配置教程

    2024-03-22 18:50:02       22 阅读
  4. 【黑马程序员】Python多任务

    2024-03-22 18:50:02       19 阅读
  5. 力扣每日练习(3.20)补

    2024-03-22 18:50:02       15 阅读