您的位置:首页 > 其它

关于VC6 MFC使用Gdiplus实现自绘按钮的总结

2018-10-29 17:24 399 查看

步骤1:简易教程(更换对话框的背景)及Gdiplus下载地址可查看这个博客https://www.geek-share.com/detail/2722448962.html

步骤2:使用Gdiplus实现自绘按钮可参考这个博客https://www.geek-share.com/detail/2669803525.html。

首先感谢上面两位博主的分享,那么我写这个博客是干什么用的呢?有用的东西不都在上面两个博客里面了吗?

emmmm。。。。对,说得对。但是这个博客的作用就是总结而已?贴贴链接什么的。。。。当然不是,第一个博客的确可以直接查看并抄代码就能用了,但是直接使用第二个博客的代码会出现按钮的闪烁现象,三态/四态按钮的显示情况也会有异常,所以我在步骤2中用参考而不是用查看。

先贴自己根据第二个博客修改后得出的代码吧,方便自己以后查找,也方便说下去。

MyPngButton.h文件的代码如下

[code]#if !defined(AFX_MYPNGBUTTON_H__07529129_0130_4E9C_B4D4_D01323B8E290__INCLUDED_)
#define AFX_MYPNGBUTTON_H__07529129_0130_4E9C_B4D4_D01323B8E290__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "gdiplus/GdiPlus.h"
// MyPngButton.h : header file
/////////////////////////////////////////////////////////////////////////////

//按钮的状态
enum
{
CTRL_NOFOCUS = 0x01,            //普通
CTRL_FOCUS,                     //mousemove
CTRL_SELECTED,                  //buttondown
CTRL_DISABLE,                   //无效
};

//图片形式
enum
{
BTN_IMG_1 = 1,                  //只有一张图片
BTN_IMG_3 = 3,                  //3分图(1个图片内有3小图,下同)
BTN_IMG_4 = 4,                  //4分图
};

//按钮类型
enum
{
BTN_TYPE_NORMAL = 0x10,         //普通BTN
BTN_TYPE_MENU,                  //菜单类型的BTN
BTN_TYPE_STATIC,                //静态类型的BTN
};

#define DEF_TEXT_FRAME_COLOR            RGB(255,255,255)                //默认颜色
#define DEF_TEXT_COLOR                  RGB(10,10,10)                   //默认颜色
#define TOOLTIP_ID                      100

class CMyPngButton : public CButton
{
public:
CMyPngButton();
virtual ~CMyPngButton();
public:
// 初始化
void Init(UINT nImg, int nPartNum, UINT nBtnType = BTN_TYPE_NORMAL);
//设置颜色
bool SetTextColor(COLORREF crTextColor, COLORREF crTextFrameColor = DEF_TEXT_FRAME_COLOR, bool bShowFrame = false);
//设置提示
void SetToolTips(LPCTSTR pszTips);
//设置鼠标形状
void SetCursorType(HCURSOR hCursor);
//设置字体大小及类型
void SetFontType(int fontSize, CString fontType);
protected:
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseHOver(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()

protected:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void PreSubclassWindow();
virtual BOOL PreTranslateMessage(MSG * pMsg);
bool ShowImage(CDC* pDC, Gdiplus::Image* pImage, UINT nState);
void PaintParent();
Gdiplus::Image *ImageFromResource(HINSTANCE hInstance, UINT uImgID, LPCTSTR lpType);
void UpdateToolTip();
void DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, LPRECT lpRect);
void DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, int nXPos, int nYPos);

private:
int m_nImgPart;                                 //载入的图片是几块
UINT            m_nState;                       //控件状态
UINT            m_nBtnType;                     //按钮类型
BOOL            m_bMenuOn;                      //是否按下
BOOL            m_bTracked;                     //是否移动
BOOL            m_bShowTextFrame;               //是否显示艺术字体
COLORREF        m_crTextColor;                  //字体颜色
COLORREF        m_crTextFrameColor;             //艺术字体边缘颜色
CString         m_strTips;                      //提示
HCURSOR         m_cursor;                       //光标
CToolTipCtrl    m_ToolTip;                      //提示控件
Gdiplus::Image* m_pImage;                       //背景图片
CFont           m_font;                         //字体
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MYPNGBUTTON_H__07529129_0130_4E9C_B4D4_D01323B8E290__INCLUDED_)

MyPngButton.cpp文件的代码如下

[code]// MyPngButton.cpp : implementation file

