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.rhkb.cn/news/490495.html

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

相关文章

渗透测试---wireshark(1)基本介绍与安装

声明&#xff1a;学习素材来自b站up【泷羽Sec】&#xff0c;侵删&#xff0c;若阅读过程中有相关方面的不足&#xff0c;还请指正&#xff0c;本文只做相关技术分享,切莫从事违法等相关行为&#xff0c;本人与泷羽sec团队一律不承担一切后果 视频地址&#xff1a;泷羽---wiresh…

AI开发 - 用GPT写一个GPT应用的真实案例

就在昨天&#xff0c;我的同事推荐给我了一个第三方的公共大模型API&#xff0c;这个API集合了国际上上几乎所有知名的大模型&#xff0c;只需要很少的费用&#xff0c;就可以接入到这些大模型中并使用它们。成本之低&#xff0c;令人乍舌&#xff01;包括我们现在无法试用的 G…

搭建Tomcat(一)---SocketServerSocket

目录 引入1 引入2--socket 流程 Socket&#xff08;应用程序之间的通讯保障&#xff09; 网卡(计算机之间的通讯保障) 端口 端口号 实例 client端 解析 server端 解析 相关方法 问题1&#xff1a;ServerSocket和Socket有什么关系&#xff1f; ServerSocket Soc…

epoll反应堆模型

epoll反应堆模型 基于该视频所做笔记&#xff0c;视频里面讲的也挺难的&#xff0c;最好先让chat给你梳理一遍整体的代码再去看视频吧 15-epoll反应堆模型总述_bilibili_哔哩哔哩_bilibili 文章目录 epoll反应堆模型1.epoll反应堆模型概述2.具体讲解1.myevent_s结构体2.超时检…

探索自我成长的心理疗愈——读《蛤蟆先生去看心理医生》

《蛤蟆先生去看心理医生》以其强烈的代入感&#xff0c;让读者仿佛置身于故事之中&#xff0c;深刻体会到心理学的魅力。 读完此书后&#xff0c;我最大的收获是&#xff1a;“过去的种种磨难使你的人生体验更加丰富和深刻&#xff0c;因此新生活不会显得乏味。通过清晰地认识…

24秋:模式识别:填空解答题

​ 目录 一.空题目 二.解答题目 一.空题目 9&#xff1a;已知样本集合为&#xff1a;([3,4],1),([2,5],2),([8,10],3),([7,8],4),([6,9],5)&#xff0c;请计算样本数据部分的均值______ 10&#xff1a;当样本数较小时&#xff0c;为什么最小化经验风险会带来过拟合问题&…

Ubuntu上源码编译安装snort,使用snort进行数据检测和防御(简单示例)

前言 Snort是一个开源的网络入侵检测和防范系统&#xff08;IDS/IPS&#xff09;&#xff0c;Snort是一个基于libpcap的轻量级网络入侵检测系统&#xff0c;它运行在一个“传感器&#xff08;sensor&#xff09;”主机上&#xff0c;监听网络数据。通过将网络数据与规则集进行…

(补)算法刷题Day19:BM55 没有重复项数字的全排列

题目链接 给出一组数字&#xff0c;返回该组数字的所有排列 例如&#xff1a; [1,2,3]的所有排列如下 [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1]. &#xff08;以数字在数组中的位置靠前为优先级&#xff0c;按字典序排列输出。&#xff09; 思路&#xff1a; 使用回…

Repo管理

文章目录 前言Repo介绍清单仓库清单仓库的组成 初始化Repo同步远程仓库Repo实际应用 前言 我们知道&#xff0c;Git是用来管理某一个仓库&#xff0c;那当一个项目用到了多个仓库时&#xff0c;怎么来同步管理这些仓库呢&#xff1f;这个时候就可以引入Repo管理。 Repo介绍 …

QT 国际化(翻译)

QT国际化&#xff08;Internationalization&#xff0c;简称I18N&#xff09;是指将一个软件应用程序的界面、文本、日期、数字等元素转化为不同的语言和文化习惯的过程。这使得软件能够在不同的国家和地区使用&#xff0c;并且可以根据用户的语言和地区提供本地化的使用体验。…

