找回密码
 立即注册
收起左侧

第25篇 Qt5之数据库(五)SQL表格模型QSqlTableModel

3
回复
17518
查看
[复制链接]
累计签到:1609 天
连续签到:1 天
来源: 2017-7-31 23:49:16 显示全部楼层 |阅读模式
版权声明

该文章原创于Qt开源社区(www.qter.org),作者yafeilinux,转载请注明出处!



导语

在上一篇我们讲到只读的QSqlQueryModel模型其实也可以实现编辑功能的,但是实现起来很麻烦。而QSqlTableModel提供了一个一次只能操作单个SQL表的读写模型,它是QSqlQuery的更高层次的替代品,可以浏览和修改独立的SQL表,并且只需编写很少的代码,而且不需要了解SQL语法。



环境:Windows 7 + Qt 5.8.0(包含QtCreator 4.2.1



目录

一、创建数据库
二、修改操作
三、查询操作
四、排序操作
五、删除操作
六、插入操作



正文


一、创建数据库


1.新建Qt Widgets应用,项目名称为tablemodel,基类为QMainWindow,类名MainWindow

2.完成后打开tablemodel.pro文件,将第一行代码更改为:
  1. QT       += coregui sql
复制代码

       然后保存文件。


3.向项目中添加新的C++头文件,名称为connection.h。完成后将其内容更改如下:
  1. #ifndef CONNECTION_H
  2. #define CONNECTION_H

  3. #include <QSqlDatabase>
  4. #include <QSqlQuery>

  5. static bool createConnection()
  6. {
  7.     QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
  8.     db.setDatabaseName("database.db");
  9.     if(!db.open()) return false;
  10.     QSqlQuery query;
  11.     query.exec("create table student (id int primary key, name vchar)");
  12.     query.exec("insert into student values (0,'刘明')");
  13.     query.exec("insert into student values (1,'陈刚')");
  14.     query.exec("insert into student values (2,'王红')");
  15.     return true;
  16. }

  17. #endif // CONNECTION_H
复制代码


4.下面将main.cpp文件更改如下:

  1. #include "mainwindow.h"
  2. #include <QApplication>
  3. #include "connection.h"

  4. int main(int argc, char *argv[])
  5. {
  6.     QApplication a(argc, argv);

  7.     if(!createConnection())
  8.         return 1;

  9.     MainWindow w;
  10.     w.show();

  11.     return a.exec();
  12. }
复制代码


5.下面进入设计模式,向窗口上拖入LabelPush ButtonLine EditTable View等部件,进行界面设计,效果如下图所示。



6.完成后到mainwindow.h文件中,先包含头文件:
  1. #include <QSqlTableModel>
复制代码

然后添加私有对象:
  1. QSqlTableModel *model;
复制代码

7.mainwindow.cpp,在构造函数添加如下代码:
  1. model = new QSqlTableModel(this);
  2. model->setTable("student");
  3. model->setEditStrategy(QSqlTableModel::OnManualSubmit);
  4. model->select(); //选取整个表的所有行

  5. //不显示name属性列,如果这时添加记录,则该属性的值添加不上
  6. // model->removeColumn(1);

  7. ui->tableView->setModel(model);

  8. //使其不可编辑
  9. // ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
复制代码

这里创建一个QSqlTableModel后,只需使用setTable()来为其指定数据表,然后使用select()函数进行查询,调用这两个函数就等价于执行了“select * from student”这个SQL语句。这里还可以使用setFilter()来指定查询时的条件,在后面会看到这个函数的使用。在使用该模型以前,一般还要设置其编辑策略,它由QSqlTableModel::EditStrategy枚举类型定义,一共有三个值,如下图所示。用来说明当数据库中的值被编辑后,什么情况下提交修改。


运行程序,效果如下图所示。




       可以看到,这个模型已经完全脱离了SQL语句,我们只需要执行select()函数就能查询整张表。上面有两行代码被注释掉了,你可以取消注释,测试一下它们的作用。


二、修改操作


1.我们进入“提交修改”按钮的单击信号槽,更改如下:
  1. void MainWindow::on_pushButton_clicked()
  2. {
  3.     model->database().transaction(); //开始事务操作
  4.     if (model->submitAll()) {
  5.         model->database().commit(); //提交
  6.     } else {
  7.         model->database().rollback(); //回滚
  8.         QMessageBox::warning(this, tr("tableModel"),
  9.                              tr("数据库错误: %1")
  10.                              .arg(model->lastError().text()));
  11.     }
  12. }
复制代码


       这里用到了事务操作,真正起提交操作的是model->submitAll()一句,它提交所有更改。

2.进入“撤销修改”按钮的单击信号槽,更改如下:
  1. void MainWindow::on_pushButton_2_clicked()
  2. {
  3.     model->revertAll();
  4. }
复制代码

3.在mainwindow.cpp文件中包含头文件:
  1. #include <QMessageBox>
  2. #include <QSqlError>
复制代码


4.现在运行程序,我们将“陈刚”改为“李强”,如果我们点击“撤销修改”,那么它就会重新改为“陈刚”,而当我们点击“提交修改”后它就会保存到数据库,此时再点击“撤销修改”就修改不回来了。
       可以看到,这个模型可以将所有修改先保存到model中,只有当我们执行提交修改后,才会真正写入数据库。当然这也是因为我们在最开始设置了它的保存策略:
  1. model->setEditStrategy(QSqlTableModel::OnManualSubmit);
复制代码

这里的OnManualSubmit表明我们要提交修改才能使其生效。


三、查询操作


1.进入“查询”按钮的单击信号槽,更改如下:

  1. void MainWindow::on_pushButton_5_clicked()
  2. {
  3.     QString name = ui->lineEdit->text();
  4.     //根据姓名进行筛选
  5.     model->setFilter(QString("name = '%1'").arg(name));
  6.     //显示结果
  7.     model->select();
  8. }
复制代码


       使用setFilter()函数进行关键字筛选,这个函数是对整个结果集进行查询。


2.进入“显示全表”按钮的单击信号槽,更改如下:

  1. void MainWindow::on_pushButton_6_clicked()
  2. {
  3.     model->setTable("student");   //重新关联表
  4.     model->select();   //这样才能再次显示整个表的内容
  5. }
复制代码

为了再次显示整个表的内容,我们需要再次关联这个表。


3.下面运行程序,输入一个姓名,点击查询按钮后,就可以显示该记录了。再点击显示全表按钮则返回。如下图所示。




四、排序操作


分别进入id升序排序id降序排序按钮的单击信号槽,更改如下:

  1. // 升序
  2. void MainWindow::on_pushButton_7_clicked()
  3. {
  4.     //id属性即第0列,升序排列
  5.     model->setSort(0, Qt::AscendingOrder);
  6.     model->select();
  7. }
  8. // 降序
  9. void MainWindow::on_pushButton_8_clicked()
  10. {
  11.     model->setSort(0, Qt::DescendingOrder);
  12.     model->select();
  13. }
复制代码


这里使用了setSort()函数进行排序,它有两个参数,第一个参数表示按第几个字段排序,表头从左向右,最左边是第0个字段,这里就是id字段。第二个参数是排序方法,有升序和降序两种。运行程序,效果如下图所示。





五、删除操作


我们进入“删除选中行”按钮的单击信号槽,更改如下:

  1. void MainWindow::on_pushButton_4_clicked()
  2. {
  3.     //获取选中的行
  4.     int curRow = ui->tableView->currentIndex().row();

  5.     //删除该行
  6.     model->removeRow(curRow);

  7.     int ok = QMessageBox::warning(this,tr("删除当前行!"),
  8.                                   tr("你确定删除当前行吗?"),
  9.                                   QMessageBox::Yes,QMessageBox::No);
  10.     if(ok == QMessageBox::No)
  11.     {
  12.         model->revertAll(); //如果不删除,则撤销
  13.     }
  14.     else model->submitAll(); //否则提交,在数据库中删除该行
  15. }
复制代码

删除行的操作会先保存在model中,当我们执行了submitAll()函数后才会真正的在数据库中删除该行。这里我们使用了一个警告框来让用户选择是否真得要删除该行。运行程序,效果如下图所示。




我们单击第二行,然后单击“删除选中行”按钮,出现了警告框。这时你会发现,表中的第二行前面出现了一个小感叹号,表明该行已经被修改了,但是还没有真正在数据库中修改,这时的数据有个学名叫脏数据(Dirty Data)。当我们按钮“Yes”按钮后数据库中的数据就会被删除,如果按下“No”,那么更改就会取消。


六、插入操作


       我们进入“添加记录”按钮的单击信号槽,更改如下:

  1. void MainWindow::on_pushButton_3_clicked()
  2. {
  3.     int rowNum = model->rowCount(); //获得表的行数
  4.     int id = 10;
  5.     model->insertRow(rowNum); //添加一行
  6.     model->setData(model->index(rowNum,0),id);
  7.     //model->submitAll(); //可以直接提交
  8. }
复制代码

在表的最后添加一行,因为在student表中我们设置了id号是主键,所以这里必须使用setData()函数给新加的行添加id字段的值,不然添加行就不会成功。这里可以直接调用submitAll()函数进行提交,也可以利用“提交修改”按钮进行提交。运行程序,效果如下图所示。




按下“添加记录”按钮后,就添加了一行,不过在该行的前面有个星号,如果我们按下“提交修改”按钮,这个星号就会消失。当然,如果我们将上面代码里的提交函数的注释去掉,也就不会有这个星号了。


结语


可以看到这个模型很强大,而且完全脱离了SQL语句,就算你不怎么懂数据库知识,也可以利用它进行大部分常用的操作。我们也看到了,这个模型提供了缓冲区,可以先将修改保存起来,当我们执行提交函数时,再去真正地修改数据库。当然,这个模型比前面的模型更高级,前面讲的所有操作,在这里都能执行。

下载源码:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
参与人数 2人气 +3 收起 理由
171887239 + 1
空蝶飞 + 2 必须支持!

查看全部评分总评分 : 人气 +3

回复

使用道具 举报

累计签到:2 天
连续签到:1 天
2018-4-20 22:04:34 显示全部楼层
前面写到: 而QSqlTableModel提供了一个一次只能操作单个SQL表的读写模型,

如果需要复杂的操作,如一个数据库,操作后,需要同时操作多个表的话,这个是否合适呢,还是使用SQL语句更好呢?
谢谢。
回复 支持 反对

使用道具 举报

累计签到:1609 天
连续签到:1 天
2018-5-5 13:46:57 显示全部楼层
zyxk 发表于 2018-4-20 22:04
前面写到: 而QSqlTableModel提供了一个一次只能操作单个SQL表的读写模型,

如果需要复杂的操作,如一个数 ...

可以使用sql语句。
回复 支持 反对

使用道具 举报

累计签到:3 天
连续签到:3 天
2020-4-12 23:05:15 显示全部楼层
此文对我很有帮助 谢谢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了