WTL按钮重绘

Table of Contents

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

    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)