C++ Qt开发:TableView与TreeView组件联动

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍TableViewTreeView组件联动的常用方法及灵活运用。

本章我们继续实现表格的联动效果,当读者点击TableViewTreeView中的某一行时,我们让其实现自动跟随功能,且当用户修改行中特定数据时也让其动态的跟随改变,首先绘制一个主界面如图,分别放置两个组件框,底部保留两个按钮,按钮1用于该表表格的行列个数,按钮2则用于设置TableView表格表头参数,整个表格我们将其设置为可编辑状态。

在函数中我们需要定义一个QStandardItemModel模型,这个模型的作用在之前的文章中有具体介绍,它是一个灵活且功能强大的模型类,适用于需要自定义数据结构、支持编辑、表头等功能的场景。通常用于与视图组件(如 QTableViewQTreeView 等)一起使用。它提供了一个表格结构,可以包含行和列,每个单元格可以存储一个 QStandardItem 对象。

这里的QStandardItemModel只适用于将两个不同类型的组件进行关联,简单点来说就是将两个组件指向同一个数据容器内,这样当用户修改任意一个组件内的数据另一个组件也会同步发生变更,但要想实现联动则还需要使用QItemSelectionModel模型,它负责跟踪哪些项被选中,以及在模型中项的选择状态发生变化时发出信号。

以下是 QItemSelectionModel 的一些重要特性和方法:

  • 选择项: 负责管理模型中的项的选择状态,可以单独选择项、选定范围内的项或清除所有选择项。
  • 信号: 当选择状态发生变化时,QItemSelectionModel 会发出相应的信号,如 selectionChanged 信号。
  • 选择模式: 提供多种选择模式,包括单选、多选、扩展选择等,可通过设置 SelectionMode 进行配置。
  • 选择策略: 提供多种选择策略,用于定义选择行为,如 SelectItemsSelectRowsSelectColumns 等。
  • 与视图的集成: 通常与 QTableViewQTreeView 等视图组件结合使用,以实现对视图中项的选择操作。

该组件是实现模型-视图架构中选择的关键组件。通过它,可以轻松管理和操作模型中的项的选择状态,实现各种灵活的用户交互。下面是 QItemSelectionModel 类的一些主要方法:

方法描述
QItemSelectionModel(QAbstractItemModel *model, QObject *parent = nullptr)构造函数,创建一个与指定模型关联的 QItemSelectionModel 对象。
QModelIndexList selectedIndexes() const获取当前被选中的项的索引列表。
void clear()清除所有的选择项。
void setSelectionMode(QItemSelectionModel::SelectionFlags mode)设置选择模式,可以选择多个项、单个项等。
void setSelectionBehavior(QItemSelectionModel::SelectionBehavior behavior)设置选择策略,如选择单个项、选择整行、选择整列等。
void select(const QModelIndex &topLeft, const QModelIndex &bottomRight, QItemSelectionModel::SelectionFlags command)在指定范围内进行选择操作,使用 SelectionFlags 定义选择操作。
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)当选择状态发生变化时发出的信号,可以通过连接这个信号来处理选择状态变化的事件。
bool hasSelection() const判断是否有选中的项。

上述方法提供了管理选择项的一些基本操作,包括清除选择、获取选中项的索引、设置选择模式和策略,以及在指定范围内进行选择操作。

MainWindow构造函数中,我们以此执行如下关键部分,来实现对主界面的初始化工作;

创建模型和选择模型

首先创建一个包含4行5列的 QStandardItemModel 模型,并为其创建了一个 QItemSelectionModel 选择模型。

model = new QStandardItemModel(4, 5, this);
selection = new QItemSelectionModel(model);

关联到 tableViewtreeView

将模型和选择模型关联到 tableViewtreeView 上,这样它们会共享同一份数据模型,也就是无论两个组件哪一个发生变化均会影响双方组件中的内容。

ui->tableView->setModel(model);
ui->tableView->setSelectionModel(selection);ui->treeView->setModel(model);
ui->treeView->setSelectionModel(selection);

添加表头与初始化数据

创建一个包含列名的 HeaderList 字符串列表,并将其设置为模型的水平表头标签。继续创建一个包含三个字符串列表的数组 DataList,每个列表代表一行数据。然后使用嵌套的循环遍历数组,将数据逐个添加到模型中。