#include "stdafx.h"
#include "MyPngButton.h"
using namespace Gdiplus;
/////////////////////////////////////////////////////////////////////////////
// CMyPngButton
CMyPngButton::CMyPngButton()
{
m_bTracked = FALSE;
m_bMenuOn = FALSE;
m_nImgPart = 0;
m_pImage = NULL;
m_nState = CTRL_NOFOCUS;
m_nBtnType = BTN_TYPE_NORMAL;
m_bShowTextFrame = FALSE;
m_crTextColor = DEF_TEXT_COLOR;
m_crTextFrameColor = DEF_TEXT_FRAME_COLOR;
m_cursor = ::LoadCursor(NULL, IDC_ARROW);
}

CMyPngButton::~CMyPngButton()
{
if (m_pImage != NULL)
{
delete m_pImage;
m_pImage = NULL;
}
}

void CMyPngButton::Init(UINT nImg, int nPartNum, UINT nBtnType)
{
m_pImage = ImageFromResource(AfxGetResourceHandle(), nImg, _T("PNG"));
m_nBtnType = nBtnType;
m_nImgPart = nPartNum;

if (m_pImage == NULL)
return;

CRect rcButton;

if (m_nImgPart == BTN_IMG_1)
rcButton = CRect(0, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
else if (m_nImgPart == BTN_IMG_3)
rcButton = CRect(0, 0, m_pImage->GetWidth() / 3, m_pImage->GetHeight());
else if (m_nImgPart == BTN_IMG_4)
rcButton = CRect(0, 0, m_pImage->GetWidth() / 4, m_pImage->GetHeight());
else
return;

SetWindowPos(NULL, 0, 0, rcButton.Width(), rcButton.Height(), SWP_NOACTIVATE | SWP_NOMOVE);
}

BEGIN_MESSAGE_MAP(CMyPngButton, CButton)
//{{AFX_MSG_MAP(CMyPngButton)
ON_WM_ERASEBKGND()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_PAINT()
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHOver)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
//}}AFX_MSG_MAP
ON_WM_SETCURSOR()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyPngButton message handlers

void CMyPngButton::OnPaint()
{
CButton::OnPaint();
}

void CMyPngButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (!IsWindowEnabled())
m_nState = CTRL_DISABLE;
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
ShowImage(&dc, m_pImage, m_nState);
dc.Detach();
}

