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