C++ Qt开发:SqlTableModel映射组件应用

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

在多数情况下我们需要使用SQL的方法来维护数据库,但此方式相对较为繁琐对于表格等数据的编辑非常不友好,在Qt中提供了QSqlTableModel模型类,它为开发者提供了一种直观的方式来与数据库表格进行交互。通过使用该组件可以将数据库与特定的组件进行关联,一旦关联被建立那么用户的所有操作均可以使用函数的方式而无需使用SQL语句,该特性有点类似于ORM对象关系映射机制。

在接下来的章节中,我们将学习如何配置 QSqlTableModel、与数据库进行交互、实现数据的动态显示和编辑,首先读者应绘制好UI界面,本次案例界面稍显复杂,读者可自行完成如下案例的绘制;

以下是 QSqlTableModel 类的一些常用方法,包括方法名、参数以及简要说明。这里列举的方法并非全部,而是一些常见的方法,更详细的信息可以参考官方文档。

方法描述
QSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())构造函数,创建 QSqlTableModel 对象。
setTable(const QString &tableName)设置要操作的数据库表名。
select()执行查询操作,从数据库中获取数据。
rowCount(const QModelIndex &parent = QModelIndex()) const返回模型中的行数。
columnCount(const QModelIndex &parent = QModelIndex()) const返回模型中的列数。
record(int row)返回指定行的记录。
setFilter(const QString &filter)设置用于过滤数据的条件。
setSort(int column, Qt::SortOrder order)设置排序的列和排序规则。
setEditStrategy(QSqlTableModel::EditStrategy strategy)设置编辑策略,决定何时将修改提交到数据库。
setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)设置模型中指定索引的数据。
data(const QModelIndex &index, int role = Qt::DisplayRole) const返回模型中指定索引的数据。
addRecord(const QSqlRecord &values)添加一条记录到模型中。
removeRow(int row)从模型中删除指定行。
insertRecord(int row, const QSqlRecord &record)在指定位置插入一条记录。
submitAll()提交所有对模型的修改到数据库。
revertAll()撤销对模型的所有修改。
setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole)设置表头数据。
indexInQuery(const QSqlQuery &query) const返回查询中模型的索引。

这些方法提供了对 QSqlTableModel 进行数据操作、过滤、排序以及提交修改的基本手段。通过这些方法,可以在应用程序中方便地操作数据库表格的数据。

1.1 初始化组件

首先我们来看一下MainWindow初始化部分是如何工作的,主要实现了以下功能:

打开数据库

首先使用SQLite数据库驱动连接名为"database.db"的数据库文件。如果数据库连接失败,函数直接返回。接着通过新建一个QSqlTableModel类,并调用setTable来打开一个数据表,设置编辑策略为 OnManualSubmit,即手动提交修改。并通过setSort函数来设置排序方式为根据ID字段升序Qt::AscendingOrder排列。

DB = QSqlDatabase::addDatabase("QSQLITE");
DB.setDatabaseName("./database.db");
if (!DB.open())
{return;
}tabModel = new QSqlTableModel(this, DB);
tabModel->setTable("Student");
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
tabModel->setSort(tabModel->fieldIndex("id"), Qt::AscendingOrder);
if (!(tabModel->select()))
{return;
}

设置字段名称

此处我们数据库中有6个字段,也就需要设置数据库字段与表格关联,如下则是对字段的动态关联。

tabModel->setHeaderData(tabModel->fieldIndex("id"),Qt::Horizontal,"Uid");
tabModel->setHeaderData(tabModel->fieldIndex("name"),Qt::Horizontal,"Uname");
tabModel->setHeaderData(tabModel->fieldIndex("sex"),Qt::Horizontal,"Usex");
tabModel->setHeaderData(tabModel->fieldIndex("age"),Qt::Horizontal,"Uage");
tabModel->setHeaderData(tabModel->fieldIndex("mobile"),Qt::Horizontal,"Umobile");
tabModel->setHeaderData(tabModel->fieldIndex("city"),Qt::Horizontal,"Ucity");

