WTL 自绘控件库 (CQsComboBox)

概述:

CQsComboBox 继承 CComboBox,该控件是有edit 控件 组合而成的复合控件,并且对下列框的背景和框的下拉进行了重绘。

代码实现如下:

#pragma once

#include "QsInclude.h"
#include "QsEdit.h"
#define		QS_COMBOX_SYSYSTEM				       0x00000001			//ComboBox系统样式
#define	    QS_COMBOX_OWNERDRAW               0x00000002          //CheckBox自绘样式,默认为自绘样式。


/* CQsComboBox class */
class CQsComboBox :
	public CWindowImpl<CQsComboBox, CComboBox>,
	public CImageMgrCtrlBase< CQsComboBox >
{
	typedef CWindowImpl< CQsComboBox, CComboBox > theBaseClass;
	typedef CImageMgrCtrlBase< CQsComboBox> theImageCtrlBaseClass;

	Image *m_pCurImage;                        //当前正在使用的图片
	Image *m_pLastImage;                       //发生状态改变前使用的图片
	volatile bool m_bMouseDown;                //鼠标左键按下
	CQsEdit m_edtEdit;						 //编辑框控件
	CFont   font;
	DWORD m_dwStyle;

public:
	BEGIN_MSG_MAP( CQsComboBox )

		MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBKGnd )
		MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown )
		MESSAGE_HANDLER( WM_LBUTTONUP, OnLButtonUp )
		MESSAGE_HANDLER( WM_PAINT, OnPaint )
		MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove )
		MESSAGE_HANDLER( WM_MOUSELEAVE, OnMouseLeave )
	    CHAIN_MSG_MAP( theImageCtrlBaseClass )
		DEFAULT_REFLECTION_HANDLER()

	END_MSG_MAP()

	/**
	*@method   CQsComboBox
	*@brief    CQsComboBox's default constructor.
	*    
	*@return   
	*/
	CQsComboBox():
	m_bBtnMouseStatus( CONTROL_CBS_NORMAL ),
		m_bLeaveFlag( false )
	{
		m_uFirstPos = CONTROL_CBS_FIRST;
		m_uLastPos = CONTROL_CBS_LAST;
		m_dwStyle = QS_COMBOX_OWNERDRAW;
	}

	/**
	*@method   ~CQsComboBox
	*@brief    CQsComboBox's destructor.
	*    
	*@return   
	*/
	virtual ~CQsComboBox()
	{
		if (NULL != font.m_hFont)
		{
			DeleteObject(&font);
		}	}
	/**
	*@method   Create
	*@brief    
	*    
	*@param    HWND hWndParent
	*@param    ATL::_U_RECT rect = NULL
	*@param    LPCTSTR szWindowName = NULL
	*@param    DWORD dwStyle = 0
	*@param    DWORD dwExStyle = 0
	*@param    ATL::_U_MENUorID MenuOrID = 0U
	*@param    LPVOID lpCreateParam = NULL
	*@return   HWND
	*/
	HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
		DWORD dwStyle = 0, DWORD dwExStyle = 0, 
		ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{		
		return theBaseClass::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
	}
	 /**
	 *@method   SetQSWindowsStyle
	 *@brief        设置窗口的样式
	 *    
	 *@param    DWORD dwstyle dwstyle 窗口的样式
	 *@return   void
	 */void SetQSWindowsStyle(DWORD dwstyle)
	 {
			m_dwStyle = dwstyle;
	 }
	/**
	*@method   SubclassWindow
	*@brief    Use this function to subclass one window
	*    
	*@param    HWND hWnd    subclass binding window handle
	*@return   BOOL success return TRUE, failed return FALSE
	*/
	BOOL SubclassWindow( HWND hWnd )
	{
		BOOL bRet = theBaseClass::SubclassWindow( hWnd );

		return bRet;
	}
		/**
	*@method   SetQSFont
	*@brief    设置文字的大小
	*    
	*@param    TCHAR*fontName
	*@param    int nFontSize
	*@param    int lfWeight = FW_NORMAL
	*@param    BYTE fCharSet = ANSI_CHARSET
	*@return   void
	*/
	void SetQSFont(LPCTSTR lpszFaceName,int nFontSize,int lfWeight = FW_NORMAL,BYTE fCharSet = DEFAULT_CHARSET)
	{
		LOGFONT itemFont;
		itemFont.lfCharSet = fCharSet;
		itemFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
		itemFont.lfEscapement = 0;
		memset(itemFont.lfFaceName, 0, LF_FACESIZE);
		memcpy_s(itemFont.lfFaceName, LF_FACESIZE, lpszFaceName, LF_FACESIZE);
		itemFont.lfHeight = nFontSize;
		itemFont.lfItalic = FALSE;
		itemFont.lfOrientation = 0;
		itemFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
		itemFont.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
		itemFont.lfQuality = DEFAULT_QUALITY;
		itemFont.lfStrikeOut = FALSE;
		itemFont.lfUnderline = FALSE;
		itemFont.lfWeight = lfWeight;
		itemFont.lfWidth = 0;
		font =  ::CreateFontIndirect( &itemFont );
		SetFont(font);
	}

