WTL 自绘控件库 (CQsRadioBox)

概述:

CQsRadioBox基础与 CButton,通过自绘来实现 实现Radion Box的效果,通过BST_CHECKED 属性来实现。

代码实现如下:

#pragma once
#include "QsInclude.h"

#define  MAXRADIOXTXT       512

#define		QS_RAD_SYSYSTEM				0x00000001			//RadioBox系统样式
#define	    QS_RAD_OWNERDRAW        0x00000002          //RadioBox自绘样式,默认为自绘样式。

class CQsRadioBox :
	public CWindowImpl<CQsRadioBox, CButton>,
	public CImageMgrCtrlBase< CQsRadioBox>,
	public COwnerDraw< CQsRadioBox >
{
	typedef CWindowImpl< CQsRadioBox, CButton > theBaseClass;
	typedef CImageMgrCtrlBase< CQsRadioBox > theImageCtrlBaseClass;

	Image *m_pCurImage;							//当前正在使用的图片
	Image *m_pLastImage;							//发生状态改变前使用的图片
	volatile int m_nCheck;							//是否被选中标志
	volatile bool m_bMouseDown;             //鼠标左键按下
	Color m_enableColor;                       //可用状态时字体的颜色
	Color m_unenableColor;                  //不可用状态时字体的颜色
public:
	BEGIN_MSG_MAP( CQsRadioBox )
		MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBKGnd )
		MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown )
		MESSAGE_HANDLER( WM_LBUTTONUP, OnLButtonUp )
		MESSAGE_HANDLER( WM_MOUSELEAVE, OnMouseLeave )
		MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove )
		MESSAGE_HANDLER( BM_SETCHECK, OnSetCheck )
		MESSAGE_HANDLER( BM_GETCHECK, OnGetCheck )
		REFLECTED_COMMAND_CODE_HANDLER( BN_CLICKED, OnClicked )
		CHAIN_MSG_MAP_ALT( COwnerDraw< CQsRadioBox >, 1 )
		CHAIN_MSG_MAP( theImageCtrlBaseClass )
		DEFAULT_REFLECTION_HANDLER()
	END_MSG_MAP()

	/**
	*@method   CQsRadioBox
	*@brief    CQsRadioBox类构造函数
	*    
	*@return   
	*/
	CQsRadioBox():
		m_bMouseDown( false ),
		m_pCurImage( NULL ),
		m_pLastImage( NULL ),
		m_enableColor(255, 0, 0, 0),
		m_unenableColor(255, 128, 128, 128),
		m_nCheck( 0 )
	{
		m_uFirstPos = CONTROL_RDB_FIRST;
		m_uLastPos = CONTROL_RDB_LAST;
		SetQsStyle(QS_RAD_OWNERDRAW);
	}

	/**
	*@method   ~CQsRadioBox
	*@brief    CQsRadioBox析构造函数
	*    
	*@return   
	*/
	virtual ~CQsRadioBox()
	{
	}

	/**
	*@method   DrawItem
	*@brief    按钮重画函数
	*    
	*@param    LPDRAWITEMSTRUCT lpdis 详见MSN
	*@return   void
	*/
	void DrawItem( LPDRAWITEMSTRUCT lpdis )
	{
		int width = lpdis->rcItem.right - lpdis->rcItem.left;
		int height = lpdis->rcItem.bottom - lpdis->rcItem.top;

		//创建内存作图对象
		WTL::CDC memDC;
		memDC.CreateCompatibleDC( lpdis->hDC );
		WTL::CBitmap memBitmap;
		memBitmap.CreateCompatibleBitmap( lpdis->hDC, width, height );
		HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap );

		//获得控件背景
		memDC.SetBkMode( TRANSPARENT );
		::SendMessage( GetParent(), WM_DRAWBKGNDUI, ( WPARAM )memDC.m_hDC, ( LPARAM )lpdis->hwndItem );

		//绘制按钮
		DrawButton( memDC.m_hDC, lpdis->rcItem );

		//提交图像
		::BitBlt( lpdis->hDC, 0, 0, width, height, memDC.m_hDC, 0, 0, SRCCOPY );

		memDC.SelectBitmap( hOldBmp );
		memBitmap.DeleteObject();
		memDC.DeleteDC();

	}

	/**
	*@method   Create
	*@brief    通过Create来创建窗口。
	*    
	*@param    HWND hWndParent  parent window
	*@param    ATL::_U_RECT rect = NULL create window rect
	*@param    LPCTSTR szWindowName = NULL the window name
	*@param    DWORD dwStyle = 0  base window style
	*@param    DWORD dwExStyle = 0  extended window style
	*@param    ATL::_U_MENUorID MenuOrID = 0U menu or ID
	*@param    LPVOID lpCreateParam = NULL create param
	*@return   HWND 非NULL success return TRUE, failed return NULL
	*/
	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.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
	}

	/**
	*@method   SubclassWindow
	*@brief    类对象关联
	*    
	*@param    HWND hWnd  对象句柄
	*@return   BOOL
	*/
	BOOL SubclassWindow( HWND hWnd )
	{
		//在此之前可能已经SetCheck
		m_nCheck = (int)::SendMessage( hWnd, BM_GETCHECK, 0, 0 );

		BOOL bRet = theBaseClass::SubclassWindow( hWnd );
		if(m_dwQsStyle&QS_RAD_OWNERDRAW)
		{
			UINT nBS = GetButtonStyle();
			SetButtonStyle( nBS | BS_OWNERDRAW );
		}

		return bRet;
	}

	/**
	*@method   SetEnableColor
	*@brief    设置可用时字体的颜色。
	*    
	*@param    Color enableColor 可用时字体的颜色
	*@return   void
	*/
	void SetEnableColor(Color enableColor)
	{
		m_enableColor =  enableColor;
	}

	/**
	*@method   SetUnEnableColor
	*@brief    设置不可用时字体的颜色
	*    
	*@param    Color unenableColor 不可用时字体的颜色
	*@return   void
	*/
	void SetUnEnableColor(Color unenableColor)
	{
		m_unenableColor = unenableColor;
	}
