文档章节

Qt树形控件QTreeView使用2——复选框的设置

尘中远
 尘中远
发布于 2016/05/12 23:52
字数 2396
阅读 45
收藏 0
点赞 2
评论 0

目录:

Qt树形控件QTreeView使用1——节点的操作

Qt树形控件QTreeView使用2——复选框的设置

利用C++11的function和bind功能,实现QStandardItemModel的通用遍历函数


 通过QStandardItem和QStandardItemModel可以很简单方便的给QTreeView添加节点,但是,许多树形控件都需要树的节点需要一个复选框(checkBox),网上许多资料都是通过自定义model来实现的,而且不能很好的实现checkbox的父子关联(父节点选中子节点全部选中,父节点不选,子节点全部选),下面将介绍如何使用QStandardItem和QStandardItemModel实现复选框,且实现父子关联




1.使用QStandardItem使树形控件条目带上复选框

复选框在树形控件中经常见到,在QStandardItem中已经封装好了对复选框的一些设置
void QStandardItem:: setCheckable ( bool checkable )
void QStandardItem:: setTristate ( bool tristate )
void QStandardItem:: setCheckState ( Qt::CheckState state )
Qt::CheckState QStandardItem:: checkState () const
bool QStandardItem:: isCheckable () const
bool QStandardItem:: isTristate () const

从字面意思就知道这些函数是干什么的了,但这里要注意一些,checkBox有两种情况,
一种是两态,就是选中和不选中
一种是三态,选中、不选中、不完全选中,如图:


这种三态叫Tristate。
要设置条目有复选框只需要使用QStandardItem的函数setCheckable,无论是两态还是三态都需要先setCheckable,setCheckable默认是两态,如果希望是三态的话,需要再setTristate
示例代码如下:(树形视图节点的具体添加方法见上篇文章)
QStandardItemModel* model = new QStandardItemModel(ui->treeView);
    model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("项目名")<<QStringLiteral("信息"));
    QStandardItem* itemProject = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_Project")],QStringLiteral("项目"));
    model->appendRow(itemProject);
    model->setItem(model->indexFromItem(itemProject).row(),1,new QStandardItem(QStringLiteral("项目信息说明")));
    QStandardItem* itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")],QStringLiteral("文件夹1"));
    itemProject->appendRow(itemFolder);
    itemProject->setChild(itemFolder->index().row(),1,new QStandardItem(QStringLiteral("信息说明")));
    itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")],QStringLiteral("文件夹2"));
    itemProject->appendRow(itemFolder);
    for(int i=0;i<5;++i){
        QStandardItem* itemgroup = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_group")],QStringLiteral("组%1").arg(i+1));
        itemFolder->appendRow(itemgroup);
        for(int j=0;j<(i+1);++j){
            QStandardItem* itemchannel = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_channel")],QStringLiteral("频道%1").arg(j+1));
            itemgroup->appendRow(itemchannel);
            itemgroup->setChild(itemchannel->index().row(),1,new QStandardItem(QStringLiteral("频道%1信息说明").arg(j+1)));
        }
    }
    itemProject->setChild(itemFolder->index().row(),1,new QStandardItem(QStringLiteral("文件夹2信息说明")));
    itemProject = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_Project")],QStringLiteral("项目2"));
    model->appendRow(itemProject);
    for(int i =0;i<3;++i)
    {
        itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")],QStringLiteral("项目2文件夹%1").arg(i+1));
        itemFolder->setCheckable(true);
        itemFolder->setTristate(true);
        QStandardItem* itemFolderDes = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_group")],QStringLiteral("文件夹%1组").arg(i+1));
        itemProject->appendRow(itemFolder);
        itemProject->setChild(itemFolder->index().row(),1,itemFolderDes);
        for(int j=0;j<i+1;++j)
        {
             QStandardItem* item = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_dataItem")],QStringLiteral("项目%1").arg(j+1));
             item->setCheckable(true);
             itemFolder->appendRow(item);

        }
    }
    //关联项目属性改变的信号和槽
    connect(model,&QStandardItemModel::itemChanged,this,&Widget::treeItemChanged);
    //connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(treeItemChanged(QStandardItem*)));
    ui->treeView->setModel(model);



