关于VC6 MFC使用Gdiplus实现自绘按钮的总结
步骤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自绘按钮弄出来的总结。如果上面有代码错误或解释错误、运行错误等问题,请轻喷,因为博主也是个菜鸟而已=_=。
阅读更多- MFC + CxImage 实现自绘半透明按钮
- MFC自绘按钮的实现
- 关于返回按钮的实现(包括页面的跳转方法总结)
- 关于安卓开发使用AlertDialog实现按钮对话框
- 关于BGT24MR12和HMC703配合使用实现天线扫频的原理和一些配置字计算的总结
- 关于在vc6后续版本MFC程序中使用ActiveX组件
- 使用mfc CWnd 自绘实现一个类似于QQ好友的一个控件
- MFC + CxImage 实现自绘半透明按钮
- 关于慕课网《使用vue2.0实现购物车和地址选配功能》的总结
- VC自绘按钮的实现(NO MFC)
- MFC下按钮自绘的实现(二)
- MFC下按钮自绘的实现
- shiro使用经验总结:【同时实现url和按钮的拦截,只能用配置文件。不需要用注解!!!已多次测试=@RequiresPermissions不能拦截url直接访问。只能拦截标签(鸡肋,不要用!!)
- GdiplusFlat(9)自绘按钮的实现(方法2)
- MFC自绘按钮的实现
- MFC下按钮自绘的实现(一)
- MFC下按钮自绘的实现
- 使用MFC基础控件实现真彩色的按钮
- MFC自绘按钮的实现
- VC自绘按钮的实现(NO MFC)