实现 QTreeWidget 中子节点勾选状态的递归更新功能只影响跟节点的状态父节点状态不受影响

在 Qt 开发中,QTreeWidget 提供了树形结构的显示和交互功能。为了实现某个子节点勾选或取消勾选时,只影响当前节点及其子节点的状态,同时递归更新父节点的状态以正确显示 Qt::PartiallyChecked 或 Qt::Checked,我们可以借助 Qt 的信号与槽机制进行处理。以下是详细实现及测试分析

1.功能需求分析

我们希望实现如下功能:

1.1勾选或取消勾选某个子节点时:

仅更新当前节点及其子节点状态。
递归更新最顶层父节点状态(Qt::Checked 或 Qt::PartiallyChecked)。

1.2不影响兄弟节点及父节点的兄弟节点状态。

测试场景如下:
场景 1:部分勾选子节点
根节点 A
子节点 A1 [Checked]
子节点 A2 [Unchecked]
结果:根节点 A 的状态为 Qt::PartiallyChecked。
场景 2:全部勾选子节点
根节点 B
子节点 B1 [Checked]
子节点 B2 [Checked]
结果:根节点 B 的状态为 Qt::Checked。
场景 3:多层嵌套
根节点 C
子节点 C1
子节点 C1.1 [Checked]
子节点 C1.2 [Unchecked]
子节点 C2 [Checked]
结果:子节点 C1 的状态为 Qt::PartiallyChecked,根节点 C 的状态为 Qt::PartiallyChecked。

2 效果展示

在这里插入图片描述

3.实现步骤

3.1 main.cpp

#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

3.2 main.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTreeWidget>class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:QTreeWidget *treeWidget;void setupTree();// checkedCount  子节点中已勾选的数量void updateParentState(QTreeWidgetItem *item,int checkedCount = 0);void updateChildState(QTreeWidgetItem *item, Qt::CheckState state);// 使用 统计节点数量int countDescendants(QTreeWidgetItem *node);//获取当前节点下的勾选状态bool areAllDescendantsChecked(QTreeWidgetItem *node);
private slots:void onItemChanged(QTreeWidgetItem *item, int column);
};#endif // MAINWINDOW_H

3.3 main.cpp