关联选择模型和数据模型

通过创建 QItemSelectionModel 对象 theSelection 并关联到 tabModel模型,将数据模型和选择模型关联到 ui->tableView,并设置选择模式为行选择模式。

theSelection = new QItemSelectionModel(tabModel);
ui->tableView->setModel(tabModel);
ui->tableView->setSelectionModel(theSelection);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);

创建数据映射

创建 QDataWidgetMapper 对象 dataMapper,将数据模型设置为 tabModel,设置提交策略为 AutoSubmit,即自动提交修改。并将 “name” 字段映射到 ui->lineEdit_name,默认选中第一条映射记录。

dataMapper = new QDataWidgetMapper();
dataMapper->setModel(tabModel);
dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
dataMapper->addMapping(ui->lineEdit_name, tabModel->fieldIndex("name"));
dataMapper->toFirst();

信号和槽连接

当选择模型中的当前行改变时,连接到槽函数 on_currentRowChanged,用于在右侧编辑框中输出当前选择的记录。

connect(theSelection, SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), this, SLOT(on_currentRowChanged(QModelIndex, QModelIndex)));

这个槽函数的实现如下所示,当行被点击后执行获取name/mobile字段,并放入映射数据集中的lineEdit编辑框中,使其能够动态的显示数据列表。

void MainWindow::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{Q_UNUSED(previous);dataMapper->setCurrentIndex(current.row());      // 更细数据映射的行号int curRecNo=current.row();                      // 获取行号QSqlRecord  curRec=tabModel->record(curRecNo);   // 获取当前记录QString uname = curRec.value("name").toString();     // 取出数据QString mobile = curRec.value("mobile").toString();ui->lineEdit_name->setText(uname);                   // 设置到编辑框ui->lineEdit_mobile->setText(mobile);
}

最后在UI文件的底部有一个comboBox组件,我们通过动态的查询记录,并将其赋值为第一个字段元素,其代码如下所示;

QSqlRecord emptyRec=tabModel->record();           //获取空记录,只有字段名
for (int i=0;i<emptyRec.count();i++)
{ui->comboBox->addItem(emptyRec.fieldName(i));
}

这段代码实现了一个简单的数据库浏览和编辑界面,用户可以通过表格展示的方式查看和编辑 “Student” 表格中的数据。当程序运行后则可以看到如下图所示的初始化部分;

1.2 数据处理

1.2.1 新增一条记录

当用户按下on_pushButton_add_clicked按钮时,则会在表格中新增一条记录,并设置默认值的功能。下面是代码的详细解释:

插入新行

在表格模型 tabModel 的末尾插入一行新记录。QModelIndex() 是一个空的索引,表示插入到末尾。

tabModel->insertRow(tabModel->rowCount(), QModelIndex());

获取最后一行的索引

获取刚刚插入的行的索引,这里假设 “name” 字段对应的列索引是 1。

QModelIndex curIndex = tabModel->index(tabModel->rowCount() - 1, 1);

清空选择项并设置新行为当前选择行

清空当前选择项,然后将刚刚插入的行设为当前选择行,并选择该行。

theSelection->clearSelection();
theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);

获取当前行号

获取当前行的行号。

int currow = curIndex.row();

设置自动生成的编号和默认值

这段代码的作用是在表格模型中插入一行新记录,然后设置该行的默认值,其中 “Uid” 字段会自动生成一个编号,“Usex” 字段默认为 “M”,“Uage” 字段默认为 “0”。

  • 自动生成编号,假设 “Uid” 字段对应的列索引是 0。
  • 将 “Usex” 字段设置为 “M”。
  • 将 “Uage” 字段设置为 “0”。
tabModel->setData(tabModel->index(currow, 0), 1000 + tabModel->rowCount());
tabModel->setData(tabModel->index(currow, 2), "M");
tabModel->setData(tabModel->index(currow, 3), "0");

运行代码,读者可自行点击增加记录按钮,每次点击均会在表格中提供新行,当读者点击on_pushButton_save_clicked保存按钮是则会调用submitAll()该函数用于将数据提交到数据库中存储,如下图所示;

