原文 https://blog.csdn.net/EveyX/article/details/38433783
DuiLib官方库中的Checkbox只有Checked和Uncheck两种状态,但我们往往要实现这中需求:
显然,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,只是每组只有一个按钮而已,组名为空,配置文件默认属性举例:
/// <CheckBox name="CheckBox" value="height='20' align='left' textpadding='24,0,0,0' normalimage='file='sys_check_btn.png' s///ource='0,0,20,20' dest='0,0,20,20'' selectedimage='file='sys_check_btn.png' source='20,0,40,20' dest='0,0,20,20'' disable///dimage='file='sys_check_btn.png' source='40,0,60,20' dest='0,0,20,20''"/>
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<COptionUI*>(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<COptionUI*>(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<CCheckBoxUI*>(aSelectGroup->GetAt(i)); cnt += pItem->IsSelected() ? 1 : 0; } CCheckBoxUI* pSelectAll = static_cast<CCheckBoxUI*>(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<CStdPtrArray*>(lp); return NULL; } bool CPaintManagerUI::AddSelectGroup(LPCTSTR pStrGroupName, CControlUI* pControl) { LPVOID lp = m_mSelectGroup.Find(pStrGroupName); if( lp ) { CStdPtrArray* aSelectGroup = static_cast<CStdPtrArray*>(lp); for( int i = 0; i < aSelectGroup->GetSize(); i++ ) { if( static_cast<CControlUI*>(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<CStdPtrArray*>(lp); if( aSelectGroup == NULL ) return; for( int i = 0; i < aSelectGroup->GetSize(); i++ ) { if( static_cast<CControlUI*>(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<CStdPtrArray*>(m_mSelectGroup.Find(key)); delete aSelectGroup; } } m_mSelectGroup.RemoveAll(); }
这样CheckBox就支持三种状态了,例如我现在又周一到周日的几个CheckBox控件,首先先把这几个控件加selectgroup属性,属性的值就填那个做全选按钮name的值,例如这个全选按钮的值为weeks,其他的按钮就都设置selectgroup="weeks",然后再设置CheckBox未全选(半选)的图标属性halfselectedimage="图标路径",这就可以这个全选按钮有三种状态了 :),如果有什么不懂的,可以问我 :)
如果觉得修改麻烦,可以去下载我已经修改好的源文件。