QStringList HeaderList;
HeaderList << "序号" << "姓名" << "年龄" << "性别" << "婚否";
model->setHorizontalHeaderLabels(HeaderList);QStringList DataList[3];
QStandardItem *Item;DataList[0] << "1001" << "admin" << "24" << "男" << "是";
DataList[1] << "1002" << "lyshark" << "23" << "男" << "否";
DataList[2] << "1003" << "lucy" << "37" << "女" << "是";

通过循环添加数据到模型

使用两个循环,外层循环遍历数组,内层循环遍历每个数组中的元素,创建 QStandardItem 对象并将其添加到模型的相应位置。

int Array_Length = DataList->length();               // 获取每个数组中元素数
int Array_Count = sizeof(DataList) / sizeof(DataList[0]);        // 获取数组个数for(int x=0; x<Array_Count; x++)
{for(int y=0; y<Array_Length; y++){Item = new QStandardItem(DataList[x][y]);model->setItem(x, y, Item);}
}

如上这段代码初始化了一个包含表头和数据的 QStandardItemModel 模型,然后将模型和选择模型关联到 tableViewtreeView 上,最后通过循环将数据逐个添加到模型中。这样就创建了一个主窗口,其中包含了一个表格视图和一个树形视图,它们共享相同的数据模型。如下图所示;

DialogSize.ui

接着来看on_pushButton_clicked按钮是如何实现的,该按钮主要用于实现改变表格行与列,当点击后则会弹出一个DialogSize自定义对话框,至于对话框是如何添加的在之前的文章中已经详细介绍过了。

在如下代码中我们通过model->rowCount()以及model->columnCount()获取到父UI界面中tableView表格的行列数,并通过ptr->setRowColumn将这些数据设置到了子对话框的编辑框上面,而ptr->columnCount()则用于接收子对话框的返回值,并将其动态设置到对应的模型中;

void MainWindow::on_pushButton_clicked()
{// //模态对话框,动态创建,用过后删除DialogSize *ptr = new DialogSize(this);     // 创建一个对话框Qt::WindowFlags flags = ptr->windowFlags(); // 需要获取返回值ptr->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint);  // 设置对话框固定大小ptr->setRowColumn(model->rowCount(),model->columnCount());      // 对话框数据初始化int ref = ptr->exec();             // 以模态方式显示对话框if (ref==QDialog::Accepted)        // OK键被按下,对话框关闭{// 当BtnOk被按下时,则设置对话框中的数据int cols=ptr->columnCount();model->setColumnCount(cols);int rows=ptr->rowCount();model->setRowCount(rows);}// 最后删除释放对话框句柄delete ptr;
}

接着来看下子对话框DialogSize做了什么,在对话框代码中rowCount()是给主窗体调用的函数其功能是获取到当前对话框中spinBoxRow组件中的数值,而columnCount()同理用于得到spinBoxColumn组件中的数值,最后的setRowColumn()则是用于接收主窗体的船只,并设置到对应的子对话框上的SpinBox组件内,其代码如下;

DialogSize::DialogSize(QWidget *parent) :QDialog(parent),ui(new Ui::DialogSize)
{ui->setupUi(this);
}DialogSize::~DialogSize()
{delete ui;
}// 主窗体调用获取当前行数
int DialogSize::rowCount()
{return  ui->spinBoxRow->value();
}// 主窗体调用获取当前列数
int DialogSize::columnCount()
{return  ui->spinBoxColumn->value();
}// 设置主窗体中的TableView行数与列数
void DialogSize::setRowColumn(int row, int column)
{ui->spinBoxRow->setValue(row);ui->spinBoxColumn->setValue(column);
}

运行程序,并点击左侧第一个按钮,此时我们可以将表格设置为6*6的矩阵,如下图所示;

DIalogHead.ui

对于第二个按钮on_pushButton_2_clicked的功能实现与第一个按钮完全一致,该按钮主要实现对父窗体中TableView的表头进行重新设置,在弹出对话框之前,需要将当前表头元素复制到strList列表容器内,并通过使用子对话框中的ptr->setHeaderList将其拷贝到子对话框中,并通过QDialog::Accepted等待对话框按下修改按钮,如下代码所示;

