图像按钮的实现 CImageButton

本文介绍如何在C++中使用GDI+库创建一个图像按钮类CImageButton,包括加载图像、平铺显示、鼠标交互效果等功能。通过示例代码详细展示了按钮的绘制过程,包括不同状态(按下、悬浮)的图像处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

环境设置:需要有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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值