protected:

	/**
	*@method   OnSetCheck
	*@brief    设置状态消息响应函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled     未被使用
	*@return   LRESULT
	*/
	LRESULT OnSetCheck( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
	{
		if(m_dwQsStyle&QS_RAD_SYSYSTEM)
		{
			return DefWindowProc(uMsg, wParam, lParam); 
		}
		//首先获得check标志
		m_nCheck = ( wParam != 0 );
		if( m_nCheck )
		{
			CSimpleArray< HWND > lst;
			lst.Add( m_hWnd );

			//获得父窗口句柄
			HWND hWndParent = GetParent().m_hWnd;

			//获得控件窗口句柄
			HWND hWnd = m_hWnd;
			while( hWnd )
			{
				//获得同组内控件的窗口句柄
				hWnd = ::GetNextDlgGroupItem( hWndParent, hWnd, 0 );

				//在list中查找这个句柄是否被查询到过
				int nPos = lst.Find( hWnd );
				if( nPos != -1 )
				{
					//如果找到了这个句柄,那就代表搜索到头了
					hWnd = NULL;
				}

				if( NULL != hWnd )
				{
					//如果没有搜索完一组,则把当前搜索的句柄添加到list中去(目的是为了不让同一控件被发送两次消息)
					lst.Add( hWnd );
					//对这个控件发送unChecked消息
					::PostMessage( hWnd, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0 );
				}
			}
		}
		Invalidate();
		return 0;
	}

	/**
	*@method   OnGetCheck
	*@brief    读取状态消息响应函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled    未被使用
	*@return   LRESULT
	*/
	LRESULT OnGetCheck( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
	{
		if(m_dwQsStyle&QS_RAD_SYSYSTEM)
		{
			return DefWindowProc(uMsg, wParam, lParam); 
		}

		return m_nCheck;
	}

	/**
	*@method   OnLButtonDown
	*@brief    	鼠标左键被按下消息响应函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled    未被使用
	*@return   LRESULT
	*/
	LRESULT OnLButtonDown( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		m_bMouseDown = true;
		Invalidate();
		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnMouseMove
	*@brief    鼠标进入消息响应函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled    未被使用
	*@return   LRESULT
	*/
	LRESULT OnMouseMove( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		if( m_pCurImage != GetImage( CONTROL_BTN_MOUSEIN ) )
		{
			Invalidate();

			// 启动鼠标离开时间
			TRACKMOUSEEVENT tme;
			tme.cbSize  = sizeof(tme);
			tme.hwndTrack = m_hWnd;
			tme.dwFlags = TME_LEAVE;
			TrackMouseEvent(&tme);
		}

		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnMouseLeave
	*@brief    鼠标离开消息响应函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled   未被使用
	*@return   LRESULT
	*/
	LRESULT OnMouseLeave( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		Invalidate();
		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnLButtonUp
	*@brief    	鼠标左键被放开消息响应函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled   未被使用
	*@return   LRESULT
	*/
	LRESULT OnLButtonUp( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		m_bMouseDown = false;
		Invalidate();
		bHandled = FALSE;
		return 0;
	}

	/**
	*@method   OnEraseBKGnd
	*@brief    背景绘制消息函数
	*    
	*@param    UINT uMsg	 消息类型
	*@param    WPARAM wParam 未被使用
	*@param    LPARAM lParam 详见MSDN
	*@param    BOOL& bHandled  未被使用
	*@return   LRESULT
	*/
	LRESULT OnEraseBKGnd( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
	{
		//禁止绘制底色
		return 0;
	}

	/**
	*@method   OnClicked
	*@brief    	按钮被按下消息响应函数
	*    
	*@param    WORD wNotifyCode	 通知消息代码
	*@param    WORD wID    发送该消息的控件ID
	*@param    HWND hWndCtl 发送该消息的控件的句柄
	*@param    BOOL& bHandled  消息是否继续处理标志
	*@return   LRESULT
	*/
	LRESULT OnClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		SetCheck( BST_CHECKED );

		Invalidate();
		return 0;
	}


private:

	/**
	*@method   GetButtonTextFormat
	*@brief    得到Button文字的对齐方式(用DrawText()输出时的格式)
	*    
	*@param    const LONG lStyle 控件风格
	*@return   UINT  输出时的格式
    * 说  明: button上的字必须是一行
	*/
	UINT GetButtonTextFormat(const LONG lStyle)
	{
		UINT uFormat = DT_SINGLELINE;//button上的字必须是一行
		
		//x方向
		if ( (lStyle & BS_CENTER)==BS_CENTER )//x方向,中
		{
			uFormat |= DT_CENTER;
		}
		else if ( (lStyle & BS_RIGHT)==BS_RIGHT )//x方向,右
		{
			uFormat |= DT_RIGHT;
		}
		else if ( (lStyle & BS_LEFT) == BS_LEFT )//x方向,左
		{
			uFormat |= DT_LEFT;
		}
		else//缺省,x中
		{
			uFormat |= DT_LEFT;
		}
		
		//y方向
		if ( (lStyle & BS_VCENTER ) == BS_VCENTER )//y,中
		{
			uFormat |= DT_VCENTER;
		}
		else if ( (lStyle & BS_TOP)==BS_TOP )//y方向,上
		{
			uFormat |= DT_TOP;
		}
		else if ( (lStyle & BS_BOTTOM)==BS_BOTTOM )//y方向,下
		{
			uFormat |= DT_BOTTOM;
		}
		else//缺省,y中
		{
			uFormat |= DT_VCENTER;
		}
		
		return uFormat;
	}

	/**
	*@method   DrawButton
	*@brief    绘制按钮函数
	*    
	*@param    HDC hDC   作图设备句柄
	*@param    RECT itemRect 按钮位置
	*@return   void
	*/
	void DrawButton( HDC hDC, RECT /*itemRect*/ )
	{
		HDC hdc = hDC;
		WTL::CDCHandle dc( hDC );

		SetBkMode( hdc, TRANSPARENT );

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

		//判断鼠标是否在按钮上
		CRect rc;
		GetWindowRect( rc );
		
		POINT pt;
		GetCursorPos( &pt );

		Image *pImg = NULL;
		UINT uStateFont = CONTROL_BTN_NORMAL;

		//如果当前处于失效状态
		if( bIsDisabled )
		{
			if( bIsChecked )//如果当前被选择
			{
				pImg = ( GetImage( CONTROL_RDB_DISCHECKED ) != NULL ? GetImage( CONTROL_RDB_DISCHECKED ) : GetImage ( CONTROL_RDB_CHECKED ) );
				uStateFont = CONTROL_RDB_DISCHECKED;  
			}
			else
			{
				pImg = ( GetImage( CONTROL_RDB_DISUNCHECK ) != NULL ? GetImage( CONTROL_RDB_DISUNCHECK ) : GetImage( CONTROL_RDB_DISCHECKED ) );
				uStateFont = CONTROL_RDB_DISUNCHECK;  //CONTROL_RDB_DISUNCHECK
			}
		}
		else
		{
			if( bIsChecked )//如果当前被选择
			{
				pImg = GetImage( CONTROL_RDB_CHECKED );
				uStateFont = CONTROL_RDB_CHECKED;
			}
			else
			{
				pImg = GetImage( CONTROL_RDB_UNCHECK );
				uStateFont = CONTROL_RDB_UNCHECK;
			}
		}

		//如果没有对应状态的图片
		if( pImg == NULL )
		{
			if( m_pCurImage != NULL )
			{
				pImg = m_pCurImage;
			}
			else
			{
				pImg = GetImage( CONTROL_BTN_NORMAL );
				uStateFont = CONTROL_BTN_NORMAL;
			}
		}

		//如果当前图片相同
		if( m_pCurImage != pImg )
		{
			//保存上一个状态的图片
			if( NULL != m_pCurImage)
			{
				m_pLastImage = m_pCurImage;
			}
			else
			{
				m_pLastImage = pImg;
			}
			m_pCurImage = pImg;
		}
		//绘制图片
		Graphics graph( hDC );
        int titleStart = 0;

		if( m_pCurImage != NULL )
		{
			graph.SetPageScale( 1.0 );
			graph.SetPageUnit( UnitPixel ); 
			graph.SetSmoothingMode( SmoothingModeNone );
            titleStart = m_pCurImage->GetWidth( );
			graph.DrawImage( m_pCurImage, 0, 0, titleStart, m_pCurImage->GetHeight() );
		}

        // 显示标题
        TCHAR tstrTitle[MAXRADIOXTXT] = _T("");
        GetWindowText( tstrTitle, MAXRADIOXTXT);

        CRect rtWnd;
        GetWindowRect( &rtWnd );
        ScreenToClient( &rtWnd );

		HFONT hFont = GetStateFont(uStateFont); //得到的Font要求销毁!
        Gdiplus::Font fontTitle(hDC,hFont);

        StringFormat format;
        UINT uStyle = GetButtonStyle();
        if ( BS_PUSHLIKE & uStyle )
        {
            CRect rtfTitle( 0, 0, rtWnd.Width(), rtWnd.Height() );
            format.SetAlignment(StringAlignmentCenter);
            format.SetLineAlignment(StringAlignmentCenter);
			if(!bIsDisabled) //失效状态
			{
				HFONT hOldFont = dc.SelectFont( hFont );
				dc.SetTextColor(m_enableColor.ToCOLORREF());
				dc.DrawText( tstrTitle, -1, &rtfTitle, GetButtonTextFormat( lStyle ) );
				dc.SelectFont( hOldFont );
				//SolidBrush sbTitle(m_enableColor);
				//graph.DrawString( tstrTitle,(int) _tcslen(tstrTitle), &fontTitle, rtfTitle, &format, &sbTitle );
			}
			else
			{
				HFONT hOldFont = dc.SelectFont( hFont );
				dc.SetTextColor(m_unenableColor.ToCOLORREF());
				dc.DrawText( tstrTitle, -1, &rtfTitle, GetButtonTextFormat( lStyle ) );
				dc.SelectFont( hOldFont );
				//SolidBrush sbTitle(m_unenableColor);
				//graph.DrawString( tstrTitle,(int) _tcslen(tstrTitle), &fontTitle, rtfTitle, &format, &sbTitle );
			}
        }
        else
        {	
            CRect rtfTitle( titleStart, 0, rtWnd.Width() - titleStart, rtWnd.Height() );
            format.SetAlignment( StringAlignmentNear );
            format.SetLineAlignment( StringAlignmentCenter );
			if(!bIsDisabled) //失效状态
			{
				HFONT hOldFont = dc.SelectFont( hFont );
				dc.SetTextColor(m_enableColor.ToCOLORREF());
				dc.DrawText( tstrTitle, -1, &rtfTitle, GetButtonTextFormat( lStyle ) );
				dc.SelectFont( hOldFont );
			//	SolidBrush sbTitle(m_enableColor);
			//	graph.DrawString( tstrTitle, (int)_tcslen(tstrTitle), &fontTitle, rtfTitle, &format, &sbTitle );
			}
			else
			{
				HFONT hOldFont = dc.SelectFont( hFont );
				dc.SetTextColor(m_unenableColor.ToCOLORREF());
				dc.DrawText( tstrTitle, -1, &rtfTitle, GetButtonTextFormat( lStyle ) );
				dc.SelectFont( hOldFont );
				//SolidBrush sbTitle(m_unenableColor);
				//graph.DrawString( tstrTitle, (int)_tcslen(tstrTitle), &fontTitle, rtfTitle, &format, &sbTitle );
			}
        }
        graph.ReleaseHDC( hDC );
		DeleteObject( hFont );
	}
};
  • 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、付费专栏及课程。

余额充值