void MainWindow::on_pushButton_2_clicked()
{DialogHead *ptr = new DialogHead(this);Qt::WindowFlags flags = ptr->windowFlags();ptr->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint);// 如果表头列数变化,则从新初始化if(ptr->headerList().count() != model->columnCount()){QStringList strList;// 获取现有的表头标题for (int i=0;i<model->columnCount();i++){strList.append(model->headerData(i,Qt::Horizontal,Qt::DisplayRole).toString());}// 用于对话框初始化显示ptr->setHeaderList(strList);}// 调用弹窗int ref = ptr->exec();if(ref==QDialog::Accepted){// 获取对话框上修改后的StringListQStringList strList=ptr->headerList();// 设置模型的表头标题model->setHorizontalHeaderLabels(strList);}delete ptr;
}

当读者按下了修改按钮之后,由于通过ui->listView->setModel(model)已经与父窗体建立了关联,则此时通过model->setStringList(headers)就可以实现对父窗体中数据的修改,代码如下所示;

DialogHead::DialogHead(QWidget *parent) :QDialog(parent),ui(new Ui::DialogHead)
{ui->setupUi(this);model = new QStringListModel;ui->listView->setModel(model);
}DialogHead::~DialogHead()
{delete ui;
}// 设置当前listView中的数据
void DialogHead::setHeaderList(QStringList &headers)
{model->setStringList(headers);
}// 返回当前的表头
QStringList DialogHead::headerList()
{return model->stringList();
}

程序运行后,读者可以先将表格的行与列修改为7*7,接着再通过设置表头的方式更新表头,效果如下;

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

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

相关文章

== 和 equals() 的区别

大家好&#xff0c;我是"java继父"伯约&#xff0c;这篇对大家有帮助的话求一个赞&#xff0c;另外文章末尾放了我从月入7k到现在3W的学习资料&#xff0c;大家可以去领一下&#xff08;无偿&#xff09;。 对于基本类型和引用类型的作用效果是不同的&#xff1a; …

再谈动态SQL

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 文章目录 专栏精选摘要引言正文动态sql标签ifchoose...when...otherwisewhere、…

【AI】阿里云免费GPU服务资源领取方法

首先&#xff0c;直接点击链接&#xff1a;阿里云免费试用 也可以复制链接到浏览器进行跳转&#xff1a;https://free.aliyun.com?userCodernbj0c1o 页面如下所示&#xff1a;这里的免费试用期限是3个月&#xff0c;给的资源点够我们试用V100 16G显存服务器300个小时&#xff…

作业--day38

1.定义一个Person类&#xff0c;包含私有成员&#xff0c;int *age&#xff0c;string &name&#xff0c;一个Stu类&#xff0c;包含私有成员double *score&#xff0c;Person p1&#xff0c;写出Person类和Stu类的特殊成员函数&#xff0c;并写一个Stu的show函数&#xff…

智慧工地云平台源码 支持二次开发、支持源码交付

智慧工地利用移动互联、物联网、云计算、大数据等新一代信息技术&#xff0c;彻底改变传统施工现场各参建方的交互方式、工作方式和管理模式&#xff0c;为建设集团、施工企业、监理单位、设计单位、政府监管部门等提供一揽子工地现场管理信息化解决方案。 通过人员管理、车辆管…

自己写的Js有序的Map, 并且支持Key为对象