1.2.4 插入一条记录

TableView 中当前选择行的上方插入一行新记录,并自动生成编号。下面是代码的详细解释:

获取当前选择行的索引和行号

获取当前选择的单元格的索引和行号。

QModelIndex curIndex = ui->tableView->currentIndex();
int currow = curIndex.row();

在当前行上方插入一行新记录

在表格模型 tabModel 的当前选择行(curIndex.row())的上方插入一行新记录。QModelIndex() 是一个空的索引,表示插入到指定行的上方。

tabModel->insertRow(curIndex.row(), QModelIndex());

设置自动生成的编号

自动生成编号,假设 “Uid” 字段对应的列索引是 0。

tabModel->setData(tabModel->index(currow, 0), 1000 + tabModel->rowCount());

清除已有选择并将当前选择行设为新插入的行

清空已有选择项,然后将当前选择行设为新插入的行,并选择该行。

theSelection->clearSelection();
theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);

当上述代码运行后则可以实现在指定行的上方插入一行新纪录,并为新插入的行生成一个自增的编号,其效果如下图所示;

对于删除一条记录来说则可以通过调用tabModel->removeRow(curIndex.row())来实现删除所选行,因为其实现起来很简单此处就不再演示,具体实现细节可以参考附件。

1.2.5 修改表中记录

如下所示代码,用于批量修改表格中所有记录的 “Uage” 字段值为某个固定的年龄。下面是代码的详细解释:

检查是否有记录

如果表格中没有记录,则直接返回,不执行后续的批量修改操作。

if (tabModel->rowCount() == 0)return;

循环遍历每一行记录并修改年龄

首先使用 tabModel->record(i) 获取表格模型中的第 i 行记录,接着使用 ui->lineEdit->text() 获取用户在 QLineEdit 中输入的文本,作为新的年龄值,并通过 aRec.setValue("age", ...) 设置 “age” 字段的新值,最后使用 tabModel->setRecord(i, aRec) 将修改后的记录设置回表格模型中的相应行。

for (int i = 0; i < tabModel->rowCount(); i++)
{QSqlRecord aRec = tabModel->record(i);                // 获取当前记录aRec.setValue("age", ui->lineEdit->text());           // 设置数据,使用 QLineEdit 中的文本作为新的年龄值tabModel->setRecord(i, aRec);                         // 将修改后的记录设置回表格模型中的相应行
}

提交修改

使用 tabModel->submitAll() 提交对表格模型的所有修改,将修改保存到数据库中。

tabModel->submitAll();

上述代码实现了一个简单的批量修改操作,将表格中所有记录的 “Uage” 字段值设置为用户在 QLineEdit 中输入的年龄值。请注意,这里没有对输入的年龄值进行验证,确保输入的是合法的数字。在实际应用中,可能需要添加一些输入验证和错误处理的逻辑。

1.2.6 表记录的排序

升序与降序排列

对表中记录的排序可以使用模型提供的setSort函数来实现,通过对该字段第二个参数设置为Qt::AscendingOrder则是升序排序,反之如果设置为Qt::DescendingOrder则为降序排序。

如下所示代码用于根据用户选择的字段对表格进行排序,并重新执行查询以更新表格数据。下面是代码的详细解释:

  • ui->comboBox->currentIndex() 获取用户在 QComboBox 中选择的字段的索引。
  • Qt::AscendingOrder 表示升序排序。
  • tabModel->select()执行对数据库的查询操作,重新获取数据并应用排序。
// 升序排序
tabModel->setSort(ui->comboBox->currentIndex(), Qt::AscendingOrder);
// 降序排序
tabModel->setSort(ui->comboBox->currentIndex(),Qt::DescendingOrder);
// 刷新查询
tabModel->select();

上述代码的作用是根据用户在下拉框中选择的字段进行升序或降序排序,并将排序后的结果重新加载到表格中。在使用这段代码之前,用户需要在 QComboBox 中选择一个字段,作为排序的依据。以升序排序为例,输出效果如下图所示;

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

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

