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 ¤t, 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 中选择一个字段,作为排序的依据。以升序排序为例,输出效果如下图所示;

C++ Qt开发:SqlTableModel映射组件应用的更多相关文章
- C/C++ Qt StringListModel 字符串列表映射组件
StringListModel 字符串列表映射组件,该组件用于处理字符串与列表框组件中数据的转换,通常该组件会配合ListView组件一起使用,例如将ListView组件与Model模型绑定,当Lis ...
- win使用MSYS2安装Qt开发环境
原文链接 MSYS2 下载地址: pacman的具体用法 有pacman的具体使用方法.我们首先对系统升级 我们首先对系统升级 pacman -Syu 就会检测整个系统可以升级的组件,并自动下载安装, ...
- 基于QT开发的第三方库
基于Qt开发的第三方库 分类: Qt2014-02-12 11:34 1738人阅读 评论(0) 收藏 举报 QT第三方库 目录(?)[+] 文章来源:http://blog.csdn.net ...
- Qt 开发 MS VC 控件终极篇
Qt 开发 MS VC 控件终极篇 1. 使用 MSVC2015 通过项目向导创建 Qt ActiveQt Server 解决方案 项目配置:以下文件需要修改 1. 项目属性页->项目属性-&g ...
- 【应用笔记】【AN005】Qt开发环境下基于RS485的4-20mA电流采集
简介 4-20mA电流环具有广泛的应用前景,在许多行业中都发挥着重要作用.本文主要介绍在Qt开发环境下基于RS485实现4-20mA电流采集,实现WINDOWS平台对数据的采集.分析及显示. 系统组成 ...
- 利用Qt开发跨平台APP
本文将手把手教你如何在Windows环境下,使用Qt编译出安卓应用程序. Qt是一个优秀的跨平台开发工具.我们利用Qt可以很方便地将一次编写的应用,多次编译到不同平台上,如Windows.Linux. ...
- Qt开发环境下载和安装
Qt是跨平台的图形开发库,目前由Digia全资子公司 Qt Company 独立运营,官方网址: http://www.qt.io/ 也可以访问Qt项目域名:http://qt-project.org ...
- Qt开发北斗定位系统融合百度地图API及Qt程序打包发布
Qt开发北斗定位系统融合百度地图API及Qt程序打包发布 1.上位机介绍 最近有个接了一个小型项目,内容很简单,就是解析北斗GPS的串口数据然后输出经纬度,但接过来觉得太简单,就发挥了主观能动性,增加 ...
- CAD控件:QT开发使用控件入门
1. 环境搭建: 3 1.1. 安装Qt 3 1.2. 安装Microsoft Windows SDK的调试包 6 2. QT中使用MxDraw控件 7 1.3. 引入控件 7 3. 打开DWG文件 ...
- QT开发环境的建立以及QTE4.6.3、tslib1.4的移植过程
1.首先是建立Linux开发环境1.1.在windowsXP下安装博创公司提供的虚拟机软件VMware Workstation,版本为VMware-workstation-full-7.0.1-227 ...
随机推荐
- 用 Rust 的 declarative macro 做了个小东西
最近几天在弄 ddnspod 的时候,写了个宏: custom_meta_struct 解决什么问题 #[derive(Debug, Clone, serde::Serialize, serde::D ...
- HTML一键打包APK工具最新版1.9.1更新(附下载地址)
HMTL网址打包APK,可以把本地HTML项目, Egret游戏,网页游戏,或者网站打包为一个安卓应用APK文件,无需编写任何代码,也无需配置安卓开发环境,支持在最新的安卓设备上安装运行. HTML一 ...
- Spring Boot虚拟线程与Webflux在JWT验证和MySQL查询上的性能比较
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错.内容较长,我就不翻译了,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读. 测试场景 作者采用了一个尽 ...
- 「codeforces - 1481F」AB Tree
link. 理一下逻辑,主要讲一下我做题时的疑惑和其它题解没提到的细节. 首先容易看到,一个必然不劣的贪心策略是把尽量靠近根的层铺成同样的字符.也许会有疑惑,字符串是否本质不同的判定每个位置地位相等. ...
- Go指针探秘:深入理解内存与安全性
Go指针为程序员提供了对内存的深入管理能力,同时确保了代码的安全性.本文深入探讨了Go指针的基础概念.操作.深层理解及其特性与限制.通过深入了解其设计哲学和应用,我们可以更好地利用Go的强大功能. 关 ...
- 【createWrapper】根据条件类创建查询wrapper
前几天写一个有几十个字段的查询wrapper,写得我心烦意乱.然后就琢磨了一下能不能只传一个条件类对像就能创建对应的wrapper.去看了下mybatis-plus的文档没看到合适的api,有一个创建 ...
- 轻松掌握组件启动之MongoDB(上):高可用复制集架构环境搭建
MongoDB复制集 复制集架构 在生产环境中,强烈不建议使用单机版的MongoDB服务器.原因如下: 单机版的MongoDB无法保证系统的可靠性.一旦进程发生故障或是服务器宕机,业务将直接不可用.此 ...
- gson如何序列化子类
需求 目前有一个需求,不同对象有一些公共属性,分别也有一些不同的属性.对方传过来的json字符串中,把这些对象组成了一个数组返回过来的.这样该如何反序列化呢? 举例 定义Person类.Student ...
- 如何优雅重启 kubernetes 的 Pod
最近在升级服务网格 Istio,升级后有个必要的流程就是需要重启数据面的所有的 Pod,也就是业务的 Pod,这样才能将这些 Pod 的 sidecar 更新为新版本. 方案 1 因为我们不同环境的 ...
- Typora +Picgo 搭建个人笔记
目录 Typora +Picgo 搭建个人笔记 一.Picgo +Github 搭建图床 1.基础设置 2. 将配置导出,方便下次使用 二.Typora:设置 : 1. 基本设置 2. 导出自动提交 ...