三态位图按钮

下午无聊写的一个简单三态按钮,功能很有限,对于一般的不需要拉伸的对话框还比较适用(不能指定WS_CLIPCHILDREN风格):

class CBitmapButton : public CWindowImpl<CBitmapButton,CButton>,
  public COwnerDraw<CBitmapButton>
{
private:
bool m_bTracking;
bool m_bDCStored;
CBitmap m_bitmapNor;
CBitmap m_bitmapOver;
CBitmap m_bitmapDown;
public:
CBitmapButton():m_bTracking(false),m_bDCStored(false)
{

}
virtual ~CBitmapButton()
{

}
void SetImage(CString strNormal, CString strHover, CString strDown)
{
m_bitmapNor=(HBITMAP)::LoadImage(NULL,strNormal,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
m_bitmapOver=(HBITMAP)::LoadImage(NULL,strHover,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
m_bitmapDown=(HBITMAP)::LoadImage(NULL,strDown,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
}

void SetImage(UINT nNormalID, UINT nHoverID, UINT nDownID)
{
m_bitmapNor.LoadBitmap(nNormalID);
m_bitmapOver.LoadBitmap(nHoverID);
m_bitmapDown.LoadBitmap(nDownID);
}

BEGIN_MSG_MAP(CBitmapButton)
MESSAGE_HANDLER(WM_CREATE,OnCreate)
MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBkgnd)
MESSAGE_HANDLER(WM_MOUSEMOVE,OnMouseMove)
MESSAGE_HANDLER(WM_MOUSELEAVE,OnMouseLeave)
CHAIN_MSG_MAP_ALT(COwnerDraw<CBitmapButton>,1)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()

LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
Init();
bHandled = FALSE;
return 1;
}

LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
return 1;
}

LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled=FALSE;

if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof (tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE;
tme.dwHoverTime = 1;
m_bTracking = _TrackMouseEvent(&tme);
Invalidate(FALSE);
}

return 0;
}

LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled=false;

m_bTracking = false;
Invalidate(FALSE);

return 0;
}

void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
CDCHandle dc = lpDrawItemStruct->hDC;

CRect rcBtn( lpDrawItemStruct->rcItem);

BITMAP bmpInfo;
m_bitmapNor.GetBitmap(&bmpInfo);

if (m_bTracking)
{
CDC dctemp;
dctemp.CreateCompatibleDC(dc);
dctemp.SelectBitmap(m_bitmapOver);

::TransparentBlt(dc,0,0, lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom, dctemp.m_hDC, 0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, RGB(255,0,255));
}

if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
CDC dctemp;
dctemp.CreateCompatibleDC(dc);
dctemp.SelectBitmap(m_bitmapDown);
::TransparentBlt(dc,0,0, lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom, dctemp.m_hDC, 0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, RGB(255,0,255));
}
else if (!m_bTracking)
{
CDC dctemp;
dctemp.CreateCompatibleDC(dc);
dctemp.SelectBitmap(m_bitmapNor);
::TransparentBlt(dc,0,0, lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom, dctemp.m_hDC, 0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, RGB(255,0,255));

}

int cchLen=GetWindowTextLength()+1;
if (cchLen>1)
{
CFont oldFont=dc.SelectFont(GetFont());
LPTSTR strText=NULL;

strText=new TCHAR[cchLen];
::memset(strText,0,cchLen);
GetWindowText(strText,cchLen);
CRect rtText;
GetClientRect(&rtText);
dc.SetBkMode(TRANSPARENT);
dc.DrawText(strText,cchLen-1,&rtText, DT_CENTER|DT_SINGLELINE |DT_VCENTER);

delete strText;
dc.SelectFont(oldFont);
}

}
protected:
void Init()
{
ModifyStyle(0,BS_OWNERDRAW);
}
};

 

Demo