当前位置: 首页 > news >正文

实现 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.mrgr.cn/news/81434.html

相关文章:

  • shell -c
  • 网站HTTP改成HTTPS
  • SpringBoot注入配置文件application.properties中的信息
  • 【云计算】OpenStack云计算平台
  • 2024年开发语言热度排名
  • 线上资源访问本地数据-跨域问题总结
  • 单片机:实现可调时钟(附带源码)
  • MarkItDown的使用(将Word、Excel、PDF等转换为Markdown格式)
  • Python|Pyppeteer实现自动化获取reCaptcha验证码图片以及提示词(29)
  • echarts地图可视化展示
  • RSICV国产芯片之CHV208
  • Datawhale-AI活动2024.12.24
  • Linux大数据方向shell
  • 增强路由器
  • 【RAG实战】语言模型基础
  • 微信小程序性能优化
  • 【Linux】数据呈现
  • Redis 介绍和安装
  • 小白考研历程:跌跌撞撞,起起伏伏,五个月备战历程!!!
  • 服务端高并发分布式结构演进之路
  • 使用 acme.sh 申请域名 SSL/TLS 证书完整指南
  • 【Java基础-27】Java中的访问修饰符:分类、作用及应用场景
  • 2.利用docker进行gitlab服务器迁移
  • 面试记录24年新
  • Javaweb (二) | Cookie、Session
  • clickhouse解决suspiciously many的异常