var map newMap(); map.put({name:"张三"}, 23); map.put("李四", 24); map.get({name:"张三"}); map.remove({name:"张三"}); map.put("张三", 23); var objArray map.allList("name", "age&…

linux find 与cp 配合使用

cp与find配合使用 一、用自带的-exec参数 find ab -iname "ef" -type f -exec cp {} tmp \;-type f 文件 d 目录 可执行文件 -type f -executable {} 是查找结果 后面空格\; 结束 有点不太好用 但后面还可以 加命令 分号隔开 $find ab -name "ef" -…

SQLServer性能分析

目录 1 常用系统存储过程2 查看执行计划3 查看磁盘使用率&#xff08;STATISTICS IO&#xff09;4 查询时间耗时较长的语句5 死锁处理参考资料 1 常用系统存储过程 1.1 查询表结构 EXEC sp_columns your_table, column_name table_column1.2 查询表索引 EXEC sp_helpindex …

平时的一些思考内容

文章目录 阶乘位运算求概率 阶乘 阶乘是一很迷人的&#xff0c;刚开始的的变化还不是很大&#xff0c;到后面变化类似于直线上升的&#xff0c;不知道现实中哪些实例来表示阶乘。19的阶乘就已经超过了long了&#xff0c;在竞赛或者其他中要求2023或者很大数字的阶乘就需要考虑…

还在用Jekins?快来试试这款比Jekins简而轻的自动部署软件!

大家好&#xff0c;我是 Java陈序员。 在工作中&#xff0c;你是否遇到过团队中没有专业的运维&#xff0c;开发还要做运维的活&#xff0c;需要自己手动构建、部署项目&#xff1f; 不同的项目还有不同的部署命令&#xff0c;需要使用 SSH 工具连接远程服务器和使用 FTP 文件…

开源大语言模型简记

文章目录 开源大模型LlamaChinese-LLaMA-AlpacaLlama2-ChineseLinlyYaYiChatGLMtransformersGPT-3(未完全开源)BERTT5QwenBELLEMossBaichuan其他

web前端之JavaScript

MENU JavaScript之设计模式、单例、代理、装饰者、中介者、观察者、发布订阅、策略JavaScript之数组静态方法的实现、reduce、forEach、map、push、every JavaScript之设计模式、单例、代理、装饰者、中介者、观察者、发布订阅、策略 单例模式 概念 保证一个类仅有一个实例&am…

C基础使用

return 0; 语句用于表示退出程序。 一个程序有且只能有一个main函数的存在 安装编译环境&#xff1a; 安装vim: ubuntu里vim编辑器使用方法_ubuntu vim-CSDN博客 编译与运行&#xff1a; gcc hello.c //编译源文件 ./a.out //运行…

SpringBoot 项目中常用的注解

每一层对应每个包&#xff0c;包名中应全为小写。 一、Common 层&#xff08;实体类&#xff09; 前提&#xff1a;导入 Lombok 依赖 Data&#xff1a;生成 get 和 set 方法以及 toString 方法 Getter&#xff1a;只生成 get 方法&#xff0c;避免对类中的成员变量修改。 …

vmware虚拟机中Nat、桥接模式和仅主机的差别

NAT 在NAT模式下&#xff0c;主机3是Kali和Win两个操作系统的宿主机&#xff0c;那么Kali和Win可以连接到外网&#xff0c;也可以和主机3进行互联&#xff0c;但是主机1和主机2不能连接到Kali和Win。 桥接 在桥接模式下&#xff0c;主机3是Kali和Win两个操作系统的宿主机&…

对于智能设备的一些设想1

最近发现脑子里经常会出现一些能够偷懒的想法&#xff0c;希望这些点子能一点点保存下来&#xff0c;希望有需要的人拿走点子&#xff0c;不用谢 1.泡脚桶 2023年12月28日 近两年泡脚桶的风着实很大&#xff0c;我差点也就入坑了&#xff0c;于是有了一种设想&#xff0c;为什么…

elasticsearch系列六:索引重建

概述 我们再起初创建索引的时候由于数据量、业务增长量都并不大&#xff0c;常常不需要搞那么多分片或者说某些字段的类型随着业务的变化&#xff0c;已经不太满足未来需求了&#xff0c;再或者由于集群上面索引分布不均匀导致节点直接容量差异较大等等这些情况&#xff0c;此时…

ssm基于Java的小区物业管理系统论文

基于Java的小区物业管理系统 摘 要 进入21世纪网络和计算机得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的角角落落。这就促使管理系统的发展。网上办公可以实现远程处理事务&#…

关于知识产权的分类标准以及分为哪些类型。

知识产权的分类标准主要有两种&#xff1a; 1.广义与狭义的分类&#xff1a; 广义的知识产权包括著作权、邻接权、商标权、商业秘密权、产地标记权、专利权、集成电路布图设计权等各种权利。目前已被《成立世界知识产权组织公约》和《与贸易有关的知识产权协议》&#xff08;…

【MySQL】数据库并发控制:悲观锁与乐观锁的深入解析

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 数 据 库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 悲观锁&#xff08;Pessimistic Locking&#xff09;: 乐观锁&#xff08;Optimistic Locking&#xff09;: 总结&#x…