让DuiLib CheckBox支持全选、全不选、非全选三种状态

    DuiLib官方库中的Checkbox只有Checked和Uncheck两种状态,但我们往往要实现这中需求:

让DuiLib CheckBox支持全选、全不选、非全选三种状态_第1张图片

    显然,Checkbox自带的属性和方法都不能满足这种需求,这就需要我们自定义重写CheckBox控件。

其实选择状态还是只有2种,因为SetCheck(bool bCheck) 参数只能为true或者false。但我们可以重写CheckBox的

void PaintStatusImage(HDC hDC) 方法,让但所有Checkbox都选中时绘制选中图标,全未选时绘制全未选图标,

未全选时绘制一种半选状态的图标。

    修改UICheckBox.h

#ifndef __UICHECKBOX_H__
#define __UICHECKBOX_H__

#pragma once

namespace DuiLib
{
	/// 最普通的单选按钮控件,只有是、否两种结果
	/// 派生于COptionUI,只是每组只有一个按钮而已,组名为空,配置文件默认属性举例:
	/// 

	class UILIB_API CCheckBoxUI : public COptionUI
	{
	public:
		~CCheckBoxUI();
		LPCTSTR GetClass() const;
		void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
		LPCTSTR GetSelectGroup() const;
		void SetSelectGroup(LPCTSTR pStrGroupName);

		LPCTSTR GetHalfSelectedImage();
		void SetHalfSelectedImage(LPCTSTR pStrImage);
		void PaintStatusImage(HDC hDC);
		void Selected(bool bSelected);
		void SetCheck(bool bCheck);
		bool GetCheck() const;
	private:
		CStdPtrArray	m_selectGroup;
		CDuiString		m_sSelectGroupName;
		CDuiString		m_sHalfSelectedImage;

	};
}

#endif // __UICHECKBOX_H__
    UICheckBox.cpp文件:

#include "stdafx.h"
#include "UICheckBox.h"

namespace DuiLib
{
	CCheckBoxUI::~CCheckBoxUI()
	{
		if( !m_sSelectGroupName.IsEmpty() && m_pManager ) m_pManager->RemoveSelectGroup(m_sSelectGroupName, this);
	}

	LPCTSTR CCheckBoxUI::GetClass() const
	{
		return _T("CheckBoxUI");
	}

	void CCheckBoxUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
	{
		if (_tcscmp(pstrName, _T("selectgroup")) == 0) SetSelectGroup(pstrValue);
		else if (_tcscmp(pstrName, _T("halfselectedimage")) == 0) SetHalfSelectedImage(pstrValue);
		else COptionUI::SetAttribute(pstrName, pstrValue);
	}

	LPCTSTR CCheckBoxUI::GetSelectGroup() const
	{
		return m_sSelectGroupName;
	}

	void CCheckBoxUI::SetSelectGroup(LPCTSTR pStrGroupName)
	{
		if( pStrGroupName == NULL ) {
			if( m_sSelectGroupName.IsEmpty() ) return;
			m_sSelectGroupName.Empty();
		}
		else {
			if( m_sSelectGroupName == pStrGroupName ) return;
			if (!m_sSelectGroupName.IsEmpty() && m_pManager) m_pManager->RemoveSelectGroup(m_sSelectGroupName, this);
			m_sSelectGroupName = pStrGroupName;
		}

		if( !m_sSelectGroupName.IsEmpty() ) {
			if (m_pManager) m_pManager->AddSelectGroup(m_sSelectGroupName, this);
		}
		else {
			if (m_pManager) m_pManager->RemoveSelectGroup(m_sSelectGroupName, this);
		}

		Selected(m_bSelected);
	}

	LPCTSTR CCheckBoxUI::GetHalfSelectedImage()
	{
		return m_sHalfSelectedImage;
	}

	void CCheckBoxUI::SetHalfSelectedImage(LPCTSTR pStrImage)
	{
		m_sHalfSelectedImage = pStrImage;
		Invalidate();
	}

