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;为建设集团、施工企业、监理单位、设计单位、政府监管部门等提供一揽子工地现场管理信息化解决方案。 通过人员管理、车辆管…

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

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

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两个操作系统的宿主机&…

elasticsearch系列六:索引重建

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

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

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

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

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

鸿蒙(HarmonyOS 3.1) DevEco Studio 3.1开发环境汉化

鸿蒙&#xff08;HarmonyOS 3.1&#xff09; DevEco Studio 3.1开发环境汉化 一、安装环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、设置过程 打开IDE&#xff0c;在第一个菜单File 中找到Settings...菜单 在Setting...中找到Plugins…

Python面向对象高级与Python的异常、模块以及包管理

Python面向对象高级与Python的异常、模块以及包管理 一、Python中的继承 1、什么是继承 我们接下来来聊聊Python代码中的“继承”:类是用来描述现实世界中同一组事务的共有特性的抽象模型,但是类也有上下级和范围之分,比如:生物 => 动物 => 哺乳动物 => 灵长型…

彭涛:2023年终复盘,工作,团队,个人!

眨眼2023即将结束&#xff0c;2024即将开启&#xff0c;每年这个时候&#xff0c;都会简单总结下自己这一年&#xff0c;既是对今年的一个复盘和回顾&#xff0c;也是对新一年的向往和期待。 我的2023年&#xff0c;大概分为 「个人」&#xff0c;「家庭」&#xff0c;「团队」…

大创项目推荐 深度学习OCR中文识别 - opencv python

文章目录 0 前言1 课题背景2 实现效果3 文本区域检测网络-CTPN4 文本识别网络-CRNN5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习OCR中文识别系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;…

第三节-数据链路层与MAC地址

如果数据进行封装时&#xff0c;基于E2或者802.3标准&#xff0c;此时我们称之为是一个以太网数据帧。 不同的协议栈用于定义和管理不同网络的数据转发规则。 E2和802.3作用&#xff1a;定义帧头和帧尾的格式 数据&#xff1a;对于下层的每个层级而言&#xff0c;上层所反馈…

台阶仪在半导体行业中的广泛应用及其重要意义

台阶仪在半导体材料的表征和研究中是一种非常重要的工具。如在半导体材料的制备过程中&#xff0c;一些关键的工艺参数&#xff0c;如温度、压力、气氛等条件的变化&#xff0c;会导致半导体材料的能带结构发生变化&#xff0c;通过使用台阶仪&#xff0c;可以准确测量和分析材…

归并算法:分治而治的高效算法大揭秘(图文详解)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《数据结构&算法》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! &#x1f4cb; 前言 归并算法是我们算法中最常见的算法之一&#xff0c;其思想非常巧妙。本身归并是只能归并有序数组…

一文带你掌握Flutter dio网络请求库的封装

highlight: an-old-hope 封装网络库考虑的几个方面&#xff1a; 请求参数的封装&#xff1a; 将请求所需的参数进行封装&#xff0c;例如 URL、请求头、请求体等。可以定义一个统一的数据结构或模型类来表示请求参数&#xff0c;以便于传递和管理。 响应结果的封装&#xff…

蓝牙物联网智能安防系统设计方案

1概述 安防系统(安全防护)的作用是预防损失&#xff0c;是人们保障人身和财产安全最重要的工具之一。近年来&#xff0c;伴随经济的飞速发展和城市人口的急剧增加&#xff0c;盗窃、入室抢劫等事件的增多给人们的安定生活带来了很大的影响&#xff0c;同时&#xff0c;交通的快…