QTreeView 与 QTreeWidget 例子

1. 先举个例子

1班有3个学生:张三、李四、王五
4个学生属性:语文 数学 英语 性别。
语文 数学 英语使用QDoubleSpinBox* 编辑,范围为0到100,1位小数
性别使用QComboBox* 编辑,选项为:男、女
实现效果:
在这里插入图片描述

2. 按照例子实现

2.1 自定义一个QStandardItemModel 来存数据

#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QStyledItemDelegate>
#include <QHeaderView>class CustomStandardItemModel : public QStandardItemModel
{
public:CustomStandardItemModel(QObject *parent = nullptr);Qt::ItemFlags flags(const QModelIndex &index) const override;
};

class CustomStandardItemModel : public QStandardItemModel
{
public:CustomStandardItemModel(QObject *parent = nullptr);Qt::ItemFlags flags(const QModelIndex &index) const override;
};CustomStandardItemModel::CustomStandardItemModel(QObject *parent) : QStandardItemModel(parent)
{// Set up the modelsetColumnCount(2);setHorizontalHeaderLabels(QStringList()<< "属性" << "值") ;// Root itemQStandardItem *rootItem = invisibleRootItem();QStandardItem *classItem = new QStandardItem("1班");rootItem->appendRow(classItem);// StudentsQStringList students = {"张三", "李四", "王五"};for (const QString &student : students){QStandardItem *studentItem = new QStandardItem(student);classItem->appendRow(studentItem);// SubjectsQStringList subjects = {"语文", "数学", "英语", "性别"};for (const QString &subject : subjects){QStandardItem *subjectItem = new QStandardItem(subject);subjectItem->setEditable(false); // Property column is not editableQStandardItem *valueItem = new QStandardItem(subject == "性别"?"女":"100.0");valueItem->setEditable(true); // Value column is editable for level 2studentItem->appendRow(QList<QStandardItem*>() << subjectItem << valueItem);}}
}Qt::ItemFlags CustomStandardItemModel::flags(const QModelIndex &index) const
{if (index.column() == 1 && index.parent().isValid()) {QStandardItem *item = itemFromIndex(index);if (item && item->hasChildren()) {// If the item has children, it's a student node, make value column not editablereturn QAbstractItemModel::flags(index) & ~Qt::ItemIsEditable;}}return QStandardItemModel::flags(index);
}

2.2 自定义一个QStyledItemDelegate 来显示不同的QWidget控件

class CustomDelegate : public QStyledItemDelegate
{
public:CustomDelegate(QObject *parent = nullptr) ;QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;};

CustomDelegate::CustomDelegate(QObject *parent) : QStyledItemDelegate(parent)
{}QWidget *CustomDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{if (index.column() == 1 && index.parent().isValid()){QString property = index.sibling(index.row(), 0).data().toString();if (property == "语文" || property == "数学" || property == "英语"){QDoubleSpinBox *spinBox = new QDoubleSpinBox(parent);spinBox->setRange(0, 100);spinBox->setDecimals(1);return spinBox;} else if (property == "性别") {QComboBox *comboBox = new QComboBox(parent);comboBox->addItem("男");comboBox->addItem("女");return comboBox;}}return QStyledItemDelegate::createEditor(parent, option, index);
}

2.3 使用 QTreeView 来显示

int main(int argc, char *argv[])
{QApplication a(argc, argv);CustomStandardItemModel* model;CustomDelegate* delegate;QTreeView *treeView;treeView = new QTreeView();treeView->setObjectName(QString::fromUtf8("treeView"));treeView->setGeometry(QRect(40, 30, 241, 501));model = new CustomStandardItemModel();delegate = new CustomDelegate();treeView->setModel(model);treeView->setItemDelegate(delegate);treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);treeView->expandAll();treeView->show();bool ret = a.exec();delete model;delete delegate;delete treeView;return ret;
}

2.4 运行效果

在这里插入图片描述

修改语文、数学、英语时,双击后,变成QDoubleSpinBox 控件
在这里插入图片描述

修改性别时,双击后,变成QComboBox控件

3. 增加修改的信号

要在 CustomDelegate 中实现值修改时发送信号,通知告知是哪个学生的哪个属性的值变成了多少,可以按照以下步骤进行修改:

定义信号:在 CustomDelegate 类中添加一个信号,用于在值修改时发送。
捕获编辑器值的变化:在 setModelData 方法中捕获编辑器的值变化,并发出信号。

修改代码:


class CustomDelegate : public QStyledItemDelegate
{Q_OBJECT
public:CustomDelegate(QObject *parent = nullptr) ;QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;signals:void valueChanged( QString &student,  QString &property, QVariant value) const;
};

CustomDelegate::CustomDelegate(QObject *parent) : QStyledItemDelegate(parent)
{}QWidget *CustomDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{if (index.column() == 1 && index.parent().isValid()) {QString property = index.sibling(index.row(), 0).data().toString();if (property == "语文" || property == "数学" || property == "英语") {QDoubleSpinBox *spinBox = new QDoubleSpinBox(parent);spinBox->setRange(0, 100);spinBox->setDecimals(1);return spinBox;} else if (property == "性别") {QComboBox *comboBox = new QComboBox(parent);comboBox->addItem("男");comboBox->addItem("女");return comboBox;}}return QStyledItemDelegate::createEditor(parent, option, index);
}void CustomDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{if (index.column() == 1 && index.parent().isValid()) {QString property = index.sibling(index.row(), 0).data().toString();QString student = index.parent().data().toString();if (QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(editor)){double value = spinBox->value();model->setData(index, value);emit valueChanged(student, property, QVariant::fromValue(value));}else if (QComboBox *comboBox = qobject_cast<QComboBox*>(editor)){QString value = comboBox->currentText();model->setData(index, value);emit valueChanged(student, property, QVariant::fromValue(value));}}else{QStyledItemDelegate::setModelData(editor, model, index);}
}

连接信号和槽

    // 连接信号槽QObject::connect(delegate, &CustomDelegate::valueChanged, [&](const QString &student, const QString &property, QVariant value) {if (property == "性别"){qDebug() << "学生:" << student << "属性:" << property << "值:" << value.toString();}else{qDebug() << "学生:" << student << "属性:" << property << "值:" << value.toDouble();}});

4. 上面例子改为QTreeWidget 实现

基本步骤也差不多,就是少了QStandardItemModel


#include <QApplication>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QHeaderView>
#include <QLineEdit>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QAbstractItemView>
#include <QEvent>
#include <QMouseEvent>
#include <QItemDelegate>
#include <QDebug>
#include <cmath> // 用于std::fabs函数
#include <iostream>class MyTreeWidgetDelegate : public QItemDelegate {Q_OBJECTpublic:MyTreeWidgetDelegate(QObject* parent = nullptr) : QItemDelegate(parent) {}QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override {if (index.column() == 1){QTreeWidgetItem* item = static_cast<QTreeWidgetItem*>(index.internalPointer());if (item && item->parent() && item->parent()->parent()) {const QString attr = item->text(0);if (attr == "语文" || attr == "数学" || attr == "英语") {QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);spinBox->setRange(0, 100);spinBox->setDecimals(1);spinBox->setSingleStep(0.1);return spinBox;}else if (attr == "性别") {QComboBox* comboBox = new QComboBox(parent);comboBox->addItems({ "男", "女" });return comboBox;}}}return QItemDelegate::createEditor(parent, option, index);}void setEditorData(QWidget* editor, const QModelIndex& index) const override {if (index.column() == 1) {QTreeWidgetItem* item = static_cast<QTreeWidgetItem*>(index.internalPointer());if (item && item->parent() && item->parent()->parent()) {const QString attr = item->text(0);if (attr == "语文" || attr == "数学" || attr == "英语") {QDoubleSpinBox* spinBox = qobject_cast<QDoubleSpinBox*>(editor);if (spinBox) {spinBox->setValue(item->text(1).toDouble());}}else if (attr == "性别") {QComboBox* comboBox = qobject_cast<QComboBox*>(editor);if (comboBox) {comboBox->setCurrentText(item->text(1));}}}}else {QItemDelegate::setEditorData(editor, index);}}void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override {if (index.column() == 1) {QString property = index.sibling(index.row(), 0).data().toString();QString student = index.parent().data().toString();if (QDoubleSpinBox* spinBox = qobject_cast<QDoubleSpinBox*>(editor)){double oldValue = index.sibling(index.row(), 1).data().toDouble();double value = spinBox->value();if (std::fabs(oldValue - value) > 1e-6){model->setData(index, value, Qt::EditRole);emit valueChanged(student, property, QVariant::fromValue(value));}}else if (QComboBox* comboBox = qobject_cast<QComboBox*>(editor)){QString oldValue = index.sibling(index.row(), 1).data().toString();QString value = comboBox->currentText();if (oldValue != value){model->setData(index, value, Qt::EditRole);emit valueChanged(student, property, QVariant::fromValue(value));}}}else {QItemDelegate::setModelData(editor, model, index);}}void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override {editor->setGeometry(option.rect);}
signals:void valueChanged(QString& student, QString& property, QVariant value) const;
};class CustomTreeWidget : public QTreeWidget {Q_OBJECTpublic:CustomTreeWidget(QWidget* parent = nullptr) : QTreeWidget(parent) {setColumnCount(2);setHeaderLabels({ "属性", "值" });// 设置属性列不可编辑header()->setSectionResizeMode(0, QHeaderView::Stretch);header()->setSectionResizeMode(1, QHeaderView::Stretch);// 创建班级节点QTreeWidgetItem* classItem = new QTreeWidgetItem(this);classItem->setText(0, "1班");classItem->setFlags(classItem->flags() & ~Qt::ItemIsEditable);// 创建学生节点QStringList students = { "张三", "李四", "王五" };for (const QString& student : students) {QTreeWidgetItem* studentItem = new QTreeWidgetItem(classItem);studentItem->setText(0, student);studentItem->setFlags(studentItem->flags() & ~Qt::ItemIsEditable);// 创建学生属性节点QStringList attributes = { "语文", "数学", "英语", "性别" };for (const QString& attr : attributes) {QTreeWidgetItem* attrItem = new QTreeWidgetItem(studentItem);attrItem->setText(0, attr);if (attr == "语文" || attr == "数学" || attr == "英语"){attrItem->setText(1, "100");}else{attrItem->setText(1, "男");}attrItem->setFlags(attrItem->flags() & ~Qt::ItemIsEditable);if (attr == "语文" || attr == "数学" || attr == "英语" || attr == "性别") {attrItem->setFlags(attrItem->flags() | Qt::ItemIsEditable);}else {attrItem->setFlags(attrItem->flags() & ~Qt::ItemIsEditable);}}}// 设置编辑策略m_delegate = new MyTreeWidgetDelegate(this);setItemDelegateForColumn(1, m_delegate);setEditTriggers(QAbstractItemView::DoubleClicked);// 连接信号槽QObject::connect(m_delegate, &MyTreeWidgetDelegate::valueChanged, [&](const QString& student, const QString& property, QVariant value){if (property == "性别"){qDebug() << "学生:" << student << "属性:" << property << "值:" << value.toString();}else{qDebug() << "学生:" << student << "属性:" << property << "值:" << value.toDouble();}});}protected:void mousePressEvent(QMouseEvent* event) override {QTreeWidgetItem* item = itemAt(event->pos());if (item && item->columnCount() > 1){int column = columnAt(event->x());if (column == 1 && item->parent() && item->parent()->parent()){editItem(item, column);return;}}QTreeWidget::mousePressEvent(event);}
private:MyTreeWidgetDelegate* m_delegate;
};int main(int argc, char* argv[]) {QApplication a(argc, argv);CustomTreeWidget w;w.setGeometry(QRect(40, 30, 241, 501));w.expandAll();w.show();return a.exec();
}

在这里插入图片描述

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

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

相关文章

UE5 C++ Subsystem 和 多线程

一.Subsystem先做一个简单的介绍&#xff0c;其实可以去看大钊的文章有一篇专门讲这个的。 GamePlay框架基础上的一个增强功能&#xff0c;属于GamePlay架构的范围。Subsystems是一套可以定义自动实例化和释放的类的框架。这个框架允许你从5类里选择一个来定义子类(只能在C定义…

Linux 添加spi-nor flash支持

1. spi-nor flash简介 在嵌入式ARM开发过程中通常会使用到spi-nor flash&#xff0c;主要用于固化u-boot镜像以支持spi方式启动系统。目前常用的spi-nor flash有gd25wq128e、w25q128等flash芯片&#xff0c;下述以gd25wq128e为例进行讲解。 2.调试通常遇到的问题 无法识别到…

C# 探险之旅:第三十七节 - 类型class之Object:万物之源的奇妙冒险

嘿&#xff0c;勇敢的探险家们&#xff01;欢迎再次踏上C#的神秘之旅。今天&#xff0c;我们将深入探索一个极其强大又无处不在的“大佬”——Object 类型。想象一下&#xff0c;它就像是C#世界里的“超级英雄祖先”&#xff0c;几乎所有的类型都得叫它一声“老祖宗”。 Objec…

LabVIEW实验站反馈控制系统

开发了一套基于LabVIEW的软X射线磁性圆二色实验站的反馈控制系统。这套系统主要用于实现对实验站高电压的精确控制&#xff0c;从而保持照射在样品上的流强稳定性&#xff0c;为分析样品吸收谱提供可靠基准&#xff0c;同时提供了易用的用户界面和强大的数据存储功能。 项目背景…

aws(学习笔记第十八课) 使用aws cdk(python)进行部署

aws(学习笔记第十八课) 使用aws cdk(python)进行部署 学习内容&#xff1a; 使用aws cdk(python)进行部署整体代码&#xff08;python的通常工程&#xff09;代码动作 1. 使用aws cdk(python)进行部署 aws cdk的整体架构 前面使用了cloudformation进行了json的aws的各种组件的…

FreeBSD vs Linux:哪个开源操作系统更强大

FreeBSD 和 Linux&#xff0c;哪一个更强大&#xff1f;这个问题没那么简单。它们各有春秋&#xff0c;不能一概而论。 来自我们 A-Team Systems 的专家们有数十年这两个系统的使用经验&#xff0c;所以&#xff0c;我们将详细阐述这两个系统的优势和劣势&#xff0c;供你选择…

网络基础 - TCP/IP 五层模型

文章目录 一、OSI 参考模型中各个分层的作用1、应用层2、表示层3、会话层4、传输层5、网络层6、数据链路层7、物理层 二、OSI 参考模型通信处理示例 一、OSI 参考模型中各个分层的作用 1、应用层 2、表示层 负责设备固有数据格式和网络标准数据格式间的转换 实际生活中&#…

C++中的接口继承和实现继承以及多态性与性能的平衡处理

接口继承 接口继承是指子类只继承基类的纯虚函数&#xff0c;即只继承基类的接口&#xff0c;而不继承基类的实现。子类必须实现基类中的所有纯虚函数&#xff0c;否则子类也将成为抽象类。在 C 中&#xff0c;接口继承主要通过抽象类来实现。抽象类是包含至少一个纯虚函数的类…

大数据相关标准——GB/T 38676-2020信息技术 大数据 存储与处理系统功能测试要求(山东省大数据职称考试)

大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 大数据相关标准…

Mysql基础操作(1)

目录 简介 1. 数据库的创建与删除 1.1 创建数据库 1.2 删除数据库 2. 表的创建与删除 2.1 创建表 2.2 删除表 3. 数据插入 4. 数据查询 4.1 基本查询 4.2 条件查询 4.3 多条件查询 4.4 排序查询 4.5 分页查询 5. 数据更新 6. 数据删除 7. 总结 简介 MySQL 是一…

查看服务器或系统架构(amd64、arm64...)

要确定您的服务器或系统是基于i386、armhf、amd64还是arm64架构&#xff0c;可以通过一系列命令行工具来获取相关信息。以下是具体的方法和步骤&#xff1a; 1. 使用 uname 命令 uname -m 是最常用的方法之一&#xff0c;它可以快速地显示系统的硬件架构。根据输出的不同字符…

MySQL 调优技巧|索引什么时候失效?为什么?

写在前面 优化慢SQL&#xff0c;这是在工作或者面试中都不可避免的问题。这篇文章我们就来讲讲慢SQL的优化的一些方法&#xff01; 1. 升配 最简单的一步就是升配&#xff01;&#xff01;当然在降本增效的当下&#xff0c;很难能将这种单子审批下来了&#xff01; 2. 索引…

有线通信与无线通信技术的深度剖析与比较

有线通信与无线通信技术的深度剖析与比较 摘要&#xff1a; 本文详细阐述了有线通信技术和无线通信技术的原理、特点、应用场景、技术标准以及发展趋势等方面的内容&#xff0c;并对二者进行了深入的比较分析。通过全面探讨&#xff0c;旨在使读者清晰地理解这两种通信技术的差…

ARM/Linux嵌入式面经(五五):未岚大陆

文章目录 0、项目中既有flash又有E2,为什么不只使用一个?问题回答:1、uart通信与i2c通讯的硬件区别;2、说说你理解的pid算法;问题回答3、串口转usb怎么实现的?问题回答:4、软件采集的adc数据有没有滤波;问题回答5、是否使用过boot?你觉得使用boot的注意事项是什么?问…

《封装继承与多态》封装的优势

文章目录 封装在面向对象编程中的优势1. 提高代码的可读性和可维护性2. 提高代码的安全性3. 降低代码的复杂性案例举例 封装在敏捷开发和团队合作中的优势1. 促进敏捷开发2. 促进团队合作案例举例 封装在面向对象编程中的优势 封装是面向对象编程&#xff08;Object-Oriented …

高级Python游戏开发:创建一款多人对战坦克大战

在本教程中,我们将用Python的Pygame库开发一款高级的坦克大战游戏。这款游戏支持多人对战、碰撞检测、子弹射击以及地图障碍生成,适合作为学习Python高级游戏开发的练习项目。 一、游戏功能概述 多人对战模式:玩家可以操作坦克,在同一屏幕上互相攻击。子弹射击:坦克可以发…

【芯片设计- RTL 数字逻辑设计入门 番外篇 7.1 -- 基于ATE的IC测试原理】

文章目录 ATE 测试概述Opens/Shorts测试Leakage测试AC测试转自:漫谈大千世界 漫谈大千世界 2024年10月23日 23:17 湖北 ATE 测试概述 ATE(Automatic Test Equipment)是用于检测集成电路(IC)功能完整性的自动测试设备。它在半导体产业中扮演着至关重要的角色,主要用于检…

WPF+MVVM案例实战与特效(三十九)- 深度剖析一个弧形进度条的实现

文章目录 1、使用 Path 结合 ArcSegment 绘制圆弧1、属性解读2、静态圆弧3、动态圆弧4、运行效果5、圆弧两端点的形状2、总结1、使用 Path 结合 ArcSegment 绘制圆弧 1、属性解读 Path 是 WPF 中的一个标记元素,用于绘制复杂的几何路径形状,而 ArcSegment 用于描述 Path 中…

YOLOv5-Backbone模块实现

YOLOv5-Backbone模块实现 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 电脑系统&#xff1a;Windows11 显卡型号&#xff1a;NVIDIA Quadro P620 语言环境&#xff1a;python 3.9.7 编译器&#xff1a…

软件需求规格说明书文档,系统需求规格说明书下载,软件工程需求规格案例模板参考(word原件)

1 范围 1.1 系统概述 1.2 文档概述 1.3 术语及缩略语 2 引用文档 3 需求 3.1 要求的状态和方式 3.2 系统能力需求 3.3 系统外部接口需求 3.3.1 管理接口 3.3.2 业务接口 3.4 系统内部接口需求 3.5 系统内部数据需求 3.6 适应性需求 3.7 安全性需求 3.8 保密性需求 3.9 环境需求…