	void CCheckBoxUI::Selected(bool bSelected)
	{
		if( m_bSelected == bSelected ) return;
		m_bSelected = bSelected;
		if( m_bSelected ) m_uButtonState |= UISTATE_SELECTED;
		else m_uButtonState &= ~UISTATE_SELECTED;

		if( (m_uButtonState & UISTATE_HALFSELECTED) != 0 )
			m_uButtonState &= ~UISTATE_HALFSELECTED;

		if( m_pManager != NULL ) {
			if( !m_sGroupName.IsEmpty() ) {
				if( m_bSelected ) {
					CStdPtrArray* aOptionGroup = m_pManager->GetOptionGroup(m_sGroupName);
					for( int i = 0; i < aOptionGroup->GetSize(); i++ ) {
						COptionUI* pControl = static_cast(aOptionGroup->GetAt(i));
						if( pControl != this ) {
							pControl->Selected(false);
						}
					}
					m_pManager->SendNotify(this, DUI_MSGTYPE_SELECTCHANGED);
				}
			}
			if (m_pManager->GetSelectGroup(GetName()) != NULL) {
				CStdPtrArray* aSelectGroup = m_pManager->GetSelectGroup(GetName());
				for (int i = 0; i < aSelectGroup->GetSize(); i++) {
					COptionUI* pControl = static_cast(aSelectGroup->GetAt(i));
					pControl->Selected(m_bSelected);
				}
			}
			if (!m_sSelectGroupName.IsEmpty()) {
				CStdPtrArray* aSelectGroup = m_pManager->GetSelectGroup(m_sSelectGroupName);
				UINT cnt = 0;
				for (int i = 0; i < aSelectGroup->GetSize(); i++) {
					CCheckBoxUI* pItem = static_cast(aSelectGroup->GetAt(i));
					cnt += pItem->IsSelected() ? 1 : 0;
				}
				CCheckBoxUI* pSelectAll  = static_cast(m_pManager->FindControl(m_sSelectGroupName));
				if (cnt == 0) // 全不选
				{
					pSelectAll->m_bSelected = false;
					pSelectAll->m_uButtonState &= ~UISTATE_SELECTED;
					pSelectAll->m_uButtonState &= ~UISTATE_HALFSELECTED;
				}else if (cnt == aSelectGroup->GetSize()) { // 全选
					pSelectAll->m_bSelected = true;
					pSelectAll->m_uButtonState |= UISTATE_SELECTED;
					pSelectAll->m_uButtonState &= ~UISTATE_HALFSELECTED;
				}else { // 非全选
					pSelectAll->m_uButtonState &= ~UISTATE_SELECTED;
					pSelectAll->m_uButtonState |= UISTATE_HALFSELECTED;
				}
				pSelectAll->NeedUpdate();
			}
			else {
				m_pManager->SendNotify(this, DUI_MSGTYPE_SELECTCHANGED);
			}
		}

		Invalidate();
	}

	void CCheckBoxUI::PaintStatusImage(HDC hDC)
	{
		m_uButtonState &= ~UISTATE_PUSHED;

		if( (m_uButtonState & UISTATE_HOT) != 0 && IsSelected() && !m_sSelectedHotImage.IsEmpty()) {
			if( !DrawImage(hDC, (LPCTSTR)m_sSelectedHotImage) )
				m_sSelectedHotImage.Empty();
			else goto Label_ForeImage;
		}
		else if( (m_uButtonState & UISTATE_SELECTED) != 0 ) {
			if( !m_sSelectedImage.IsEmpty() ) {
				if( !DrawImage(hDC, (LPCTSTR)m_sSelectedImage) ) m_sSelectedImage.Empty();
				else goto Label_ForeImage;
			}
			else if(m_dwSelectedBkColor != 0) {
				CRenderEngine::DrawColor(hDC, m_rcPaint, GetAdjustColor(m_dwSelectedBkColor));
				return;
			}	
		}
		else if( (m_uButtonState & UISTATE_HALFSELECTED) != 0 ) {
			if( !m_sHalfSelectedImage.IsEmpty() ) {
				if( !DrawImage(hDC, (LPCTSTR)m_sHalfSelectedImage) ) m_sHalfSelectedImage.Empty();
				else goto Label_ForeImage;
			}
		}

		CButtonUI::PaintStatusImage(hDC);

Label_ForeImage:
		if( !m_sForeImage.IsEmpty() ) {
			if( !DrawImage(hDC, (LPCTSTR)m_sForeImage) ) m_sForeImage.Empty();
		}
	}

	void CCheckBoxUI::SetCheck(bool bCheck)
	{
		Selected(bCheck);
	}

	bool  CCheckBoxUI::GetCheck() const
	{
		return IsSelected();
	}
}
    还要在UIManager.h中加入一些自定义的宏和方法:

自定义半选状态宏

