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 对象并将其添加到模型的相应位置。

cppCopy codeint 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)
    {
        // 获取对话框上修改后的StringList
        QStringList 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,接着再通过设置表头的方式更新表头,效果如下;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Transfer Learning(迁移学习)

1. 什么是迁移学习 迁移学习(Transfer Learning)是一种机器学习方法&#xff0c;就是把为任务 A 开发的模型作为初始点&#xff0c;重新使用在为任务 B 开发模型的过程中。迁移学习是通过从已学习的相关任务中转移知识来改进学习的新任务&#xff0c;虽然大多数机器学习算法都…

表单(HTML)

<!DOCTYPE html> <html><head><meta charset"utf-8"><title>个人信息</title></head><body><h1>个人信息</h1><form><fieldset><legend>基本信息</legend><label for"…

强光led电筒控制芯片方案:OC5338

强光LED电筒控制芯片OC5338是一款内置100V/3A功率MOS的高性能芯片方案。它具有多种功能&#xff0c;包括100%输出、25%输出和爆闪。此外&#xff0c;它还具有宽输入电压范围&#xff0c;从3.6V到100V&#xff0c;并且具有高达90%的高效率。 强光led电筒控制芯片方案:OC5338 L…

C#与VisionPro联合编程

C#与VisionPro联合 1. 参照康耐视提供的样例2. 参照样例写一个1. 创建工程2. 添加引用3. 声明变量4. 初始化5. 刷新队列6. 用户数据获取7. 跨线程访问Windows控件--委托8. 显示图像9. 释放资源 3. 代码4. 资源下载 1. 参照康耐视提供的样例 C:\Program Files\Cognex\VisionPro…

【Linux操作系统】命令补全

补全命令 快捷键&#xff1a;Tab 示例&#xff1a; 在终端中输入“ifc”&#xff0c;按Tab键&#xff0c;自动补全为“ifconfig”命令——查询IP地址。

k8s的二进制部署

k8s的二进制部署&#xff1a;源码包部署 k8smaster01: 20.0.0.101 kube-apiserver kube-controller-manager kube-scheduler etcd k8smaster02: 20.0.0.102 kube-apiserver kube-controller-manager kube-scheduler node节点01: 20.0.0.103 kubelet kube-proxy etcd node节点02…

最优化考试之牛顿法

最优化考试之牛顿法 一、牛顿法1.问题条件2.求解过程3.例子 PS 一、牛顿法 1.问题条件 目标函数 f ( x ) f(x) f(x)&#xff0c;求极小值初始点 x 0 x_0 x0​精度要求e&#xff08;没有提就是近似0&#xff09; 2.求解过程 求解一阶雅克比矩阵 ∇ f ( x ) ∇f(x) ∇f(x)和二…

Jmeter接口工具大全使用—响应断言

断言的作用&#xff1a;一个HTTP请求发出去&#xff0c;怎么判断执行的任务是否成功呢&#xff1f;通过检查服务器响应数据&#xff0c;是否返回预期想要的数据&#xff0c;如果是&#xff0c;判断任务成功&#xff0c;反之任务失败。 1.添加断言 选中一个取样器&#xff0c;…

少走弯路:单片机使用点阵字体通过像素化的正确获取

要在单片机内自由显示文字&#xff0c;必须准备相应的字库。之前也发文介绍过&#xff1a; 在esp32(esp8266) 提供软字库显示中文的解决方案_esp32中文字库-CSDN博客 包括已经开源的项目&#xff1a; https://github.com/StarCompute/tftziku 这种字体获取思路是&#xff1a…

HackTheBox - Medium - Linux - Agile

Agile Agile 是一个中等难度的 Linux 机器&#xff0c;在端口 80 上有一个密码管理网站。创建帐户并添加几个密码后&#xff0c;发现网站的导出到 CSV 功能容易受到任意文件读取的攻击。其他终结点的枚举显示“/download”在访问时引发错误&#xff0c;并显示“Werkzeug”调试…

Duboo-入门到学废【上篇】

目录 1&#x1f95e;.什么是duboo 2&#x1f32d;.架构图 3.&#x1f37f;快速入门 4.&#x1f9c7;浅浅理解 1.什么是duboo&#x1f936;&#x1f936;&#x1f936; Dubbo是一个由阿里巴巴开发的基于Java的开源RPC框架。它提供了高性能、透明化的远程方法调用&#xff0…

通讯录管理系统简单实现

1.功能介绍 今天我们要实现的通讯录管理系统主要有7项功能&#xff1a;添加联系人&#xff0c;显示联系人&#xff0c;删除联系人&#xff0c;查找联系人&#xff0c;修改联系人&#xff0c;清空联系人&#xff0c;退出通讯录 2.功能实现 2.1创建联系人结构体 通讯录结构体 一…

linux 中 ext2文件系统实现

ext2文件系统结构 图片的svg下载链接&#xff08;图中关于buffer的部分&#xff0c;上下两部分是重复的&#xff0c;是从不同维度下看的buffer结构&#xff09; linux内核本身不提供ext2文件系统的格式化功能&#xff0c;可以参考busybox中对mkfs.ext2的实现&#xff08;mkfs.…

【数据结构】顺序表与单链表的增删查改

文章目录 前言顺序表增删查改顺序表的定义与初始化增删查改操作测试代码完整代码 单链表的增删查改数据结构定义动态申请节点单链表的尾插和头插单链表的尾删和头删单链表的查找单链表的插入和删除销毁链表测试代码完整代码 总结 前言 在计算机编程领域&#xff0c;数据结构是…

安全运维是做什么的,主要工作内容是什么

安全运维&#xff0c;简称SecOps&#xff0c;是一种集成安全措施和流程到信息技术运维的实践。它的目的是确保在日常运维活动中&#xff0c;如网络管理、系统维护、软件更新等&#xff0c;均考虑并融入安全策略。安全运维的核心是实现安全和运维团队的密切协作&#xff0c;以快…

前端map标签(创建热点区域或是点击图片指定区域跳转对应链接))