protected:

	/**
	*@method   OnPaint
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
	{
		if(m_dwStyle&QS_COMBOX_SYSYSTEM)
		{
			return DefWindowProc(uMsg, wParam, lParam);
		}
		WTL::CPaintDC paintDC( m_hWnd );

		// 		LONG lStyle = GetWindowLong( GWL_STYLE );
		// 		BOOL bIsDisabled = ( ( lStyle & WS_DISABLED ) != 0 ); //是否被禁止

		CRect rc;
		GetWindowRect( rc );

		//创建内存作图对象
		WTL::CDC dc;
		dc.CreateCompatibleDC( paintDC.m_hDC );
		WTL::CBitmap memBitmap;
		memBitmap.CreateCompatibleBitmap( paintDC.m_hDC, rc.Width(), rc.Height() );
		HBITMAP hOldBmp = dc.SelectBitmap( memBitmap );

		//还原背景
		dc.BitBlt( 0, 0, rc.Width(), rc.Height(), paintDC.m_hDC, 0, 0, SRCCOPY );


		WTL::CPen pen;
		pen.CreatePen( PS_SOLID, 1, RGB( 133, 173, 215 ) );

		//画一个淡蓝色的边框
		HPEN hOldPen = dc.SelectPen( pen );

		dc.RoundRect( 0, 0, rc.Width(), rc.Height(), 5, 5 );
		dc.SelectPen( hOldPen );

		COMBOBOXINFO cbInfo;
		cbInfo.cbSize = sizeof( COMBOBOXINFO );
		GetComboBoxInfo( &cbInfo );

		Image *pImg = GetImage( m_bBtnMouseStatus );

		if( pImg )
		{
			Graphics graph( dc.m_hDC );
			graph.SetPageScale( 1.0 );
			graph.SetPageUnit( UnitPixel ); 
			graph.SetSmoothingMode( SmoothingModeNone );
			CRect rcBtn( &cbInfo.rcButton );
			rcBtn.left -= 2;
			graph.DrawImage( pImg, Rect( rcBtn.left, rcBtn.top, rcBtn.Width(), rcBtn.Height() ),
				0, 0, pImg->GetWidth(), pImg->GetHeight(), UnitPixel );
			graph.ReleaseHDC( dc.m_hDC );
		}

		//获得当前EDIT控件的图像
		CRect edtRc;
		::GetWindowRect( cbInfo.hwndItem, edtRc );

		WTL::CDC memDC;
		memDC.CreateCompatibleDC( paintDC.m_hDC );
		WTL::CBitmap edtBmp;
		edtBmp.CreateCompatibleBitmap( paintDC.m_hDC, edtRc.Width(), edtRc.Height() );
		HBITMAP hEdtOld = memDC.SelectBitmap( edtBmp.m_hBitmap );

		SendMessage( WM_PRINT, (WPARAM)memDC.m_hDC, 
			(LPARAM)PRF_NONCLIENT | PRF_CLIENT | PRF_CHILDREN | PRF_CHECKVISIBLE );

		edtRc = CRect( cbInfo.rcItem );
		dc.BitBlt( edtRc.left, edtRc.top, edtRc.Width(), edtRc.Height(), memDC.m_hDC,
			edtRc.left, edtRc.top, SRCCOPY );

		memDC.SelectBitmap( hEdtOld );

		//提交图像
		paintDC.BitBlt( 0, 0, rc.Width(), rc.Height(), dc.m_hDC, 0, 0, SRCCOPY );

		dc.SelectBitmap( hOldBmp );

		dc.DeleteDC();
		memBitmap.DeleteObject();
		memDC.DeleteDC();
		pen.DeleteObject();
		edtBmp.DeleteObject();

		return 0;
	}

	/**
	*@method   OnLButtonDown
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnLButtonDown( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		m_bMouseDown = true;

		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnLButtonUp
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnLButtonUp( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		m_bMouseDown = false;

		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnEraseBKGnd
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnEraseBKGnd( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
	{
		//not draw background
		
		return 0;
	}

	/**
	*@method   OnMouseMove
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnMouseMove( UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
	{
		POINT pos;
		pos.x = GET_X_LPARAM(lParam); 
		pos.y = GET_Y_LPARAM(lParam); 

		COMBOBOXINFO cbInfo;
		cbInfo.cbSize = sizeof( COMBOBOXINFO );
		GetComboBoxInfo( &cbInfo );
		CRect rc( cbInfo.rcButton );

		//判断当前鼠标是否在按钮范围内
		if( rc.PtInRect( pos ) )
		{
			//如果鼠标左键被按下
			if( ( ( wParam & MK_LBUTTON ) == MK_LBUTTON ) && 
				( m_bBtnMouseStatus != CONTROL_CBS_MOUSEDOWN ) &&
				GetImage( CONTROL_CBS_MOUSEDOWN ) )
			{
				m_bBtnMouseStatus = CONTROL_CBS_MOUSEDOWN;
				Invalidate();
			}
			//否则,将状态设置为鼠标进入状态
			else if( ( m_bBtnMouseStatus != CONTROL_CBS_MOUSEIN ) &&
				GetImage( CONTROL_CBS_MOUSEIN ) )
			{
				m_bBtnMouseStatus = CONTROL_CBS_MOUSEIN;
				Invalidate();
			}
		}
		else if( ( m_bBtnMouseStatus != CONTROL_CBS_NORMAL ) )
		{
			m_bBtnMouseStatus = CONTROL_CBS_NORMAL;
			Invalidate();
		}

		//如果鼠标状态不为正常状态,则启动鼠标离开事件检查
		if( ( m_bBtnMouseStatus != CONTROL_CBS_NORMAL ) && !m_bLeaveFlag )
		{
			// 启动鼠标离开时间
			TRACKMOUSEEVENT tme;
			tme.cbSize  = sizeof(tme);
			tme.hwndTrack = m_hWnd;
			tme.dwFlags = TME_LEAVE;
			TrackMouseEvent(&tme);
		}

		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnMouseLeave
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnMouseLeave( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
	{
		if(m_dwStyle&QS_COMBOX_SYSYSTEM)
		{
			return DefWindowProc(uMsg, wParam, lParam);
		}
		if( ( m_bBtnMouseStatus != CONTROL_CBS_NORMAL ) )
		{
			m_bBtnMouseStatus = CONTROL_CBS_NORMAL;
			Invalidate();
		}

		return 0;
	}

private:
	volatile UINT m_bBtnMouseStatus;  //当前鼠标状态 CONTROL_CBS_NORMAL:鼠标未进入  1:鼠标进入  2:鼠标左键按下
	volatile bool m_bLeaveFlag;       //鼠标离开事件检查启动标志 false:未启动 true:已启动

};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

houxian1103

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值