#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), treeWidget(new QTreeWidget(this)) {setCentralWidget(treeWidget);setupTree();// 连接信号槽connect(treeWidget, &QTreeWidget::itemChanged, this, &MainWindow::onItemChanged);
}MainWindow::~MainWindow() {}void MainWindow::setupTree() {treeWidget->setColumnCount(1);treeWidget->setHeaderLabel("Tree Example");// 添加根节点 A,及其子节点QTreeWidgetItem *rootA = new QTreeWidgetItem(treeWidget, QStringList("A"));rootA->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childA1 = new QTreeWidgetItem(rootA, QStringList("A1"));childA1->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childA2 = new QTreeWidgetItem(rootA, QStringList("A2"));childA2->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childA3 = new QTreeWidgetItem(childA2, QStringList("A2.1"));childA3->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childA4 = new QTreeWidgetItem(childA2, QStringList("A2.2"));childA4->setCheckState(0, Qt::Unchecked);// 添加根节点 B,及其子节点QTreeWidgetItem *rootB = new QTreeWidgetItem(treeWidget, QStringList("B"));rootB->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childB1 = new QTreeWidgetItem(rootB, QStringList("B1"));childB1->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childB2 = new QTreeWidgetItem(rootB, QStringList("B2"));childB2->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childB3 = new QTreeWidgetItem(childB2, QStringList("B2.1"));childB3->setCheckState(0, Qt::Unchecked);// 添加根节点 C,及其多层子节点QTreeWidgetItem *rootC = new QTreeWidgetItem(treeWidget, QStringList("C"));rootC->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childC1 = new QTreeWidgetItem(rootC, QStringList("C1"));childC1->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childC2 = new QTreeWidgetItem(childC1, QStringList("C1.1"));childC2->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childC3 = new QTreeWidgetItem(childC1, QStringList("C1.2"));childC3->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childC31 = new QTreeWidgetItem(childC1, QStringList("C1.3"));childC31->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childC4 = new QTreeWidgetItem(rootC, QStringList("C2"));childC4->setCheckState(0, Qt::Unchecked);// 添加根节点 D,及其子节点QTreeWidgetItem *rootD = new QTreeWidgetItem(treeWidget, QStringList("D"));rootD->setCheckState(0, Qt::Unchecked);QTreeWidgetItem *childD1 = new QTreeWidgetItem(rootD, QStringList("C1"));childD1->setCheckState(0, Qt::Unchecked);
}void MainWindow::onItemChanged(QTreeWidgetItem *item, int column) {if (column != 0) return;treeWidget->blockSignals(true);// 防止递归调用 信号屏蔽Qt::CheckState state = item->checkState(0);// 更新子节点状态updateChildState(item, state);updateParentState(item);// 更新父节点状态treeWidget->blockSignals(false);// 恢复信号
}void MainWindow::updateChildState(QTreeWidgetItem *item, Qt::CheckState state) {for (int i = 0; i < item->childCount(); ++i) {QTreeWidgetItem *child = item->child(i);child->setCheckState(0, state);updateChildState(child, state);// 递归处理子节点}
}int MainWindow::countDescendants(QTreeWidgetItem *node)
{if (!node) return 0;int count = 0;// 遍历直接子节点for (int i = 0; i < node->childCount(); ++i) {QTreeWidgetItem *child = node->child(i);++count; // 当前子节点计数count += countDescendants(child); // 递归统计子节点的子节点}return count;
}bool MainWindow::areAllDescendantsChecked(QTreeWidgetItem *node)
{if (!node) return false;// 遍历子节点for (int i = 0; i < node->childCount(); ++i) {// 检查当前节点的状态QTreeWidgetItem *child = node->child(i);QString Text = child->text(0);if (child->checkState(0) != Qt::Checked) {return false;}if (!areAllDescendantsChecked(node->child(i))) {return false;}}return true;
}void MainWindow::updateParentState(QTreeWidgetItem *item,int checkedCount) {QTreeWidgetItem *parent = item->parent();if (!parent) return;int childCheckedCount = checkedCount;int partiallyCheckedCount = 0; // 子节点中部分勾选的数量int parentCheckedCount = 0; //检验根节点选择个数(只针对根节点有用)// 遍历所有子节点,统计状态for (int i = 0; i < parent->childCount(); ++i) {QTreeWidgetItem *child = parent->child(i);// 递归更新父节点QString text = child->text(0);if (child->checkState(0) == Qt::Checked) {++checkedCount;if(parent->parent() == nullptr){++parentCheckedCount;}} else if (child->checkState(0) == Qt::PartiallyChecked) {++partiallyCheckedCount;}}// 根据子节点状态更新 根节点状态if(parent->parent() == nullptr ){if (checkedCount == parent->childCount()) {//第二层if(parentCheckedCount == parent->childCount()){//分情况考虑 只考虑第二层节点bool status = false;for (int i = 0; i < parent->childCount(); ++i) {QTreeWidgetItem *child = parent->child(i);status = areAllDescendantsChecked(child);if(!status){break;}}if(status){parent->setCheckState(0, Qt::Checked);}else{parent->setCheckState(0, Qt::PartiallyChecked);}}else if(checkedCount != 0){parent->setCheckState(0, Qt::PartiallyChecked);}else{}} else if (checkedCount > 0 || partiallyCheckedCount > 0) {parent->setCheckState(0, Qt::PartiallyChecked);} else {parent->setCheckState(0, Qt::Unchecked);}}// 递归更新父节点updateParentState(parent,checkedCount);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/495512.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机图形学知识点汇总

一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中&#xff0c;“形”指形体或形状&#xff0c;存在于客观世界和虚拟世界&#xff0c;它的本质是“表示”&#xff1b;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面&#xff0c;用于表达…

Yolo11改策略:卷积改进|SAC,提升模型对小目标和遮挡目标的检测性能|即插即用

摘要 一、论文介绍 本文参考的论文主要介绍了DetectoRS模型&#xff0c;一个高性能的目标检测模型。DetectoRS通过引入递归特征金字塔&#xff08;RFP&#xff09;和可切换空洞卷积&#xff08;SAC&#xff09;两大创新点&#xff0c;显著提升了目标检测的精度。尽管原文并未…

Y3编辑器教程8:资源管理器与存档、防作弊设置

文章目录 一、资源管理器简介1.1 界面介绍1.2 资源商店1.3 AI专区1.3.1 AI文生图1.3.2 AI图生图1.3.3 立绘头像 二、导入导出2.1 文件格式2.2 模型导入2.2.1 模型制作后导出2.2.2 模型文件导入Y3编辑器2.2.3 Y3编辑器角色、装饰物模型要求 2.3 纹理导入2.4 材质贴图2.4.1 材质支…

【联动】【MSS】【AF】

【联动】【MSS】【AF】 一、版本要求 AF&#xff1a;不低于8.0.7&#xff1b;AF8.0.7R2不支持接入 二、接入配置 2.1、AF配置 对于AF8.0.13版本及以上&#xff0c;登录WEB控制台&#xff0c;点击[下一代安全防护体系] -> [云网联动] -> [云网接入设置]&#xff0c;然…

攻防世界 cookie

开启场景 Cookie&#xff08;HTTP cookie&#xff09;是一种存储在用户计算机上的小型文本文件。它由网站通过用户的浏览器在用户访问网站时创建&#xff0c;并存储一些用于跟踪和识别用户的信息。Cookie 主要用于在网站和浏览器之间传递数据&#xff0c;以便网站可以根据用户的…

STM32-笔记11-手写带操作系统的延时函数

1、为什么带操作系统的延时函数&#xff0c;和笔记10上的延时函数不能使用同一种&#xff1f; 因为笔记10的延时函数在每次调用的时候&#xff0c;会一直开关定时器&#xff0c;而在FreeRTOS操作系统中&#xff0c;SysTick定时器当作时基使用。 时基是一个时间显示的基本单位。…

JWT令牌与微服务

1. 什么是JWT JWT&#xff08;JSON Web Token&#xff09;是一种开放标准(RFC 7519)&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于作为JSON对象在各方之间安全地传输信息。JWT通常用于身份验证和信息交换。 以下是JWT的一些关键特性&#xff1a; 紧凑&#xff…

代码随想录Day37 动态规划:完全背包理论基础,518.零钱兑换II,本周小结动态规划,377. 组合总和 Ⅳ,70. 爬楼梯(进阶版)。

1.完全背包理论基础 思路 完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 完…

【多时段】含sop的配电网重构【含分布式电源】【已更新视频讲解】

1 主要内容 之前分享了很多配电网重构的程序&#xff0c;每个程序针对场景限定性比较大&#xff0c;程序初学者修改起来难度较大&#xff0c;本次分享一个基础程序&#xff0c;针对含sop的配电网重构模型&#xff0c;含风电和光伏&#xff0c;优化了33节点网络电压合理性&…

查看php已安装扩展命令

在powershell中查看完整的拓展 php -m 指定搜索某几个拓展 php -m | Select-String -Pattern "xml"

YOLOv11 引入高效的可变形卷积网络 DCNv4 | 重新思考用于视觉应用的动态和稀疏算子

我们介绍了可变形卷积v4(DCNv4),这是一种为广泛的视觉应用设计的高效且有效的算子。DCNv4通过以下两项关键改进解决了其前身DCNv3的局限性: 在空间聚合中移除softmax归一化,以增强其动态特性和表达能力。优化内存访问,减少冗余操作以提高速度。这些改进使得DCNv4相比DCNv…

vue 基础学习

一、ref 和reactive 区别 问题&#xff1a;发生跨域问题 Access to script at file:///Users/new/Desktop/webroot/vue/vue.esm-browser.js from origin null has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome, chrom…

AIA - IMSIC之二(附IMSIC处理流程图)

本文属于《 RISC-V指令集基础系列教程》之一,欢迎查看其它文章。 1 ​​​​​​​通过IMSIC接收外部中断的CSR 软件通过《AIA - 新增的CSR》描述的CSR来访问IMSIC。 machine level 的 CSR 与 IMSIC 的 machine level interrupt file 可相互互动;而 supervisor level 的 CSR…

光谱相机的工作原理

光谱相机的工作原理主要基于不同物质对不同波长光的吸收、反射和透射特性存在差异&#xff0c;以下是其具体工作过程&#xff1a; 一、光的收集 目标物体在光源照射下&#xff0c;其表面会对光产生吸收、反射和透射等相互作用。光谱相机的光学系统&#xff08;如透镜、反射镜…

Kafka可视化工具 Offset Explorer (以前叫Kafka Tool)

数据的存储是基于 主题&#xff08;Topic&#xff09; 和 分区&#xff08;Partition&#xff09; 的 Kafka是一个高可靠性的分布式消息系统&#xff0c;广泛应用于大规模数据处理和实时, 为了更方便地管理和监控Kafka集群&#xff0c;开发人员和运维人员经常需要使用可视化工具…

TLDR:终端命令的简洁百科全书

TLDR&#xff0c;全称 “Too Long, Don’t Read”&#xff0c;是一款特别实用的终端命令百科全书工具。通过 TLDR&#xff0c;您可以快速查找到常用命令的使用方法&#xff0c;避免繁琐冗长的官方文档&#xff0c;让日常工作更加高效。 为什么选择 TLDR&#xff1f; 简单易用&…

2024-12-25-sklearn学习(20)无监督学习-双聚类 料峭春风吹酒醒,微冷,山头斜照却相迎。

文章目录 sklearn学习(20) 无监督学习-双聚类1 Spectral Co-Clustering1.1 数学公式 2 Spectral Biclustering2.1 数学表示 3 Biclustering 评价 sklearn学习(20) 无监督学习-双聚类 文章参考网站&#xff1a; https://sklearn.apachecn.org/ 和 https://scikit-learn.org/sta…

数据结构(Java版)第六期:LinkedList与链表(一)

目录 一、链表 1.1. 链表的概念及结构 1.2. 链表的实现 专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 一、链表 1.1. 链表的概念及结构 链表是⼀种物理存储结构上⾮连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引⽤链接次序实现的。与火车…

《Java核心技术I》Swing的网格包布局

复杂的布局管理 网格包布局 行列大小可改变&#xff0c;先建立表格&#xff0c;合并相邻单元格&#xff0c;组件指定在格内的对齐方式。 字体选择器组件&#xff1a; 另个指定字体和字体大小的组合框两个组合框标签两个选择粗体和斜体的复选框一个显示示例字符串的文本区 将容…

Python——day09

os模块 sys模块 time模块 logging模块