この記事は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);
}