// Flags used for controlling the paint
#define UISTATE_FOCUSED      0x00000001
#define UISTATE_SELECTED     0x00000002
#define UISTATE_DISABLED     0x00000004
#define UISTATE_HOT          0x00000008
#define UISTATE_PUSHED       0x00000010
#define UISTATE_READONLY     0x00000020
#define UISTATE_CAPTURED     0x00000040
#define UISTATE_HALFSELECTED 0x00000080
    添加选项组添加/删除方法(例如添加周几、删除周几到选项组)
    bool AddOptionGroup(LPCTSTR pStrGroupName, CControlUI* pControl);
    CStdPtrArray* GetOptionGroup(LPCTSTR pStrGroupName);
    void RemoveOptionGroup(LPCTSTR pStrGroupName, CControlUI* pControl);
    void RemoveAllOptionGroups();

    CStdPtrArray* GetSelectGroup(LPCTSTR pStrGroupName);
    bool AddSelectGroup(LPCTSTR pStrGroupName, CControlUI* pControl);
    void RemoveSelectGroup(LPCTSTR pStrGroupName, CControlUI* pControl);
    void CPaintManagerUI::RemoveAllSelectGroups();

    添加选项组map映射(例如weeks对应周一,周二...)

    CStdPtrArray m_aNotifiers;
    CStdPtrArray m_aTimers;
    CStdPtrArray m_aPreMessageFilters;
    CStdPtrArray m_aMessageFilters;
    CStdPtrArray m_aPostPaintControls;
    CStdPtrArray m_aDelayedCleanup;
    CStdPtrArray m_aAsyncNotify;
    CStdPtrArray m_aFoundControls;
    CStdStringPtrMap m_mNameHash;
    CStdStringPtrMap m_mOptionGroup;
    CStdStringPtrMap m_mSelectGroup;

    在UIManager.cpp中析构函数~CPaintManagerUI()

    RemoveAllFonts();
    RemoveAllImages();
    RemoveAllDefaultAttributeList();
    RemoveAllOptionGroups();
	RemoveAllSelectGroups();
    RemoveAllTimers();
    自定义方法的实现

CStdPtrArray* CPaintManagerUI::GetSelectGroup(LPCTSTR pStrGroupName)
{
	LPVOID lp = m_mSelectGroup.Find(pStrGroupName);
	if( lp ) return static_cast(lp);
	return NULL;
}

bool CPaintManagerUI::AddSelectGroup(LPCTSTR pStrGroupName, CControlUI* pControl)
{
	LPVOID lp = m_mSelectGroup.Find(pStrGroupName);
	if( lp ) {
		CStdPtrArray* aSelectGroup = static_cast(lp);
		for( int i = 0; i < aSelectGroup->GetSize(); i++ ) {
			if( static_cast(aSelectGroup->GetAt(i)) == pControl ) {
				return false;
			}
		}
		aSelectGroup->Add(pControl);
	}
	else {
		CStdPtrArray* aSelectGroup = new CStdPtrArray(6);
		aSelectGroup->Add(pControl);
		m_mSelectGroup.Insert(pStrGroupName, aSelectGroup);
	}
	return true;
}

void CPaintManagerUI::RemoveSelectGroup(LPCTSTR pStrGroupName, CControlUI* pControl)
{
	LPVOID lp = m_mSelectGroup.Find(pStrGroupName);
	if( lp ) {
		CStdPtrArray* aSelectGroup = static_cast(lp);
		if( aSelectGroup == NULL ) return;
		for( int i = 0; i < aSelectGroup->GetSize(); i++ ) {
			if( static_cast(aSelectGroup->GetAt(i)) == pControl ) {
				aSelectGroup->Remove(i);
				break;
			}
		}
		if( aSelectGroup->IsEmpty() ) {
			delete aSelectGroup;
			m_mSelectGroup.Remove(pStrGroupName);
		}
	}
}

void CPaintManagerUI::RemoveAllSelectGroups()
{
	CStdPtrArray* aSelectGroup;
	for( int i = 0; i< m_mSelectGroup.GetSize(); i++ ) {
		if(LPCTSTR key = m_mSelectGroup.GetAt(i)) {
			aSelectGroup = static_cast(m_mSelectGroup.Find(key));
			delete aSelectGroup;
		}
	}
	m_mSelectGroup.RemoveAll();
}

    这样CheckBox就支持三种状态了,例如我现在又周一到周日的几个CheckBox控件,首先先把这几个控件加selectgroup属性,属性的值就填那个做全选按钮name的值,例如这个全选按钮的值为weeks,其他的按钮就都设置selectgroup="weeks",然后再设置CheckBox未全选(半选)的图标属性halfselectedimage="图标路径",这就可以这个全选按钮有三种状态了 :),如果有什么不懂的,可以问我 :)

    如果觉得修改麻烦,可以去下载我已经修改好的源文件。

    http://download.csdn.net/detail/eveyx/7728665


你可能感兴趣的:(DuiLib)