代码中 m_publicIconMap 是QMap<QString,QIcon>对象,用于存放定义好的图标,在树形视图节点添加之前进行初始化,初始化代码如下:
m_publicIconMap[QStringLiteral("treeItem_Project")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/Project.png"));
m_publicIconMap[QStringLiteral("treeItem_folder")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/folder.png"));
m_publicIconMap[QStringLiteral("treeItem_folder-ansys")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/folder-ansys.png"));
m_publicIconMap[QStringLiteral("treeItem_group")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/group.png"));
m_publicIconMap[QStringLiteral("treeItem_channel")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/channel.png"));

效果图:

2.三态复选框的智能关联

三态复选框的主要体现就在树形控件里,如果子项目全选,父级需要全选,如果子项目部分选,父级就是不完全选
下图是三态的正确表现方法



但QTreeView在QStandardItem设置复选框后,并不是按照规则的,这时需要进行代码设置

2.1 捕获复选框改变的信号

要对复选框进行操作,首先需要捕获树形视图的复选框改变发出的信号
通过QStandardItemModel设置的项目,任何改变都会触发void QStandardItemModel::itemChanged(QStandardItem * item)信号
因此需要定义一个槽函数和这个信号关联
private slots :
void treeItem_CheckChildChanged ( QStandardItem * item );


关联代码写在model创建之后的地方:
//关联项目属性改变的信号和槽
connect ( model ,&QStandardItemModel::itemChanged , this ,&Widget::treeItemChanged );
//connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(treeItemChanged(QStandardItem*)));

这里使用最新的信号和槽的关联方法,记得在pro文件中加入如下,使得支持C++11
CONFIG+=c++11
槽函数的写法如下:
void Widget : : treeItemChanged ( QStandardItem * item )
{
}

下面开始实现三态的自动关联(父子节点checkbox自动关联)

2.2 父子节点复选框自动关联实现

void Widget : : treeItemChanged ( QStandardItem * item )
{
    if ( item == nullptr )
    return ;
    if ( item - > isCheckable ())
    {
        //如果条目是存在复选框的,那么就进行下面的操作
        Qt : : CheckState state = item - > checkState (); //获取当前的选择状态
        if ( item - > isTristate ())
        {
             //如果条目是三态的,说明可以对子目录进行全选和全不选的设置
            if ( state != Qt : : PartiallyChecked )
            {
                //当前是选中状态,需要对其子项目进行全选
                treeItem_checkAllChild ( item , state == Qt : : Checked ? true : false );
            }
        }
        else
        {
            //说明是两态的,两态会对父级的三态有影响
            //判断兄弟节点的情况
            treeItem_CheckChildChanged ( item );
        }
    }
}


首先要判断条目的状态,如果条目是有复选框的话,那么就进行操作。通过函数isCheckable()可以判断条目是否有复选框
在确认条目有复选框后,需要获取当前条目的选中状态,使用checkState ()函数可以判断当前条目的选中状态;
现在分两种情况:
1.如果条目是三态的,说明要判断它的子节点。条目选中时,所有子节点都将选中,条目不选中时,所有子节点都不选中
2.如果条目是两态的,说明可能会影响它的三态的父节点,当两态节点选中且其所有的兄弟节点都选中,三态父节点选中,若两态子节点和其兄弟节点都没选中,那么其三态父节点将不选中,若果兄弟节点有选中有不选中,三态父节点将是处于不完全选中状态

2.2.1 子节点递归全选

treeItem_checkAllChild 函数是用于使子节点全选的函数。这个函数实现如下:

///
/// \brief 递归设置所有的子项目为全选或全不选状态
/// \param item 当前项目
/// \param check true时为全选,false时全不选
///
void Widget::treeItem_checkAllChild(QStandardItem * item, bool check)
{
    if(item == nullptr)
        return;
    int rowCount = item->rowCount();
    for(int i=0;i<rowCount;++i)
    {
        QStandardItem* childItems = item->child(i);
        treeItem_checkAllChild_recursion(childItems,check);
    }
    if(item->isCheckable())
        item->setCheckState(check ? Qt::Checked : Qt::Unchecked);
}
void Widget::treeItem_checkAllChild_recursion(QStandardItem * item,bool check)
{
    if(item == nullptr)
        return;
    int rowCount = item->rowCount();
    for(int i=0;i<rowCount;++i)
    {
        QStandardItem* childItems = item->child(i);
        treeItem_checkAllChild_recursion(childItems,check);
    }
    if(item->isCheckable())
        item->setCheckState(check ? Qt::Checked : Qt::Unchecked);
}


通过这个功能实现,可以看看如何对树形节点的所有子节点进行遍历,一般树形节点的遍历是通过递归来实现的(递归的效率不是最高的,可以把递归拆解为循环)。
QStandardItem的child方法可以获取它的下级子节点,在这个方法之前现需要查明有多少个子节点,rowCount()方法是获取树形节点下一级的子节点个数(在树形视图中,每个节点的子节点算作这个节点的条目,第一个节点就是第一行,第二个就是第二行,以此类推,如果树形视图有多列的话,那么列也会起作用)。
treeItem_checkAllChild_recursion是个递归函数,通过这个函数可以把树形节点的所有子节点遍历一遍。
通过上面的这个方法,即可实现第一种情况。

2.2.2 父节点递归处理


treeItem_CheckChildChanged函数是用于处理第二种情况的,此函数主要对父级节点有影响,函数实现如下:
///
/// \brief 根据子节点的改变,更改父节点的选择情况
/// \param item
///
void Widget::treeItem_CheckChildChanged(QStandardItem * item)
{
    if(nullptr == item)
        return;
    Qt::CheckState siblingState = checkSibling(item);
    QStandardItem * parentItem = item->parent();
    if(nullptr == parentItem)
        return;
    if(Qt::PartiallyChecked == siblingState)
    {
        if(parentItem->isCheckable() && parentItem->isTristate())
            parentItem->setCheckState(Qt::PartiallyChecked);
    }
    else if(Qt::Checked == siblingState)
    {
        if(parentItem->isCheckable())
            parentItem->setCheckState(Qt::Checked);
    }
    else
    {
        if(parentItem->isCheckable())
            parentItem->setCheckState(Qt::Unchecked);
    }
    treeItem_CheckChildChanged(parentItem);
}


此函数也是一个递归函数,首先要判断的是父级是否到达顶层,到达底层作为递归的结束,然后通过函数checkSibling判断当前的兄弟节点的具体情况,checkSibling方法的实现如下:

///
/// \brief 测量兄弟节点的情况,如果都选中返回Qt::Checked,都不选中Qt::Unchecked,不完全选中返回Qt::PartiallyChecked
/// \param item
/// \return 如果都选中返回Qt::Checked,都不选中Qt::Unchecked,不完全选中返回Qt::PartiallyChecked
///
Qt::CheckState Widget::checkSibling(QStandardItem * item)
{
    //先通过父节点获取兄弟节点
    QStandardItem * parent = item->parent();
    if(nullptr == parent)
        return item->checkState();
    int brotherCount = parent->rowCount();
    int checkedCount(0),unCheckedCount(0);
    Qt::CheckState state;
    for(int i=0;i<brotherCount;++i)
    {
        QStandardItem* siblingItem = parent->child(i);
        state = siblingItem->checkState();
        if(Qt::PartiallyChecked == state)
            return Qt::PartiallyChecked;
        else if(Qt::Unchecked == state)
            ++unCheckedCount;
        else
            ++checkedCount;
        if(checkedCount>0 && unCheckedCount>0)
            return Qt::PartiallyChecked;
    }
    if(unCheckedCount>0)
        return Qt::Unchecked;
    return Qt::Checked;
}

checkSibling用于判断兄弟节点的关系,兄弟节点之间无外乎三种关系:
1.全选
2.全不选
3.部分选中
获取QStandardItem的兄弟节点有多种方法,这里是通过获取它的父级在获取父级的子节点来得到包括它自己的所有兄弟节点,另外QStandardItem可以通过函数QModelIndex index() const;获取Item对应的QModelIndex,QModelIndex有QModelIndex QModelIndex::sibling(int row, int column) const方法获取兄弟节点。
通过以上几个函数,即可实现QTreeView的复选框及自动识别勾选的功能。
下面放出效果图:





© 著作权归作者所有

共有 人打赏支持
尘中远
粉丝 1
博文 26
码字总数 47436
作品 0
朝阳
程序员
QT中的树型控件QTreeWidget和checkstate的使用

今天简单说一下Qt的树形控件,在Qt中树形控件的名称叫做QTreeWidget,而控件里的树节点的名称叫做QTreeWidgetItem。今天这 里讲的是如何创建具有复选框的树形控件: 当选中顶层的树形节点时,...

barsoom ⋅ 2012/11/02 ⋅ 0

PyQt5教程(六)——控件

原文:http://zetcode.com/gui/pyqt5/widgets/ 控件是应用程序的基础构件。PyQt5具有类目广泛的各种控件,包括按钮、复选框、滑动条、列表框等。在本节教程中,我们将学习几个很有用的控件:...

pseudo ⋅ 2015/12/15 ⋅ 0

带复选框的CTreeCtrl响应复选消息

1.在对话框中添加CTreeCtrl控件并勾选Check Boxes选项,为CTreeCtrl控件添加CTreeCtrl变量m_tree; 2.为CTreeCtrl控件添加NM_CLICK消息响应函数OnClickTree();代码如下: OnClickTree(NMHDR pNM...

barsoom ⋅ 2013/01/30 ⋅ 0

《Qt 实战一二三》

简介 “我们来自Qt分享&&交流,我们来自QML分享&&交流”,不管你是笑了,还是笑了,反正我们是认真的。我们就是要找寻一种Hold不住的状态,来开始每一天的点滴分享,我们是一个有激情,有态度...

u011012932 ⋅ 2015/12/12 ⋅ 0

Qt控件上下布局,根据数据量自己扩充功能。

我要在固定大小的窗口里添加两个QTreeView控件,用QVBoxLayout进行上下布局。 要求两个QTreeView控件都要展开,以便用户查阅。而展开的时候每个控制不够显示全部内容。 现在有一个需求就是,...

临峰不畏 ⋅ 2013/12/24 ⋅ 2

功能表单字段选择数据类型的配置详解——JEPLUS快速开发平台

功能表单字段之下拉框、单选框、多选框、树形选择数据类型的配置详解 JEPLUS平台的表单支持有多种不同的数据类型,这些不同的数据类型在展示不同类型的数据时能有很好的效果,今天这篇笔记就...

JEPLUS ⋅ 06/12 ⋅ 0

动手改造柴哥的Html2Tree

原文发表在:http://www.birchlee.com/post/2011/10/25/31.aspx 最近在使用一些js,jQuery树形控件,大多数都是基于json格式,都是按照要求的数据格式才能出固定的树形。扩展性差,还要研究他...

birchlee ⋅ 2011/10/25 ⋅ 0

Qt:在TreeModel+QTreeView中使用复选框(checkbox)

转自:http://blog.csdn.net/vah101/article/details/6190809 需要实现一个功能:在QT的TreeView中,能够使用复选框,并且选中父节点的复选框可以全选或取消子节点的复选框。这里就以QT附带的...

长平狐 ⋅ 2013/01/11 ⋅ 0

MFC界面库BCGControlBar v25.0新功能详解二:网格和报表控件

BCGControlBar Pro for MFC最新试用版下载请猛戳>>> 亲爱的BCGSoft用户,我们非常高兴地宣布BCGControlBar Professional for MFC和BCGSuite for MFC v25.0正式发布!我们为您提供开发桌面应用...

Miss_Hello_World ⋅ 2016/07/06 ⋅ 0

浅谈 Qt 布局管理器 如何让控件随着窗口变化

Qt 布局管理器 基础学习是本文要介绍的内容,学习Qt的时候,参照帮助手册和相关书籍,其中的例子几乎都是手动的编写代码。至于方便设计界面的Qt designer的例子几乎就没有,想在designer中实...

barsoom ⋅ 2012/10/19 ⋅ 1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Centos7重置Mysql 8.0.1 root 密码

问题产生背景: 安装完 最新版的 mysql8.0.1后忘记了密码,向重置root密码;找了网上好多资料都不尽相同,根据自己的问题总结如下: 第一步:修改配置文件免密码登录mysql vim /etc/my.cnf 1...

豆花饭烧土豆 ⋅ 今天 ⋅ 0

熊掌号收录比例对于网站原创数据排名的影响[图]

从去年下半年开始,我在写博客了,因为我觉得业余写写博客也还是很不错的,但是从2017年下半年开始,百度已经推出了原创保护功能和熊掌号平台,为此,我也提交了不少以前的老数据,而这些历史...

原创小博客 ⋅ 今天 ⋅ 0

LVM讲解、磁盘故障小案例

LVM LVM就是动态卷管理,可以将多个硬盘和硬盘分区做成一个逻辑卷,并把这个逻辑卷作为一个整体来统一管理,动态对分区进行扩缩空间大小,安全快捷方便管理。 1.新建分区,更改类型为8e 即L...

蛋黄Yolks ⋅ 今天 ⋅ 0

Hadoop Yarn调度器的选择和使用

一、引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色。在讨论其构造器之前先简单了解一下Yarn的架构。 上图是Yarn的基本架构,其中ResourceManager是整个架构的核心组件,它负...

p柯西 ⋅ 今天 ⋅ 0

uWSGI + Django @ Ubuntu

创建 Django App Project 创建后, 可以看到路径下有一个wsgi.py的问题 uWSGI运行 直接命令行运行 利用如下命令, 可直接访问 uwsgi --http :8080 --wsgi-file dj/wsgi.py 配置文件 & 运行 [u...

袁祾 ⋅ 今天 ⋅ 0

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 2

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部