bool CMyPngButton::ShowImage(CDC* pDC, Image* pImage, UINT nState)
{
bool bSuc = false;

if (pImage != NULL)
{
CRect rcButton;
if (m_nImgPart == BTN_IMG_1)
rcButton = CRect(0, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
else if (m_nImgPart == BTN_IMG_3)
{
if (nState == CTRL_NOFOCUS)
rcButton = CRect(0, 0, m_pImage->GetWidth() / 3, m_pImage->GetHeight());
else if (nState == CTRL_FOCUS)
rcButton = CRect(m_pImage->GetWidth() / 3, 0, m_pImage->GetWidth() / 3 * 2, m_pImage->GetHeight());
else if (nState == CTRL_SELECTED)
rcButton = CRect(m_pImage->GetWidth() / 3 * 2, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
else
return false;
}
else if (m_nImgPart == BTN_IMG_4)
{
if (nState == CTRL_NOFOCUS)
rcButton = CRect(0, 0, m_pImage->GetWidth() / 4, m_pImage->GetHeight());
else if (nState == CTRL_FOCUS)
rcButton = CRect(m_pImage->GetWidth() / 4, 0, m_pImage->GetWidth() / 4 * 2, m_pImage->GetHeight());
else if (nState == CTRL_SELECTED)
rcButton = CRect(m_pImage->GetWidth() / 4 * 2, 0, m_pImage->GetWidth() / 4 * 3, m_pImage->GetHeight());
else if (nState == CTRL_DISABLE)
rcButton = CRect(m_pImage->GetWidth() / 4 * 3, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
else
return false;
}
else
return false;
pDC->SetBkMode(TRANSPARENT);
Graphics graph(pDC->GetSafeHdc());
graph.DrawImage(pImage, RectF(0.0, 0.0, float(rcButton.Width()),
float(rcButton.Height())), float(rcButton.left), float(rcButton.top),
float(rcButton.Width()), float(rcButton.Height()), UnitPixel);
graph.ReleaseHDC(pDC->GetSafeHdc());
//绘画字体
CString szText;
GetWindowText(szText);
CRect txtRc(0, 0, rcButton.Width(), rcButton.Height());
CFont* oldFont = pDC->SelectObject(m_font.GetSafeHandle() ? &m_font : GetFont());
if (!m_bShowTextFrame)
{
pDC->SetTextColor(m_crTextColor);
pDC->DrawText(szText, szText.GetLength(), &txtRc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_TABSTOP);
}
else
{
//艺术字体
DrawTextString(pDC, szText, m_crTextColor, m_crTextFrameColor, &txtRc);
}
pDC->SelectObject(oldFont);
bSuc = true;
}
return bSuc;
}

Image *CMyPngButton::ImageFromResource(HINSTANCE hInstance, UINT uImgID, LPCTSTR lpType)
{
HRSRC hResInfo = ::FindResource(hInstance, MAKEINTRESOURCE(uImgID), lpType);
if (hResInfo == NULL)
return NULL; //fail
DWORD dwSize;
dwSize = SizeofResource(hInstance, hResInfo); //get resource size(bytes)
HGLOBAL hResData;
hResData = ::LoadResource(hInstance, hResInfo);
if (hResData == NULL)
return NULL; //fail
HGLOBAL hMem;
hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
if (hMem == NULL) {
::FreeResource(hResData);
return NULL;
}
LPVOID lpResData, lpMem;
lpResData = ::LockResource(hResData);
lpMem = ::GlobalLock(hMem);
::CopyMemory(lpMem, lpResData, dwSize); //copy memory
::GlobalUnlock(hMem);
::FreeResource(hResData); //free memory

IStream *pStream;
HRESULT hr;
hr = ::CreateStreamOnHGlobal(hMem, TRUE, &pStream);//create stream object
Image *pImage = NULL;
if (SUCCEEDED(hr)) {
pImage = Image::FromStream(pStream);//get GDI+ pointer
pStream->Release();
}
::GlobalFree(hMem);
return pImage;
}

void CMyPngButton::PreSubclassWindow()
{
ModifyStyle(0, BS_OWNERDRAW);

if (NULL != GetSafeHwnd())
{
if (!(GetButtonStyle() & WS_CLIPSIBLINGS))
SetWindowLong(GetSafeHwnd(), GWL_STYLE, GetWindowLong(GetSafeHwnd(),
GWL_STYLE) | WS_CLIPSIBLINGS);
}

CButton::PreSubclassWindow();
}

//消息解释
BOOL CMyPngButton::PreTranslateMessage(MSG * pMsg)
{
if (m_ToolTip.m_hWnd != NULL)
m_ToolTip.RelayEvent(pMsg);
return CButton::PreTranslateMessage(pMsg);
}

//设置提示
void CMyPngButton::SetToolTips(LPCTSTR pszTips)
{
m_strTips = pszTips;
UpdateToolTip();
}

//更新提示
void CMyPngButton::UpdateToolTip()
{
if (GetSafeHwnd())
{
if (m_ToolTip.GetSafeHwnd() == NULL) m_ToolTip.Create(this);
if (m_strTips.IsEmpty() == false)
{
CRect ClientRect;
GetClientRect(&ClientRect);
m_ToolTip.Activate(TRUE);
m_ToolTip.AddTool(this, m_strTips, &ClientRect, TOOLTIP_ID);
}
else m_ToolTip.Activate(FALSE);
}
return;
}

//设置颜色
bool CMyPngButton::SetTextColor(COLORREF crTextColor, COLORREF crTextFrameColor, bool bShowFrame)
{
m_crTextColor = crTextColor;
m_bShowTextFrame = bShowFrame;
m_crTextFrameColor = crTextFrameColor;

if (GetSafeHwnd()) Invalidate(FALSE);
return true;
}

void CMyPngButton::SetCursorType(HCURSOR hCursor)
{
m_cursor = hCursor;
}

//光标消息
BOOL CMyPngButton::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
{
::SetCursor(m_cursor);
return TRUE;
}

void CMyPngButton::SetFontType(int fontSize, CString fontType)
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = fontSize;
_tcsncpy(lf.lfFaceName, fontType, fontType.GetLength());
VERIFY(m_font.CreateFontIndirect(&lf));
}

BOOL CMyPngButton::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}

void CMyPngButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (!m_bTracked)
{
TRACKMOUSEEVENT tme;
ZeroMemory(&tme, sizeof(TRACKMOUSEEVENT));
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 1;
tme.hwndTrack = this->GetSafeHwnd();
if (::_TrackMouseEvent(&tme))
m_bTracked = TRUE;
}

CButton::OnMouseMove(nFlags, point);
}

void CMyPngButton::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_nState != CTRL_SELECTED)
{
m_nState = CTRL_SELECTED;

if (!m_bMenuOn)
m_bMenuOn = TRUE;

PaintParent();
}

