Qt,优化QTreeWidget的三态:勾选,未勾选,半勾选

      这是以前做过的例子,之前是参考的网上的例子,觉得遍历次数太多,效率不行。自己尝试优化修改了一番。小试牛刀,欢迎拍砖。效果如下图:

 

    示例数据做得比较粗糙。来看看是怎么实现的吧。

功能

  •  勾选树控件的节点,其子节点全部选中或全部取消选中
  •  父节点选中或者部分选中

实现

QTreeWidgetItem的复选框,可以通过setCheckState(int column,Qt::CheckState state)方法调出。

勾选状态的改变,通过itemChanged(QTreeWidgetItem *item,int column)信号触发。

connect(ui->treeWidget,&QTreeWidget::itemChanged,this,&Widget::ItemCheckChanged);

节点勾选状态的改变,1,需要改变其子节点的状态;2 ,需要改变父节点的状态;

子节点的状态改变,通过一个递归就可以实现,要么全部勾选,要么全部不勾选:

void Widget::UpdateChild(QTreeWidgetItem *itm)
{
    int childCount = itm->childCount();
    if(childCount > 0)
    {
        for(int i = 0; i < childCount; i++)
        {
            itm->child(i)->setCheckState(0,itm->checkState(0));
            if(itm->child(i)->childCount() > 0)
                UpdateChild(itm->child(i));
        }
    }
}

父节点的状态改变稍稍有点麻烦。存在如下几种情况:

(这个图,我实在是画的难看,就不画了,用这张勉强看看)

 

1. 子节点勾选,兄弟节点不勾,则父节点半勾选,根节点半勾选;

2. 子节点勾选,兄弟节点勾选,则父节点勾选,根节点待定(如果存在父节点的兄弟,需要递归判断);

3. 子节点不勾选,兄弟节点不勾选,则父节点不勾选,根节点待定(同上);

4. 子节点不勾选,兄弟节点勾选,则父节点半勾选,根节点半勾选。

由上可知,1,4两种情况是确定的,不管有多少层,父节点,根节点一定是半勾选,直接递归往上设置就可以了:

void Widget::SetParentPartiallyChecked(QTreeWidgetItem *itm)
{
    QTreeWidgetItem *parent = itm->parent();
    if(parent)
    {
        parent->setCheckState(0,Qt::PartiallyChecked);
        SetParentPartiallyChecked(parent);
    }
}

剩余2,3这两种情况,需要逐层遍历往上判断。

通过获取子节点及兄弟节点的勾选个数与总的节点数进行判断:

1. 勾选数 == 0时,父不勾;

2.勾选数 > 0且 勾选数 < 节点总数时,父半勾;

3.勾选数 == 节点总数时,父勾选。

代码如下:

void Widget::UpdateParent(QTreeWidgetItem *itm)
{
    QTreeWidgetItem *parent = itm->parent();
    if(parent)
    {
        int checkedCount = 0;
        int itemCount = parent->childCount();
        for(int i = 0; i < itemCount; i++)
        {
            QTreeWidgetItem *item = parent->child(i);
            if(Qt::Checked == item->checkState(0))
                checkedCount++;
        }

        if(checkedCount <= 0 )
        {
            parent->setCheckState(0,Qt::Unchecked);
        }
        else if(checkedCount > 0 && checkedCount < itemCount  )
        {
            parent->setCheckState(0,Qt::PartiallyChecked);
            SetParentPartiallyChecked(parent);
            return;
        }
        else if(checkedCount > 0 && checkedCount == itemCount)
        {
            parent->setCheckState(0,Qt::Checked);
        }
        // Recursively iterate up
        UpdateParent(parent);
    }
}

看起来好像没问题了,但是忽略了这种情况,导致如下问题:

根节点应该是半勾选状态,但实际是未勾选。

这是因为在“勾选数 == 0”这种情况下,忽略了对半勾选状态的判断。

“勾选数 == 0”时,还存在两种情况:

1. 半勾选数 ==0 时,父不勾;

2. 半勾选数 > 0时,父半勾。

增加半勾选数量,及相应判断,修改代码如下:

void Widget::UpdateParent(QTreeWidgetItem *itm)
{
    QTreeWidgetItem *parent = itm->parent();
    if(parent)
    {
        int checkedCount = 0;
        int patiallyCount = 0;
        int itemCount = parent->childCount();
        for(int i = 0; i < itemCount; i++)
        {
            QTreeWidgetItem *item = parent->child(i);
            if(Qt::Checked == item->checkState(0))
                checkedCount++;
            else if(Qt::PartiallyChecked == item->checkState(0))
                patiallyCount++;
        }

        if(checkedCount <= 0 )
        {
            if(patiallyCount > 0)
                goto Partially;
            else
                parent->setCheckState(0,Qt::Unchecked);
        }
        else if(checkedCount > 0 && checkedCount < itemCount  )
        {
            Partially:
            parent->setCheckState(0,Qt::PartiallyChecked);
            SetParentPartiallyChecked(parent);
            return;
        }
        else if(checkedCount > 0 && checkedCount == itemCount)
        {
            parent->setCheckState(0,Qt::Checked);
        }
        // Recursively iterate up
        UpdateParent(parent);
    }
}

这样就覆盖了刚刚忽略的情况,实现了gif图的效果。

之前的代码,设置父节点,都是一层层的往上遍历,其实是可以排除一些不必要的遍历。优化整体效率。

全部代码下载地址:

由于csdn的积分制度,原来的资源涨到了9分,就重新上传了一份,结果还是5分起步。唉,能少一点是一点吧。更新一下链接。

https://download.csdn.net/download/xiaosha00000/11212101

这只是自己的一点点拙见,希望有更好的思路,能提出来,相互提高。感谢!

  • 9
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值