原文 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")) == ) SetSelectGroup(pstrValue);
else if (_tcscmp(pstrName, _T("halfselectedimage")) == ) 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) != )
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 = ; 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 = ; 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 = ;
for (int i = ; i < aSelectGroup->GetSize(); i++) {
CCheckBoxUI* pItem = static_cast<CCheckBoxUI*>(aSelectGroup->GetAt(i));
cnt += pItem->IsSelected() ? : ;
}
CCheckBoxUI* pSelectAll = static_cast<CCheckBoxUI*>(m_pManager->FindControl(m_sSelectGroupName));
if (cnt == ) // 全不选
{
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) != && IsSelected() && !m_sSelectedHotImage.IsEmpty()) {
if( !DrawImage(hDC, (LPCTSTR)m_sSelectedHotImage) )
m_sSelectedHotImage.Empty();
else goto Label_ForeImage;
}
else if( (m_uButtonState & UISTATE_SELECTED) != ) {
if( !m_sSelectedImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sSelectedImage) ) m_sSelectedImage.Empty();
else goto Label_ForeImage;
}
else if(m_dwSelectedBkColor != ) {
CRenderEngine::DrawColor(hDC, m_rcPaint, GetAdjustColor(m_dwSelectedBkColor));
return;
}
}
else if( (m_uButtonState & UISTATE_HALFSELECTED) != ) {
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 = ; i < aSelectGroup->GetSize(); i++ ) {
if( static_cast<CControlUI*>(aSelectGroup->GetAt(i)) == pControl ) {
return false;
}
}
aSelectGroup->Add(pControl);
}
else {
CStdPtrArray* aSelectGroup = new CStdPtrArray();
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 = ; 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 = ; 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="图标路径",这就可以这个全选按钮有三种状态了 :),如果有什么不懂的,可以问我 :)

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

让DuiLib CheckBox支持全选、全不选、非全选三种状态的更多相关文章

  1. TreeView的三种状态,全选,全不选,半选中

    我知道的设置treeview节点的三种状态,如果不是买的控件,那么通过代码,只能设置两种状态,我知道的有三种方法, 第一种是重写treeview,第二种是把三种状态做成小图标,让节点复选框随着不同的状 ...

  2. WPF中CheckBox三种状态打勾打叉和滑动效果

    本文分为两个demo, 第一个demo实现checkBox的打叉或打勾的效果: 第二个demo部分实现checkBox的滑动效果. Demo1: wpf的CheckBox支持三种状态,但是美中不足的是 ...

  3. 【翻译】checkbox的第三种状态

    checkbox只有两种值:选中(checked)或未选中(unchecked).它可以有任何值,但是表单提交时checkbox的值只能是checked或unchecked.它的默认值是uncheck ...

  4. IOS(苹果手机)使用video播放HLS流,实现在内部播放及全屏播放(即非全屏和全屏播放)。

    需求: 实现PC及移动端播放HLS流,并且可以自动播放,在页面内部播放及全屏播放功能. 初步:PC及安卓机使用hls.js实现hls流自动播放及全屏非全屏播放 首先使用了hls.js插件,可以实现在P ...

  5. (最全)Xpath、Beautiful Soup、Pyquery三种解析库解析html 功能概括

    一.Xpath 解析   xpath:是一种在XMl.html文档中查找信息的语言,利用了lxml库对HTML解析获取数据. Xpath常用规则: nodename :选取此节点的所有子节点 // : ...

  6. checkbox,三种状态设置

    多选按钮的  选中.未选中.半选中(常用于子项有选中,未全选) <input id="ckeckbox" type="checkbox"> $('# ...

  7. checkbox的三种状态处理

    checkbox只有两种值:选中(checked)或未选中(unchecked).它可以有任何值,但是表单提交时checkbox的值只能是checked或unchecked.它的默认值是uncheck ...

  8. Devexpress treelist 树形控件 实现带三种状态的CheckBox

    树形控件是使用频率很高的一种控件.对于属性控件往往需要下面两个功能 1.TreeList带有CheckBox,并且节点要有三种状态(所有的子节点都选中,所有的子节点都没选择,一部分子节点选中).使用 ...

  9. HTML5文件上传qq、百度、taobao等比较(改进支持三种状态提示)

    拖拽过程详解: 1:文件未拖出文件选择框的时候提示:将要上传的文件或文件夹拖拽至此区域 2:文件拖出文件选择框但未拖入上传的文件框提示:请继续拖拽文件或文件夹至此区域 3:文件拖出文件选择框且已拖入上 ...

随机推荐

  1. Asp.Net Core集成Swagger

    工作中一个公司会有很多个项目,项目之间的交互经常需要编写 API 来实现,但是编写文档是一件繁琐耗时的工作,并且随着 API 的迭代,每次都需要去更新维护接口文档,很多时候由于忘记或者人员交替的愿意造 ...

  2. ng接口API开发文档

    接口版本:v1 接口协议:请商户对接使用对应的转账接口API和免转接口API,商户只能使用菜单对应的API,否则接口会调用失败.左侧菜单未注明的接口免转钱包和转账钱包可以共同使用所有采集均按照北京时间 ...

  3. [转帖]hive与hbase的联系与区别:

    https://www.cnblogs.com/xubiao/p/5571176.html 原作者写的很好.. 这里面简单学习总结一下.. 都是bigdata的工具, 都是基于google的bigta ...

  4. 微软的一道网红Java面试题

    题目: 给定一个int类型数组:int[] array = new int[]{12, 2, 3, 3, 34, 56, 77, 432}, 让该数组的每个位置上的值去除以首位置的元素,得到的结果,作 ...

  5. Django Simple Captcha的使用

    Django Simple Captcha的使用 1.下载Django Simple Captcha django-simple-captcha官方文档地址 http://django-simple- ...

  6. python 虚拟环境 venv 简单用法

    Python3.3以上的版本通过venv模块原生支持虚拟环境,可以代替Python之前的virtualenv.该venv模块提供了创建轻量级“虚拟环境”,提供与系统Python的隔离支持.每一个虚拟环 ...

  7. React-intl相关使用介绍

    React-intl用于国际化react组件,提供react组件和api来格式化日期.数字,字符等等.其中一个很重要的功能是实现文本翻译,将你所做的中文版应用所有文字转为英文. 关于配置什么的,请参照 ...

  8. mysql存储emoji表情报错的处理方法【更改编码为utf8mb4】

    utf-8编码可能2个字节.3个字节.4个字节的字符,但是MySQL的utf8编码只支持3字节的数据,而移动端的表情数据是4个字节的字符.如果直接往采用utf-8编码的数据库中插入表情数据,Java程 ...

  9. MySQL 常用函数介绍

    MySQL 基础篇 三范式 MySQL 军规 MySQL 配置 MySQL 用户管理和权限设置 MySQL 常用函数介绍 MySQL 字段类型介绍 MySQL 多列排序 MySQL 行转列 列转行 M ...

  10. Unity塔防游戏的创建

    看了下塔防游戏的教程,比我想像的还简单一些,有些收获: (1)敌人的移动路径,其时比较简单,用了N个Empty GameObject作为路径点,然后做一个总的Empty GameObject 作为父级 ...