【卷积神经网络】AlexNet实践

构建模型 模版搭建 # 定义一个AlexNet模型类def __init__(self):# 调用父类的构造函数&#xff08;如果继承自nn.Module的话&#xff09;super(AlexNet, self).__init__()# ReLU激活函数self.ReLU nn.ReLU()# 卷积层1&#xff1a;输入1个通道&#xff08;灰度图&#xff09;&a…

socket编程UDP-实现停等机制(接收确认、超时重传)

在下面博客中&#xff0c;我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程&#xff0c;并附上完整源码。 socket编程UDP-文件传输&模拟TCP建立连接脱离连接&#xff08;进阶篇&#xff09;_udp socket发送-CSDN博客 下面博客实现的是滑动窗口机制&#xff1a; sock…

Leetcode 面试150题 399.除法求值

系列博客目录 文章目录 系列博客目录题目思路代码 题目 链接 思路 广度优先搜索 我们可以将整个问题建模成一张图&#xff1a;给定图中的一些点&#xff08;点即变量&#xff09;&#xff0c;以及某些边的权值&#xff08;权值即两个变量的比值&#xff09;&#xff0c;试…

Python机器视觉的学习

一、二值化 1.1 二值化图 二值化图&#xff1a;就是将图像中的像素改成只有两种值&#xff0c;其操作的图像必须是灰度图。 1.2 阈值法 阈值法&#xff08;Thresholding&#xff09;是一种图像分割技术&#xff0c;旨在根据像素的灰度值或颜色值将图像分成不同的区域。该方法…

Linux 支持多个spi-nor flash

1. 需求 通常在嵌入式开发过程中可能会遇到需要再同一个SPI总线上挂载多个spi nor flash才能满足存储需求。 2. 技术简介 对于spi-nor flash驱动通常不需要驱动开发人员手搓&#xff0c;一般内核会有一套固定的驱动&#xff0c;而且走的是内核的MTD子系统那一套&#xff0c;市…

超标量处理器设计笔记(11)发射内容:分配、仲裁、唤醒

发射 概述集中式和分布式数据捕捉和非数据捕捉数据捕捉非数据捕捉总结对比 压缩式和非压缩式压缩式发射队列非压缩式发射队列总结 发射过程的流水线非数据捕捉结构的流水线数据捕捉结构的流水线 分配仲裁1-of-M 的仲裁电路N of M 的仲裁电路 唤醒单周期指令的唤醒多周期指令的…

ArrayList源码分析、扩容机制面试题,数组和List的相互转换,ArrayList与LinkedList的区别

目录 1.java集合框架体系 2. 前置知识-数组 2.1 数组 2.1.1 定义&#xff1a; 2.1.2 数组如何获取其他元素的地址值&#xff1f;&#xff08;寻址公式&#xff09; 2.1.3 为什么数组索引从0开始呢&#xff1f;从1开始不行吗&#xff1f; 3. ArrayList 3.1 ArrayList和和…

地下管线三维建模,市面上有哪些软件

1. 地下管线&#xff1a;城市“生命线” 地下管线是城市的重要基础设施&#xff0c;包括供水、排水、燃气、热力、电力、通信等管线&#xff0c;它们如同城市的“生命线”&#xff0c;支撑着城市的正常运转。如果缺乏完整和准确的地下管线信息&#xff0c;施工破坏地下管线的事…

蓝桥杯刷题——day5

蓝桥杯刷题——day5 题目一题干解题思路一代码解题思路二代码 题目二题干解题思路代码 题目一 题干 给定n个整数 a1,a2,⋯ ,an&#xff0c;求它们两两相乘再相加的和&#xff0c;即&#xff1a; 示例一&#xff1a; 输入&#xff1a; 4 1 3 6 9 输出&#xff1a; 117 题目链…

L1-3流量分析

1. 初步分析 数据包下载 流量分析基础篇 使用科来网络分析系统&#xff0c;打开L1-3.pcapng数据包&#xff0c;查看数据包中ssh的协议占的比例较大。 2. 通过分析数据包L1-3&#xff0c;找出黑客的IP地址&#xff0c;并将黑客的IP地址作为FLAG(形式:[IP地址)提交; 获取的fl…