CButton::OnLButtonDown(nFlags, point);
}

void CMyPngButton::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_nState != CTRL_FOCUS)
{
m_nState = CTRL_FOCUS;
PaintParent();
}

CButton::OnLButtonUp(nFlags, point);
}

LRESULT CMyPngButton::OnMouseHOver(WPARAM wParam, LPARAM lParam)
{
//鼠标放上去时
if (m_nState != CTRL_FOCUS)
{
m_nState = CTRL_FOCUS;
PaintParent();
}

return 0;
}

LRESULT CMyPngButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
//鼠标移开时
m_bTracked = FALSE;

if (m_nBtnType == BTN_TYPE_NORMAL)
m_nState = CTRL_NOFOCUS;
else if (m_nBtnType == BTN_TYPE_MENU)
{
if (m_bMenuOn)
m_nState = CTRL_SELECTED;
else
m_nState = CTRL_NOFOCUS;
}

PaintParent();
return 0;
}

void CMyPngButton::PaintParent()
{
/*
CRect   rect;
GetWindowRect(&rect);
GetParent()->ScreenToClient(&rect);
GetParent()->InvalidateRect(&rect);
*/
CRect   rect;
GetWindowRect(&rect);
ScreenToClient(&rect);
InvalidateRect(&rect);
}

//艺术字体
void CMyPngButton::DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, LPRECT lpRect)
{
//变量定义
int nStringLength = lstrlen(pszString);
int nXExcursion[8] = { 1,1,1,0,-1,-1,-1,0 };
int nYExcursion[8] = { -1,0,1,1,1,0,-1,-1 };
//绘画边框
pDC->SetTextColor(crFrame);
CRect rcDraw;
for (int i = 0; i < sizeof(nXExcursion) / sizeof(nXExcursion[0]); ++i)
{
rcDraw.CopyRect(lpRect);
rcDraw.OffsetRect(nXExcursion[i], nYExcursion[i]);
pDC->DrawText(pszString, nStringLength, &rcDraw, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
//绘画字体
rcDraw.CopyRect(lpRect);
pDC->SetTextColor(crText);
pDC->DrawText(pszString, nStringLength, &rcDraw, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
return;
}

//艺术字体
void CMyPngButton::DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, int nXPos, int nYPos)
{
//变量定义
int nStringLength = lstrlen(pszString);
int nXExcursion[8] = { 1,1,1,0,-1,-1,-1,0 };
int nYExcursion[8] = { -1,0,1,1,1,0,-1,-1 };
//绘画边框
pDC->SetTextColor(crFrame);
for (int i = 0; i < sizeof(nXExcursion) / sizeof(nXExcursion[0]); i++)
{
pDC->TextOut(nXPos + nXExcursion[i], nYPos + nYExcursion[i], pszString, nStringLength);
}

//绘画字体
pDC->SetTextColor(crText);
pDC->TextOut(nXPos, nYPos, pszString, nStringLength);
return;
}

那么代码上面跟第二个博客哪里不一样了呢?就是下面这里

[code]void CMyPngButton::PaintParent()
{
/*
CRect   rect;
GetWindowRect(&rect);
GetParent()->ScreenToClient(&rect);
GetParent()->InvalidateRect(&rect);
*/
CRect   rect;
GetWindowRect(&rect);
ScreenToClient(&rect);
InvalidateRect(&rect);
}

注释掉的就是第二个博客中的原来的代码,下面的是我修改后的代码。出现闪烁以及三态/四态异常的原因就是,这个函数重绘的地方出现了错误,应该是重绘按钮而不是重绘父窗体。

那么应该怎么使用上面这个类呢。(在APP类的InitInstance函数中调用GdiplusStartup、ExitInstance函数中调用GdiplusShutdown函数之类的入门的东西就去看第一个博客就行了,链接在文章的开头。)

先把PNG图片加载到MFC的资源管理中,MFC按钮绑定该类之后,在OnInitDialog函数中调用按钮的init函数即可。示例如下

[code]        m_idok.Init(IDR_OK_PNG, 3);
m_idok.SetWindowPos(NULL, 100, 100, 0, 0, SWP_NOSIZE);

需要注意的是,这个类默认PNG图片的资源种类为PNG(感觉有点像废话了,会有人把PNG图片的资源种类不命名为PNG吗。。。。)。

恩,上面就是今天花费了一个下午搞掂VC6 MFC Gdiplus自绘按钮弄出来的总结。如果上面有代码错误或解释错误、运行错误等问题,请轻喷,因为博主也是个菜鸟而已=_=。

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: