Skip to content

WTL按钮重绘

Published: at 03:30 AM | 4 min read

下面的类不是我写的,我只简单介绍一下用法:

  1. 将AtlBitmapSkinButton.h头文件导入到工程中;
  2. 添加#include “AtlBitmapSkinButton.h”头文件;
  3. 添加按钮控件IDC_BUTTON1,并将其Ower Draw属性改为True;
BEGIN_MSG_MAP(CDialog)
......
REFLECT_NOTIFICATIONS()//这句不要忘了!
END_MSG_MAP()
  1. CAtlBitmapButton m_button1;
  2. 在OnInitDialog里面添加如下代码:
m_button1.SubclassWindow(GetDlgItem(IDC_BUTTON1));
m_button1.LoadStateBitmaps(IDB_BITMAP1, IDB_BITMAP2, IDB_BITMAP3);

IDB_BITMAP1:当前显示,IDB_BITMAP2:鼠标按下,IDB_BITMAP3:鼠标滑过

class CAtlBitmapButton;
typedef CWindowImpl < CAtlBitmapButton, CWindow, CWinTraits < WS_CHILD | WS_VISIBLE | BS_OWNERDRAW> > CCustButton;

class CAtlBitmapButton : public CCustButton
{
public:
	DECLARE_WND_SUPERCLASS(NULL, _T("BUTTON"))
		
		
	CAtlBitmapButton()
	{
		m_bButtonDown = m_bTracking = false;
	}
	
