VC++自绘不太熟,搞了大半天终于实现了。
自己全部画控件又不能用VS的界面工具箱直接放弃,还是只能在MFC的基础上拓展吧。
使用简单的说明一下。首先要在stdafx.h中添加以下代码
#ifndef GDIPLUS #define GDIPLUS #include <gdiplus.h> using namespace Gdiplus; #pragma comment(lib, "gdiplus.lib") #endif
//不添加此代码对IMAGE创建返回一直为NULL ULONG_PTR gdiplusToken; GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
添加一个变量,类型为CBUTTONEX,也可以手动附加,里面有Attach函数,关联到界面的BUTTON
.h文件
#pragma once #include "resource.h" // CButtonEx class CButtonEx : public CButton { public: Image *m_pImage; Image *m_pTemp; CSize m_sizeImage; char szTitle[MAX_PATH]; enumButtonState m_buttonState; CRect m_rc; UINT m_frameCount; CButtonEx(); virtual ~CButtonEx(); void SetBitmap(UINT nResourceID=IDB_PNG_DEFAULT,UINT nFrameCount=4); virtual void OnFinalRelease(); protected: DECLARE_MESSAGE_MAP() public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); BOOL Attach(const UINT nID, CWnd* pParent); void OnLButtonDown(UINT nFlags, CPoint point); void OnLButtonUp(UINT nFlags, CPoint point); void OnMouseMove(UINT nFlags, CPoint point); void DrawContent(CDC &MemDC); afx_msg void OnMouseLeave(); afx_msg BOOL OnEraseBkgnd(CDC* pDC); virtual void PreSubclassWindow(); };
// ButtonEx.cpp : 实现文件 // #include "stdafx.h" #include "ButtonEx.h" // CButtonEx CButtonEx::CButtonEx() { m_pImage = NULL; m_pTemp = NULL; m_buttonState = bsNormal; } CButtonEx::~CButtonEx() { if(m_pImage != NULL) delete m_pImage; if(m_pTemp != NULL) delete m_pTemp; } void CButtonEx::OnFinalRelease() { // 释放了对自动化对象的最后一个引用后,将调用 // OnFinalRelease。基类将自动 // 删除该对象。在调用该基类之前,请添加您的 // 对象所需的附加清理代码。 CWnd::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CButtonEx, CWnd) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_MOUSELEAVE() ON_WM_ERASEBKGND() END_MESSAGE_MAP() void CButtonEx::SetBitmap(UINT nResourceID,UINT nFrameCount) { ImageFromID(nResourceID,m_pImage); this->m_frameCount = nFrameCount; m_sizeImage.SetSize(m_pImage->GetWidth() / m_frameCount, m_pImage->GetHeight()); } // CButtonEx 消息处理程序 void CButtonEx::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CWnd::OnLButtonDown(nFlags, point); m_buttonState = bsDown; Invalidate(); } void CButtonEx::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CWnd::OnLButtonUp(nFlags, point); if (m_buttonState == bsDown) { if(IsWindowEnabled()) m_buttonState = bsHover; else m_buttonState = bsDisable; } } void CButtonEx::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CWnd::OnMouseMove(nFlags, point); //TRACKMOUSEEVENT不加此结构体OnMouseLeave不会被调用 TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.hwndTrack = this->m_hWnd; tme.dwFlags = TME_LEAVE | TME_HOVER; _TrackMouseEvent(&tme); m_buttonState = bsHover; Invalidate(); } void CButtonEx::OnMouseLeave() { // TODO: 在此添加消息处理程序代码和/或调用默认值 CButton::OnMouseLeave(); if(IsWindowEnabled()) m_buttonState = bsNormal; else m_buttonState = bsDisable; Invalidate(); } //手动附加到窗口控件 BOOL CButtonEx::Attach(const UINT nID, CWnd* pParent) { if (!SubclassDlgItem(nID, pParent)) return FALSE; return TRUE; } void CButtonEx::DrawContent(CDC &MemDC) { Graphics g(MemDC); g.DrawImage(m_pTemp,0,0); if((UINT)m_buttonState < m_frameCount) DrawImageFrame(g, m_pImage, m_rc, m_buttonState*(REAL)m_sizeImage.cx, 0, (REAL)m_sizeImage.cx, (REAL)m_sizeImage.cy, 3); COLORREF clrOld = MemDC.SetTextColor(RGB(0, 28, 48)); CFont *pOldFont = MemDC.SelectObject(GetFont()); MemDC.DrawText(szTitle, &m_rc, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS); MemDC.SelectObject(pOldFont); MemDC.SetTextColor(clrOld); } void CButtonEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC *pDc = GetDC(); // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CButton::OnPaint() pDc->SetBkMode(TRANSPARENT); CRect rcClient; GetClientRect(&rcClient); CDC MemDC; MemDC.CreateCompatibleDC(pDc); MemDC.SetBkMode(TRANSPARENT);//不设置透明文字会有背景 CBitmap memBmp; memBmp.CreateCompatibleBitmap(pDc, rcClient.Width(), rcClient.Height()); CBitmap *pOldmap = MemDC.SelectObject(&memBmp); //先填充一下原先的背景 //MemDC.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), pDc, 0, 0, SRCCOPY); DrawContent(MemDC);//直接画无背景 //复制到原来的CDC pDc->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &MemDC, 0, 0, SRCCOPY); //MemDC.SelectObject(pOldmap); //旧图应该是不存在的,直接删除 pOldmap->DeleteObject(); MemDC.DeleteDC(); memBmp.DeleteObject(); ReleaseDC(&MemDC); ReleaseDC(pDc); } BOOL CButtonEx::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //不要背景 // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CButton::OnPaint() CDC MemDC; CBitmap memBmp; MemDC.CreateCompatibleDC(pDC); memBmp.CreateCompatibleBitmap(pDC, m_rc.Width(), m_rc.Height()); CBitmap *pOldmap = MemDC.SelectObject(&memBmp); //先填充一下原先的背景 MemDC.BitBlt(m_rc.left, m_rc.top, m_rc.Width(), m_rc.Height(), pDC, 0, 0, SRCCOPY); //绘制内容 if(m_pTemp == NULL) BitmapToImage(&memBmp,m_pTemp); //旧图应该是黑的无用,直接删除 pOldmap->DeleteObject(); MemDC.DeleteDC(); memBmp.DeleteObject(); ReleaseDC(&MemDC); return TRUE; } void CButtonEx::PreSubclassWindow() { // TODO: 在此添加专用代码和/或调用基类 SetButtonStyle(GetButtonStyle()|BS_OWNERDRAW);//修改为自绘模式 GetClientRect(&m_rc); GetWindowTextA(szTitle,sizeof(szTitle));//复制内容 SetBitmap(); CButton::PreSubclassWindow(); }
#pragma once #include "stdafx.h" #include "MDraw.h" void BitmapToImage(CBitmap *pBitmap,Image* &img) { //拿到位图的句柄 Bitmap是Image的子类 HBITMAP hBmp = (HBITMAP)pBitmap->GetSafeHandle(); //创建一个从位图句柄的Bitmap位图 Bitmap *bmp = new Bitmap(hBmp,NULL); //创建一个临时的位图 Bitmap *temp = new Bitmap(bmp->GetWidth(),bmp->GetHeight(),PixelFormat24bppRGB); Graphics g(temp);//临时位图的画笔 g.DrawImage(bmp,0,0);//将数据画到临时位图上 img = temp; //最后删除位图不然会内存泄漏 delete bmp; } void ImageFromID(int IDB_ID,Image* &_outImg) { LPCTSTR lpType = "PNG"; if(lpType == RT_BITMAP) { //GDI+ can not load RT_BITMAP resouce, //because they are predefined resource, //they don't contains the image file header. return; } HINSTANCE hInst = AfxGetResourceHandle(); HRSRC hRsrc = ::FindResource(hInst,MAKEINTRESOURCE(IDB_ID),lpType); if (!hRsrc) return; DWORD len = SizeofResource(hInst, hRsrc); BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc); if (!lpRsrc) return; HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len); BYTE* pmem = (BYTE*)GlobalLock(m_hMem); memcpy(pmem,lpRsrc,len); IStream* pstm; if (CreateStreamOnHGlobal(m_hMem,FALSE,&pstm) == S_OK) { _outImg = new Image(pstm); GlobalUnlock(m_hMem); pstm->Release(); } FreeResource(lpRsrc); } // 画图片边框 void DrawImageFrame(Graphics &graphics, Image *pIamge, const CRect &rcControl, REAL nX, REAL nY, REAL nW, REAL nH, REAL nFrameSide/* = 3*/) { // 左上角 graphics.DrawImage(pIamge, RectF((REAL)rcControl.left ,(REAL)rcControl.top, nFrameSide, nFrameSide), nX, nY, nFrameSide, nFrameSide, UnitPixel); // 左中边框 graphics.DrawImage(pIamge, RectF((REAL)rcControl.left ,(REAL)rcControl.top + nFrameSide, nFrameSide, (REAL)rcControl.Height() - 2 * nFrameSide), nX, nY + nFrameSide, nFrameSide, nH - 2 * nFrameSide, UnitPixel); // 左下角 graphics.DrawImage(pIamge, RectF((REAL)rcControl.left ,(REAL)rcControl.bottom - nFrameSide, nFrameSide, nFrameSide), nX, nY + nH - nFrameSide, nFrameSide, nFrameSide, UnitPixel); // 上中边框 graphics.DrawImage(pIamge, RectF((REAL)rcControl.left + nFrameSide ,(REAL)rcControl.top, (REAL)rcControl.Width() - 2 * nFrameSide, nFrameSide), nX + nFrameSide, nY, nW - 2 * nFrameSide, nFrameSide, UnitPixel); // 右上角 graphics.DrawImage(pIamge, RectF((REAL)rcControl.right - nFrameSide ,(REAL)rcControl.top, nFrameSide, nFrameSide), nX + nW - nFrameSide, nY, nFrameSide, nFrameSide, UnitPixel); // 右中边框 graphics.DrawImage(pIamge, RectF((REAL)rcControl.right - nFrameSide ,(REAL)rcControl.top + nFrameSide, nFrameSide, (REAL)rcControl.Height() - 2 * nFrameSide), nX + nW - nFrameSide, nY + nFrameSide, nFrameSide, nH - 2 * nFrameSide, UnitPixel); // 右下角 graphics.DrawImage(pIamge, RectF((REAL)rcControl.right - nFrameSide ,(REAL)rcControl.bottom - nFrameSide, nFrameSide, nFrameSide), nX + nW - nFrameSide, nY + nH - nFrameSide, nFrameSide, nFrameSide, UnitPixel); // 下中边框 graphics.DrawImage(pIamge, RectF((REAL)rcControl.left + nFrameSide ,(REAL)rcControl.bottom - nFrameSide, (REAL)rcControl.Width() - 2 * nFrameSide, nFrameSide), nX + nFrameSide, nY + nH - nFrameSide, nW - 2 * nFrameSide, nFrameSide, UnitPixel); // 中间 graphics.DrawImage(pIamge, RectF((REAL)rcControl.left + nFrameSide ,(REAL)rcControl.top + nFrameSide, (REAL)rcControl.Width() - 2 * nFrameSide, (REAL)rcControl.Height() - 2 * nFrameSide), nX + nFrameSide, nY + nFrameSide, nW - 2 * nFrameSide,nH - 2 * nFrameSide, UnitPixel); }