相关文章

编程笔记 html5cssjs 004 我的第一个页面

编程笔记 html5&css&js 004 我的第一个页面 一、基本结构二、HTML标签三、HTML元素四、HTML属性五、编写第一个网页六、使用VSCODE小结 开始编写网页&#xff0c;并且使用第一个网页成为一个母板&#xff0c;用于完成后续内容的学习。有一个基本要求&#xff0c;显示结…

二叉树数据结构:深入了解二叉树的概念、特性与结构

在探索栈和队列之后&#xff08;大家可以移步至我的数据结构专栏&#xff09;&#xff1a;T-rLN的数据结构专栏 我们转向了更为复杂而有趣的数据结构——二叉树。本文将引领我们进入二叉树的世界&#xff0c;从最基本的概念和结构开始&#xff0c;逐步深入了解二叉树的顺序结构…

C语言停车场模型详解

C语言停车场模型详解 1. 引言2. 代码概述3. 代码详解3.1 定义常量和数据结构3.2 初始化车库3.3 查找车辆所在车库3.4 查找车辆所在的车位3.5 打印车库状态3.6 打印等候车辆3.7 车辆入库3.8 车辆出库3.9 菜单功能3.10 主函数 5.效果展示5.完整代码6. 总结 1. 引言 本文将介绍一…

hyper-v ubuntu 3节点 k8s集群搭建

前奏 搭建一主二从的k8s集群&#xff0c;如图所示&#xff0c;准备3台虚拟机。 不会创建的同学&#xff0c;可以看我上上篇博客&#xff1a;https://blog.csdn.net/dawnto/article/details/135086252 和上篇博客&#xff1a;https://blog.csdn.net/dawnto/article/details/135…

(04730)半导体器件之基本放大器工作原理(三)

本文主要阐述多级与差动放大器 为使输入的微弱信号进行放大后能获得足够的输出功率去推动负载运行&#xff0c;往往要采用所谓的多级放大电路&#xff0c;信号逐级通过放大&#xff0c;直至得到输出信号。这就必须考虑放大电路级与级之间的信号传递方法&#xff0c;或者称为耦…

微软官方系统镜像安装U盘制作

https://www.microsoft.com/zh-cn/software-download/windows11https://www.microsoft.com/zh-cn/software-download/windows10工具下载地址 #win10 https://download.microsoft.com/download/b/0/5/b053c6bc-fc07-4785-a66a-63c5aeb715a9/MediaCreationTool21H2.exehttps://d…

GC控制器(Garbagecollector)源码解析

KubeController Garbagecollector 本文从源码的角度分析KubeController Garbagecollector相关功能的实现。 本篇kubernetes版本为v1.27.3。 kubernetes项目地址: https://github.com/kubernetes/kubernetes controller命令main入口: cmd/kube-controller-manager/controller-…

k8s的网络类型

部署 CNI 网络组件 部署 flannel K8S 中 Pod 网络通信&#xff1a; ●Pod 内容器与容器之间的通信 在同一个 Pod 内的容器&#xff08;Pod 内的容器是不会跨宿主机的&#xff09;共享同一个网络命名空间&#xff0c; 相当于它们在同一台机器上一样&#xff0c;可以用 localho…

internet download manager 6.42怎么删除卸载,2024最新idm卸载不干净怎么解决

internet download manager 6.42简称为IDM&#xff0c;这是一款非常好用的下载软件&#xff0c;很多小伙伴都在使用。如果后续我们不再需要使用该软件&#xff0c;小伙伴们知道具体该如何将其卸载掉吗&#xff0c;其实卸载方法是非常简单的&#xff0c;只需要进行几个非常简单的…

Qt+Opencv:模板匹配

一、模板匹配应用场景闲聊 在很多机器视觉的应用场景都有用到模板匹配的功能&#xff0c;常常用来判断是否有目标检测对象&#xff0c;以及检测对象在图像中的位置。譬如在AOI检测软件中&#xff0c;通过拍摄Mark点的图像&#xff0c;进行mark模板的匹配&#xff0c;从而进行晶…