	~CAtlBitmapButton()
	{
	}
	
	
	BEGIN_MSG_MAP(CAtlBitmapButton)
		MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
		MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)
		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
		MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
		END_MSG_MAP()
		
		LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ATLASSERT(m_bTracking);
		m_bTracking = false;
		Invalidate();
		return 0;
	}
	LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		// TODO : Add Code for message handler. Call DefWindowProc if necessary.
		LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
		HDC hdcMem = ::CreateCompatibleDC(lpdis->hDC);
        HBITMAP hbmMem = ::CreateCompatibleBitmap(lpdis->hDC,
			lpdis->rcItem.right - lpdis->rcItem.left,
			lpdis->rcItem.bottom - lpdis->rcItem.top);
        
		HGDIOBJ hbmOld = ::SelectObject(hdcMem, (HGDIOBJ)hbmMem);
		HBRUSH transparent = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
		RECT rect={lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem .right, lpdis->rcItem.bottom };
		int cx = rect.right - rect.left;
		int cy = rect.bottom -rect.top;
		
		FillRect(hdcMem , &rect, transparent);
		
		
		POINT mouse_position;
		if ((m_bButtonDown) &&(::GetCapture() == m_hWnd) &&(::GetCursorPos(&mouse_position)))
		{
			if (::WindowFromPoint(mouse_position) == m_hWnd)
			{
				if ((GetState() & BST_PUSHED) != BST_PUSHED)
				{
					SetState(TRUE);
					return -1;
				}
			}
			else 
			{
				if ((GetState() & BST_PUSHED) == BST_PUSHED)
				{
					SetState(FALSE);
					return -1;
				}
			}
		}
		
		if (lpdis->itemState & ODS_SELECTED)
		{
			if (!m_bmpDown)
			{
				FillRect(lpdis->hDC, &rect, CreateSolidBrush(GetSysColor(COLOR_BTNFACE))); 
			}
			else
				DrawBitmap(lpdis->hDC, m_bmpDown, rect); 
		}
		else
		{
			if (!m_bmpNormal)
				FillRect(lpdis->hDC, &rect, CreateSolidBrush(GetSysColor(COLOR_BTNFACE))); 
			else
			{
				if ((m_bTracking) && m_bmpOver)
					DrawBitmap(lpdis->hDC, m_bmpOver, rect); 
				else
					DrawBitmap(lpdis->hDC, m_bmpNormal, rect); 
			}
		}
		
		::SelectObject(hdcMem, hbmOld);
        ::DeleteObject((HGDIOBJ)hbmMem);
        ::DeleteDC(hdcMem);
		
        return 0;
	}
	
	public:
		
		LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			// TODO : Add Code for message handler. Call DefWindowProc if necessary.
			return 0;
		}
		
		LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			return 1;
		}
		
		LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			// TODO : Add Code for message handler. Call DefWindowProc if necessary.
			
			if (m_bTracking)
			{
				TRACKMOUSEEVENT t = 
				{
					sizeof(TRACKMOUSEEVENT),
						TME_CANCEL | TME_LEAVE,
						m_hWnd,
						0
				};
				if (::_TrackMouseEvent(&t))
				{
					m_bTracking = false;
				}
			}
			
			
			m_bButtonDown = true;
			
			bHandled = false;
			
			return 0;
		}
		LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			// TODO : Add Code for message handler. Call DefWindowProc if necessary.
			m_bButtonDown = false;
			bHandled = false;
			return 0;
		}
		
		LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			// TODO : Add Code for message handler. Call DefWindowProc if necessary.
			if ((m_bButtonDown) &&(::GetCapture() == m_hWnd))
			{
				POINT p2;
				p2.x = LOWORD(lParam);
				p2.y = HIWORD(lParam);
				
				::ClientToScreen(m_hWnd, &p2);
				HWND mouse_wnd = ::WindowFromPoint(p2);
				
				bool pressed = ((GetState() & BST_PUSHED) == BST_PUSHED);
				bool need_pressed = (mouse_wnd == m_hWnd);
				if (pressed != need_pressed)
				{
					SetState(need_pressed ? TRUE : FALSE);
					Invalidate();
				}
			}
			else 
			{
				if (!m_bTracking)
				{
					TRACKMOUSEEVENT t = 
					{
						sizeof(TRACKMOUSEEVENT),
							TME_LEAVE,
							m_hWnd,
							0
					};
					if (::_TrackMouseEvent(&t))
					{
						m_bTracking = true;
						Invalidate();
					}
				}
			}
			bHandled = false;
			return 0;
		}
		
		int GetBitmapWidth(HBITMAP hBitmap)
		{
			BITMAP bm; 
			GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm); 
			return bm.bmWidth;
		}
		
		int GetBitmapHeight(HBITMAP hBitmap)
		{
			BITMAP bm; 
			GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);
			return bm.bmHeight;
		}
		
		void DrawBitmap(HDC hdc, HBITMAP hBitmap, RECT& rc)
		{
			if (!hBitmap)
			{
				ATLTRACE("/nUnable to load bitmap....");
				return;
			}
			
			int cx = rc.right  - rc.left;
			int cy = rc.bottom - rc.top;
			
			int nbmpWidth= GetBitmapWidth(hBitmap);
			int nbmpHeight = GetBitmapHeight(hBitmap);
			HDC hdcMem = CreateCompatibleDC(hdc);
			SelectObject(hdcMem, hBitmap);
			
			StretchBlt(hdc, rc.left, rc.top, cx, cy, hdcMem, 0, 0, nbmpWidth, nbmpHeight, SRCCOPY);
			
			DeleteDC(hdcMem);
		}
		
		
		
		void LoadStateBitmaps(UINT nSelected, UINT nDown, UINT nOver)
		{
			if (m_bmpNormal)
				m_bmpNormal.DeleteObject();
			if (m_bmpDown)
				m_bmpDown.DeleteObject();
			if (m_bmpOver)
				m_bmpOver.DeleteObject();
			
			m_bmpNormal.LoadBitmap(nSelected);
			m_bmpDown.LoadBitmap(nDown);
			m_bmpOver.LoadBitmap(nOver);
		}
		
		UINT GetState() const
		{
			ATLASSERT(::IsWindow(m_hWnd));
			return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L);
		}
		
		void SetState(BOOL bHighlight)
		{
			ATLASSERT(::IsWindow(m_hWnd));
			::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L);
		}	
		
private:
	int m_nBorder;
	CBitmap m_bmpNormal, m_bmpDown, m_bmpOver;
	short	m_DrawMode;	
	BOOL m_bTracking;
	BOOL m_bButtonDown;	
	
	
	LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		// TODO : Add Code for message handler. Call DefWindowProc if necessary.
		if (::GetCapture() == m_hWnd)
		{
			::ReleaseCapture();
			ATLASSERT(!m_bTracking);
			m_bButtonDown = false;
			ATLTRACE("/nKillFocus");
		}
		bHandled = false;
		return 0;
	}
};

from

(迁移2011-05-09)