CBitmapButtonを継承してマウスオーバー時に画像を変化させるようにする。

Posted on Sun 30 August 2009 in Windows

デフォルトのCBitmapButtonだとマウスオーバー時の画像を読み込んで
表示させてくれないので、CBitmapButtonを継承して機能を付け足しました。

Create()で作成して、LoadBitmapsで画像を読み込みます。
その他のAutoLoadなどには対応していません。

ヘッダー

#pragma once
class CHoverBitmapButton :
public CBitmapButton
{
  public:
    CHoverBitmapButton() : m_isHover(false) {};
    ~CHoverBitmapButton(){};
    BOOL LoadBitmaps(
      UINT nIDBitmapResource,
      UINT nIDBitmapResourceHov,
      UINT nIDBitmapResourceSel=0,
      UINT nIDBitmapResourceFocus=0,
      UINT nIDBitmapResourceDisabled=0);
    void DrawItem(LPDRAWITEMSTRUCT lpDis);
  protected:
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    LRESULT OnMouseHover(WPARAM wp, LPARAM lp);
    LRESULT OnMouseLeave(WPARAM wp, LPARAM lp);
    DECLARE_MESSAGE_MAP();
  private:
    bool m_isHover;
    CBitmap m_bitmapHov;
};

ソース

LoadBitmapsは、読み込み時に呼ばれる関数です。
一つリソースIDを受け取る引数を増やして、画像をリソースから読み込んでいます。

OnMouseMove()が呼び出されたときに、
WM_MOUSEHOVERとWM_MOUSELEAVEメッセージが来るように、
TrackMouseEvent()を呼び出しています。

DrawItem()は、描画時に呼ばれる関数です。
DrawItem()内では、マウスオーバー時、ボタンが押されていなければ、
読み込んだ画像を表示させています。

#include "HoverBitmapButton.h"

BOOL CHoverBitmapButton::LoadBitmaps(
  UINT nIDBitmapResource,
  UINT nIDBitmapResourceHov,
  UINT nIDBitmapResourceSel,
  UINT nIDBitmapResourceFocus,
  UINT nIDBitmapResourceDisabled)
{
  m_bitmapHov.DeleteObject();
  if(!m_bitmapHov.LoadBitmap(nIDBitmapResourceHov)){
    return FALSE;
  }
  return CBitmapButton::LoadBitmaps(
    nIDBitmapResource,
    nIDBitmapResourceSel,
    nIDBitmapResourceFocus);
}

void CHoverBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDis)
{
  if(m_isHover && !(lpDis->itemState & ODS_SELECTED)){
    CDC* pDC = CDC::FromHandle(lpDis->hDC);
    CDC memDC;
    memDC.CreateCompatibleDC(pDC);
    CBitmap* pOld = memDC.SelectObject(&m_bitmapHov);
    if (pOld == NULL)
      return; //destructors will clean up
    CRect rect;
    rect.CopyRect(&lpDis->rcItem);
    pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),
    &memDC, 0, 0, SRCCOPY);
    memDC.SelectObject(pOld);
  }
  else{
    CBitmapButton::DrawItem(lpDis);
  }
}

BEGIN_MESSAGE_MAP(CHoverBitmapButton, CBitmapButton)
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()

void CHoverBitmapButton::OnMouseMove(UINT nFlags, CPoint point)
{
  TRACKMOUSEEVENT tme;
  tme.cbSize = sizeof(tme);
  tme.dwFlags = TME_HOVER | TME_LEAVE;
  tme.hwndTrack = this->GetSafeHwnd();
  tme.dwHoverTime = 1;
  ::TrackMouseEvent(&tme);
  CBitmapButton::OnMouseMove(nFlags, point);
}

LRESULT CHoverBitmapButton::OnMouseHover(WPARAM wp, LPARAM lp)
{
  m_isHover = true;
  this->Invalidate(FALSE);
  return FALSE;
}

LRESULT CHoverBitmapButton::OnMouseLeave(WPARAM wp, LPARAM lp)
{
  m_isHover = false;
  this->Invalidate(FALSE);
  return FALSE;
}

参考URL

http://d.hatena.ne.jp/xyuyux/20090211/1234346399