【Java EE初阶三 】线程的状态与安全(上)

1. join方法与多线程 1.1 初识多线程 为了提高cpu得利用率&#xff0c;因此就引入了多个线程的概念&#xff1b;即每个线程负责完成整个程序的一部分工作即可。 写一个代码&#xff0c;让主线程&#xff0c;创建一个新的线程&#xff0c;由新线程负责完成运算&#xff08;12。…

数模学习day01-层次分析法模型

已经一个多月没有更新过文章了&#xff0c;为了保住那绩点的意思微弱的优势&#xff0c;直接开摆&#xff0c;开始复习专业课和公共课考试了&#xff0c;结果虽然有遗憾但是还是算不错&#xff0c;至少没有掉到3.xx嘿嘿。 然后现在就要开始学习数学建模和算法同步了。接下来的文…

element ui Checkbox 多选框组件 lable不支持Object类型的值的问题

浅浅记录一下&#xff0c;遇到这个问题的心理路程吧&#xff0c;首先我遇到的问题是多选框的值回显不打对勾&#xff0c;&#xff08;例如&#xff1a;你新增的时候多选&#xff0c;然后点击编辑的时候选过的值没有被勾选&#xff0c;其实是被勾选上了&#xff0c;但是没有显示…

Ubuntu中fdisk磁盘分区并挂载、扩容逻辑卷

Ubuntu中fdisk磁盘分区并挂载、扩容逻辑卷 一&#xff1a;fdisk磁盘分区并挂载1.查看磁盘分区信息2.分区3.强制系统重新读取分区(避免重启系统)4.格式化分区5.创建挂载目录6.设置开机自动挂载&#xff1a;7.验证并自动挂载(执行了该命令不需要重启系统)8.查看挂载007.异常情况处…

Zulip:开源团队协作工具,高效沟通与远程办公 | 开源日报 No.126

zulip/zulip Stars: 18.9k License: Apache-2.0 Zulip 是一个开源的团队协作工具&#xff0c;拥有独特的基于主题的线程功能&#xff0c;结合了电子邮件和聊天的优点&#xff0c;使远程工作更加高效和愉快。它是唯一设计用于实时和异步对话的现代团队聊天应用程序。 其核心优势…

【线性代数】通过矩阵乘法得到的线性方程组和原来的线性方程组同解吗?

一、通过矩阵乘法得到的线性方程组和原来的线性方程组同解吗&#xff1f; 如果你进行的矩阵乘法涉及一个线性方程组 Ax b&#xff0c;并且你乘以一个可逆矩阵 M&#xff0c;且产生新的方程组 M(Ax) Mb&#xff0c;那么这两个系统是等价的&#xff1b;它们具有相同的解集。这…

RabbitMq知识概述

本文来说下RabbitMq相关的知识与概念 文章目录 概述AMQP协议Exchange 消息如何保证100&#xff05;投递什么是生产端的可靠性投递可靠性投递保障方案 消息幂等性高并发的情况下如何避免消息重复消费confirm 确认消息、Return返回消息如何实现confirm确认消息return消息机制 消费…

《数据库开发实践》之存储过程【知识点罗列+例题演练】

一、什么是存储过程&#xff1f; 1.概念理解&#xff1a; 存储过程是一组为了完成特定功能的SQL语句集。通过组成SQL语句和控制语句&#xff0c;提供一种封装任务的方法。因此在创建编译好某个存储过程后&#xff0c;因为存储过程中有可执行操作的sql语句&#xff0c;用户可以…

表单(HTML)

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

【机组期末速成】计算机的运算方法|进制转换|无符号数与有符号数|数的定点表示与浮点表示|定点运算

&#x1f3a5; 个人主页&#xff1a;深鱼~&#x1f525;收录专栏&#xff1a;计算机组成原理&#x1f304;欢迎 &#x1f44d;点赞✍评论⭐收藏 目录 前言&#xff1a; 一、本章考点总览 二、考点分析 1、日常我们采用十进制来表示数据&#xff0c;计算机如何表示&#xf…