环境设置:需要有GDIPlus,并设置好相应的路径
程序代码如下:
//stdafx.h
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long*
#endif
#include <GdiPlus.h>
#pragma comment(lib,"GdiPlus.lib")
using namespace Gdiplus;
//你的APP文件(.h)
class C**App : public CWinApp
增加变量 : ULONG_PTR m_gdiplusToken;
增加方法 : virtual int ExitInstance();
//你的APP文件(.cpp)
BOOL C**App::InitInstance()
{
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
****以下默认****
}
int C**App::ExitInstance()
{
Gdiplus::GdiplusShutdown(m_gdiplusToken);
return CWinApp::ExitInstance();
}
下面转入正题:
//ImageButton.h
////////////////////////////////////////////////////////////////////////////
// Origin Author : Darren Sessions //
// Origin Class : GdipButton //
// http://www.codeproject.com/KB/buttons/GdipButton.aspx //
// Modify: wxy3064one##163.com //
// (1)支持Flat和正常显示 //
// (2)删除了Alter相关的处理 //
// (3)图片居中显示 //
// //
// Date: 2010-5-20 //
////////////////////////////////////////////////////////////////////////////
#pragma once
class CMemDC : public CDC
{
public:
CMemDC(CDC* pDC, const CRect& rect) : CDC(), m_pOldBitmap(NULL), m_pDC(pDC)
{
ASSERT(m_pDC != NULL);
#ifndef WCE_NO_PRINTING
m_bValid = !pDC->IsPrinting();
#else
m_bValid = FALSE;
#endif
if (m_bValid){
if (CreateCompatibleDC(m_pDC))
{
SetMapMode(m_pDC->GetMapMode());
if ( rect == CRect(0,0,0,0) )
pDC->GetClipBox(&m_rc);
else
m_rc = rect;
m_bitmap.CreateCompatibleBitmap(m_pDC, m_rc.Width(), m_rc.Height());
m_pOldBitmap = SelectObject(&m_bitmap);
#ifndef _WIN32_WCE
SetWindowOrg(m_rc.left, m_rc.top);
#endif
}
else
{
m_bValid = FALSE;
m_pOldBitmap = NULL;
}
} else {
#ifndef WCE_NO_PRINTING
m_bPrinting = pDC->m_bPrinting;
#endif
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
}
virtual ~CMemDC()
{
if (m_bValid)
{
m_pDC->BitBlt(m_rc.left, m_rc.top, m_rc.Width(), m_rc.Height(),this, 0, 0, SRCCOPY);
}
if (m_pOldBitmap != NULL)
SelectObject(m_pOldBitmap);
DeleteDC();
}
CRect GetRect() { return m_rc; }
CBitmap& GetBitmap() { return m_bitmap; }
CMemDC* operator->(){ return this; }
operator CMemDC*() { return this; }
void Discard()
{
m_bValid = FALSE;
}
void FromDC()
{
BitBlt(0, 0, m_rc.Width(), m_rc.Height(),m_pDC, m_rc.left, m_rc.top, SRCCOPY);
}
protected:
CDC* m_pDC; // Saves CDC passed in constructor
CRect m_rc; // Rectangle of drawing area.
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_pOldBitmap; // Original GDI object
BOOL m_bValid; // flag for autodraw in dtor
};
/////////////////////////////////////////////////////////////////////////////
// CImageButton window
class CImageButton : public CButton
{
class CGdiPlusBitmap
{
protected:
HGLOBAL m_hBuffer;
Gdiplus::Bitmap* m_pBitmap;
public:
CGdiPlusBitmap() { m_hBuffer = NULL; m_pBitmap = NULL;}
CGdiPlusBitmap(LPCTSTR pName, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
{ m_hBuffer = NULL; m_pBitmap = NULL; Load(pName, pType, hInst); }
CGdiPlusBitmap(UINT id, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
{ m_hBuffer = NULL; m_pBitmap = NULL; Load(id, pType, hInst); }
virtual ~CGdiPlusBitmap() { Empty(); }
inline void Empty(){
delete m_pBitmap;
m_pBitmap = NULL;
if (m_hBuffer)
{
::GlobalUnlock(m_hBuffer);
::GlobalFree(m_hBuffer);
m_hBuffer = NULL;
}
}
inline bool Load(LPCTSTR pName, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
{
Empty();
HRSRC hResource = ::FindResource(hInst, pName, pType);
if (!hResource)
return false;
DWORD imageSize = ::SizeofResource(hInst, hResource);
if (!imageSize)
return false;
const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
if (!pResourceData)
return false;
m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
if (m_hBuffer)
{
void* pBuffer = ::GlobalLock(m_hBuffer);
if (pBuffer)
{
CopyMemory(pBuffer, pResourceData, imageSize);
IStream* pStream = NULL;
if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
{
m_pBitmap = Gdiplus::Bitmap::FromStream(pStream);
pStream->Release();
if (m_pBitmap)
{
if (m_pBitmap->GetLastStatus() == Gdiplus::Ok)
return true;
delete m_pBitmap;
m_pBitmap = NULL;
}
}
::GlobalUnlock(m_hBuffer);
}
::GlobalFree(m_hBuffer);
m_hBuffer = NULL;
}
return false;
}
bool Load(UINT id, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
{ return Load(MAKEINTRESOURCE(id), pType, hInst); }
operator Gdiplus::Bitmap*() const { return m_pBitmap;}
int Width() const{ return m_pBitmap?m_pBitmap->GetWidth():0; }
int Height() const{ return m_pBitmap?m_pBitmap->GetHeight():0; }
};
public:
CImageButton();
virtual ~CImageButton();
void SetFlat(BOOL IsFlat = TRUE);
BOOL LoadImage(UINT id, LPCTSTR pType);
void EnableButton(BOOL bEnable = TRUE) {
EnableWindow(bEnable);
m_bIsDisabled = !bEnable;
}
BOOL IsDisabled(void) {return (m_bIsDisabled == TRUE); }
protected:
void PaintBk(CDC* pDC);
void PaintBtn(CDC* pDC);
BOOL m_bHaveBitmaps;
BOOL m_bIsDisabled;
BOOL m_bIsTracking;
BOOL m_bIsFlat;
BOOL m_bIsHovering;
CGdiPlusBitmap* m_pBitmap;
virtual void PreSubclassWindow();
virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
//{{AFX_MSG(CImageButton)
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnMouseHover(WPARAM wparam, LPARAM lparam) ;
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
CDC m_dcBk; // button background
CDC m_dcStd; // standard button
CDC m_dcStdP; // standard button pressed
CDC m_dcStdH; // standard button hot
CDC m_dcGS; // grayscale button (does not have a hot or pressed state)
CDC* m_pCurBtn; // current pointer to one of the above
};
//ImageButton.cpp
#include "stdafx.h"
#include "ImageButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CImageButton
CImageButton::CImageButton()
{
m_pBitmap = NULL;
m_bHaveBitmaps = FALSE;
m_bIsTracking = FALSE;
m_pCurBtn = NULL;
m_bIsHovering = FALSE;
m_bIsDisabled = FALSE;
m_bIsFlat = FALSE;
}
CImageButton::~CImageButton()
{
if(m_pBitmap) delete m_pBitmap;
}
BEGIN_MESSAGE_MAP(CImageButton, CButton)
//{{AFX_MSG_MAP(CImageButton)
ON_WM_DRAWITEM()
ON_WM_ERASEBKGND()
ON_WM_CTLCOLOR_REFLECT()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CImageButton::SetFlat(BOOL IsFlat)
{
m_bIsFlat = IsFlat;
}
BOOL CImageButton::LoadImage(UINT id, LPCTSTR pType)
{
if (m_pBitmap) delete m_pBitmap;
m_pBitmap = new CGdiPlusBitmap;
return m_pBitmap->Load(id, pType);
}
HBRUSH CImageButton::CtlColor(CDC* pScreenDC, UINT nCtlColor)
{
if(!m_bHaveBitmaps)
{
if(!m_pBitmap)
{
return NULL;
}
CBitmap bmp, *pOldBitmap;
CRect rect;
GetClientRect(rect);
CMemDC pDC(pScreenDC, rect);
Gdiplus::Graphics graphics(pDC->m_hDC);
// background
if (m_dcBk.m_hDC == NULL)
{
CRect rect1;
CClientDC clDC(GetParent());
GetWindowRect(rect1);
GetParent()->ScreenToClient(rect1);
m_dcBk.CreateCompatibleDC(&clDC);
bmp.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height());
pOldBitmap = m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY);
bmp.DeleteObject();
}
// standard image
if (m_dcStd.m_hDC == NULL)
{
PaintBk(pDC);
graphics.DrawImage(*m_pBitmap, 0, 0);
m_dcStd.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcStd.SelectObject(&bmp);
m_dcStd.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
// standard image pressed
if (m_dcStdP.m_hDC == NULL)
{
PaintBk(pDC);
graphics.DrawImage(*m_pBitmap, 1, 1);
m_dcStdP.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcStdP.SelectObject(&bmp);
m_dcStdP.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
// standard image hot
if(m_dcStdH.m_hDC == NULL)
{
PaintBk(pDC);
ColorMatrix HotMat = { 1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.05f, 0.05f, 0.05f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&HotMat);
float width = (float)m_pBitmap->Width();
float height = (float)m_pBitmap->Height();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pBitmap, grect, 0, 0, width, height, UnitPixel, &ia);
m_dcStdH.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcStdH.SelectObject(&bmp);
m_dcStdH.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
// grayscale image
if(m_dcGS.m_hDC == NULL)
{
PaintBk(pDC);
ColorMatrix GrayMat = { 0.30f, 0.30f, 0.30f, 0.00f, 0.00f,
0.59f, 0.59f, 0.59f, 0.00f, 0.00f,
0.11f, 0.11f, 0.11f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.00f, 0.00f, 0.00f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&GrayMat);
float width = (float)m_pBitmap->Width();
float height = (float)m_pBitmap->Height();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pBitmap, grect, 0, 0, width, height, UnitPixel, &ia);
m_dcGS.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcGS.SelectObject(&bmp);
m_dcGS.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
}
if(m_pCurBtn == NULL)
{
m_pCurBtn = &m_dcStd;
}
m_bHaveBitmaps = TRUE;
}
return NULL;
}
void CImageButton::PaintBk(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
}
void CImageButton::PaintBtn(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
int img_width = 0;
int img_height = 0;
if (m_pBitmap != NULL)
{
img_width = m_pBitmap->Width();
img_height = m_pBitmap->Height();
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
}
pDC->BitBlt(rect.left + (rect.Width() - img_width)/2,
rect.top + (rect.Height() - img_height)/2,
rect.Width(), rect.Height(), m_pCurBtn, 0,0,SRCCOPY);
}
void CImageButton::PreSubclassWindow()
{
ModifyStyle(0, BS_OWNERDRAW, SWP_FRAMECHANGED);
CButton::PreSubclassWindow();
}
BOOL CImageButton::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CImageButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
BOOL bIsPressed = (lpDIS->itemState & ODS_SELECTED);
if(m_bIsDisabled)
{
m_pCurBtn = &m_dcGS;
goto F_PAINT_BUTTON;
}
if(bIsPressed)
{
m_pCurBtn = &m_dcStdP;
}
else if(m_bIsHovering)
{
m_pCurBtn = &m_dcStdH;
}
else
{
m_pCurBtn = &m_dcStd;
}
F_PAINT_BUTTON:
PaintBtn(pDC);
if (!m_bIsFlat)
{
CRect itemRect = lpDIS->rcItem;
CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT));
CPen pen3DLight(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));
CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));
CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW));
CPen* pOldPen = pDC->SelectObject(&penBtnHiLight);
pDC->MoveTo(itemRect.left, itemRect.bottom-1);
pDC->LineTo(itemRect.left, itemRect.top);
pDC->LineTo(itemRect.right, itemRect.top);
pDC->SelectObject(pen3DLight);
pDC->MoveTo(itemRect.left+1, itemRect.bottom-1);
pDC->LineTo(itemRect.left+1, itemRect.top+1);
pDC->LineTo(itemRect.right, itemRect.top+1);
pDC->SelectObject(pen3DDKShadow);
pDC->MoveTo(itemRect.left, itemRect.bottom-1);
pDC->LineTo(itemRect.right-1, itemRect.bottom-1);
pDC->LineTo(itemRect.right-1, itemRect.top-1);
pDC->SelectObject(penBtnShadow);
pDC->MoveTo(itemRect.left+1, itemRect.bottom-2);
pDC->LineTo(itemRect.right-2, itemRect.bottom-2);
pDC->LineTo(itemRect.right-2, itemRect.top);
pDC->SelectObject(pOldPen);
}
return;
}
LRESULT CImageButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
{
m_bIsHovering = TRUE;
Invalidate();
return 0;
}
LRESULT CImageButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
{
m_bIsTracking = FALSE;
m_bIsHovering = FALSE;
Invalidate();
return 0;
}
void CImageButton::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bIsTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bIsTracking = _TrackMouseEvent(&tme);
}
CButton::OnMouseMove(nFlags, point);
}
//调用方法
CImageButton m_btnBmp;
m_btnBmp.LoadImage(IDR_PNG1, _T("PNG"));
//备注:
//修改下CGdiPlusBitmap ,也可以支持从文件中读取图像, 这样就比较完备了。 有需要代码的,可以发我的邮箱wxy3064one@163.com