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的各种组件的…

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

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

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

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

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

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

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 环境需求…

Linux - MySQL迁移至一主一从

Linux - MySQL迁移至一主一从 迁移准备安装MySQL ibd文件迁移原服务器操作目标服务器操作 一主一从增量同步异常解决结尾 首先部分单独安装MySQL&#xff0c;请参考Linux - MySQL安装&#xff0c;迁移数据量比较大约400G左右且网络不通故使用文件迁移&#xff0c;需开启一段时间…

29. Three.js案例-自定义平面图形

29. Three.js案例-自定义平面图形 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它利用 WebGL 技术在浏览器中渲染 3D 图形。 构造器 THREE.WebGLRenderer(parameters : object) 参数类型描述parametersobject可选参数对象&…

大模型运用-Prompt Engineering(提示工程)

什么是提示工程 提示工程 提示工程也叫指令工程&#xff0c;涉及到如何设计、优化和管理这些Prompt&#xff0c;以确保AI模型能够准确、高效地执行用户的指令&#xff0c;如&#xff1a;讲个笑话、java写个排序算法等 使用目的 1.获得具体问题的具体结果。&#xff08;如&…

MTK Android12 更换开机LOGO和开机动画

1、路径&#xff1a; &#xff08;1&#xff09;device/mediatek/system/common/device.mk &#xff08;2&#xff09;vendor/audio-logo/animation/bootanimation.zip &#xff08;3&#xff09;vendor/audio-logo/products/resource-copy.mk &#xff08;4&#xff09;vendo…

嵌入式驱动开发详解16(音频驱动开发)

文章目录 前言WM8960简介I2S协议接口说明 SAI音频接口简介驱动框架简介设备树配置内核使能声卡设置与测试 后续参考文献 前言 该专栏主要是讲解嵌入式相关的驱动开发&#xff0c;但是由于ALSA驱动框架过于复杂&#xff0c;实现音频编解码芯片的驱动不是一个人能完成的&#xf…

learn-(Uni-app)输入框u-search父子组件与input输入框(防抖与搜索触发)

1.父子组件u-search &#xff08;1&#xff09;父组件 <!-- 父组件 --> <template> <div><searchBar change"change" search"search"></searchBar> </div> </template> <script> // 子组件搜索 import…

计算机进制的介绍

一.进制介绍 对于整数&#xff0c;有四种表示方式: 1&#xff09;二进制:0,1&#xff0c;满2进1。 在golang中&#xff0c;不能直接使用二进制来表示一个整数&#xff0c;它沿用了c的特点。 参考:Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国 //赋值…

Transformers参数高效微调之LoRA

简介 LoRA: Low-Rank Adaptation of Large Language Models是微软研究人员为处理微调大语言模型的问题而引入的一项新技术。具有数十亿个参数的强大模型&#xff08;例如 GPT-3&#xff09;为了适应特定任务或领域而进行微调的成本非常高。LoRA 建议冻结预先训练的模型权重并注…

【原生js案例】如何让你的网页实现图片的按需加载

按需加载&#xff0c;这个词应该都不陌生了。我用到你的时候&#xff0c;你才出现就可以了。对于一个很多图片的网站&#xff0c;按需加载图片是优化网站性能的一个关键点。减少无效的http请求&#xff0c;提升网站加载速度。 感兴趣的可以关注下我的系列课程【webApp之h5端实…

博弈论1:拿走游戏(take-away game)

假设你和小红打赌&#xff0c;玩“拿走游戏”&#xff0c;输的人请对方吃饭.... 你们面前有21个筹码&#xff0c;放成一堆&#xff1b;每轮你或者小红可以从筹码堆中拿走1个/2个/3个&#xff1b;第一轮你先拿&#xff0c;第二轮小红拿&#xff0c;你们两个人交替进行;拿走筹码堆…