[Visual C++] MFC のボタンをマウスオーバーでイメージ切り替えできるようにする

この記事は3年以上前に書かれた記事です。情報が古い可能性があります。

MFC の CButton を継承して、マウスオーバーでイメージが切り替わるボタンをつくったときのコードを、そのまんま以下にメモ。

/** ImageButton.h */
#pragma once
class CImageButton : public CButton
{
  DECLARE_DYNAMIC(CImageButton)
  public:
    CImageButton();
    virtual ~CImageButton();
    void FreeBitmaps();
    void DrawBG(LPDRAWITEMSTRUCT lpDrawItemStruct);
    virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
  protected:
    BOOL m_bHover;
    CBitmap *m_pRestoreBmp;
    CBitmap m_cDefaultBmp;
    CBitmap m_cHoverBmp;
    HBITMAP m_hDefaultBmp;
    HBITMAP m_hHoverBmp;
    HBITMAP LoadBitmapFromFile(const LPCTSTR lpszPath);
  protected:
    DECLARE_MESSAGE_MAP()
  public:
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnMouseHover(UINT nFlags, CPoint point);
    afx_msg void OnMouseLeave();
};

/** ImageButton.cpp */
// ImageButton.cpp : 実装ファイル
//
#include "stdafx.h"
#include "ImageButton.h"

// CImageButton
IMPLEMENT_DYNAMIC(CImageButton, CButton)
CImageButton::CImageButton()
{
  m_bHover = FALSE;
  m_pRestoreBmp = NULL;
  m_hDefaultBmp = NULL;
  m_hHoverBmp = NULL;
}
CImageButton::~CImageButton()
{
  FreeBitmaps();
}

BEGIN_MESSAGE_MAP(CImageButton, CButton)
ON_WM_MOUSEMOVE()
ON_WM_MOUSEHOVER()
ON_WM_MOUSELEAVE()
END_MESSAGE_MAP()

HBITMAP CImageButton::LoadBitmapFromFile(const LPCTSTR lpszPath)
{
  return (HBITMAP)::LoadImage(AfxGetResourceHandle(),
    lpszPathsPath,
    IMAGE_BITMAP,
    0,
    0,
    LR_LOADFROMFILE + LR_CREATEDIBSECTION);
}

void CImageButton::LoadBitmaps(const LPCTSTR lpszDefBmpPath, const LPCTSTR lpszHovrBmpPath)
{
  m_hDefaultBmp = LoadBmp(lpszDefBmpPath);
  m_cDefaultBmp.Attach(m_hDefaultBmp);
  m_hHoverBmp = LoadBmp(lpszHovrBmpPath);
  m_cHoverBmp.Attach(m_hHoverBmp);
}

void CImageButton::FreeBitmaps()
{
  if (m_cDefaultBmp.m_hObject != NULL) {
    m_cDefaultBmp.Detach();
  }
  if (m_cHoverBmp.m_hObject != NULL) {
    m_cHoverBmp.Detach();
  }
  if (m_hDefaultBmp != NULL) {
    ::DeleteObject(m_hDefaultBmp);
    m_hDefaultBmp = NULL;
  }
  if (m_hHoverBmp != NULL) {
    ::DeleteObject(m_hHoverBmp);
    m_hHoverBmp = NULL;
  }
}

void CImageButton::DrawBG(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
  CRect rect = lpDrawItemStruct->rcItem;
  UINT state = lpDrawItemStruct->itemState;
  CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
  CBitmap *pCurrentBmp = &m_cDefaultBmp;
  if (m_cHoverBmp.m_hObject != NULL) {
    if (m_bHover) {
      m_pRestoreBmp = pCurrentBmp;
      pCurrentBmp = &m_cHoverBmp;
    } else {
      pCurrentBmp = m_pRestoreBmp;
    }
  }
  CDC MemDC, SrcDC;
  MemDC.CreateCompatibleDC(pDC);
  SrcDC.CreateCompatibleDC(&MemDC);
  CBitmap *pcOldBmp = SrcDC.SelectObject(pCurrentBmp);
  CRect rBtn;
  GetWindowRect(rBtn);
  CBitmap cMemBmp;
  cMemBmp.CreateCompatibleBitmap(pDC, rBtn.Width(), rBtn.Height());
  CBitmap* pcOldMemBmp = MemDC.SelectObject(&cMemBmp);
  MemDC.BitBlt(0, 0, rBtn.Width(), rBtn.Height(), &SrcDC, 0, 0, SRCCOPY);
  pDC->BitBlt(0, 0, rBtn.Width(), rBtn.Height(), &MemDC, 0, 0, SRCCOPY);
  MemDC.SelectObject(pcOldMemBmp);
  SrcDC.SelectObject(pcOldBmp);
  MemDC.DeleteDC();
  SrcDC.DeleteDC();
}

void CImageButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
  DrawBG(lpDrawItemStruct);  // XXX その他の描画処理
}

// CImageButton メッセージ ハンドラー
void CImageButton::OnMouseMove(UINT nFlags, CPoint point)
{
  TRACKMOUSEEVENT evt;
  evt.cbSize = sizeof(evt);
  evt.dwFlags = TME_HOVER | TME_LEAVE;
  evt.hwndTrack = this->GetSafeHwnd();
  evt.dwHoverTime = 1;
  ::TrackMouseEvent(&evt);
  __super::OnMouseMove(nFlags, point);
}

void CImageButton::OnMouseHover(UINT nFlags, CPoint point)
{
  //__super::OnMouseHover(nFlags, point);
  m_bHover = TRUE;
  this->Invalidate(FALSE);
}

void CImageButton::OnMouseLeave()
{
  //__super::OnMouseLeave();
  m_bHover = FALSE;
  this->Invalidate(FALSE);
}
タイトルとURLをコピーしました