前言 点击整张图片的某一部分,可以实现自定义跳转或者一些事件 利用img和map和area标签实现 先来看下实现 https://www.w3cschool.cn/tryrun/showhtml/tryhtml_areamap <img src"/statics/images/course/planets.gif" width"145" height"126&…

条件覆盖和条件组合覆盖测试设计-实验八例题

目录 条件覆盖 判定-条件覆盖 条件组合覆盖 实验内容&#xff1a; 以银行内部转账为实例&#xff0c;针对内部转账业务逻辑代码进行分析&#xff0c;运用条件覆盖和条件组合覆盖进行测试用例设计。 实验过程&#xff1a; 条件覆盖 条件覆盖&#xff08;Condition Cover…

java中XML格式转换

之前很少用xml格式&#xff0c;但是有些老系统还是需要使用xml格式进行对接&#xff0c;所以干脆总结一下&#xff0c;方便以后使用。 关于xml: 即可扩展标记语言&#xff0c;xml是互联网数据传输的重要工具&#xff0c;它可以跨越互联网任何的平台&#xff0c;不受编程语言和操…

Word中插入mathtype的行内公式显示不全,设置行距,最小值

Word中插入mathtype的行内公式显示不全 如下图&#xff1a;公式上下被遮住 解决方式&#xff1a; 设置所在段落的行距&#xff1a;最小值--xx磅。同时取消勾选 “如果定义了文档网格&#xff0c;则对齐到网格” 处理后效果&#xff1a;

Flash芯片W25Q系列驱动注意事项以及跨页读写操作

一、硬件 二、W25Q64简介与API函数 1) W25Q有很多系列&#xff0c;其区别就是存储容量不一样 以我现在使用的举例W25Q64 64指的是64Mbit&#xff0c;不是64M字节要区分清楚 64Mbit 8Mbyte,所以总的容量能存储8MByte 2) W25q64的存储分为块、扇区、页 一页&#xff1…