目录
一、QT SQL简介
(一)、QT SQL对数据库支持
1、驱动层
2、SQL API层
3、用户接口层
(二)SQLite数据库初识
1、第一步:在项目管理文件(.pro)中增加数据库模块编辑
2、第二步:查看QT 对数据库的驱动的类型的支持
3、第三步:连接和打开数据库
4、第四步: 访问数据库
5、第五步:关闭数据库
(三)QtSqlite数据库接口介绍和使用
1、QSqlDataBase
2、QSqlQuery
3、数据库中的数据操作 (增查更删、显示UI上)
二、QT SQL案例:案例描述 数据在控件 QListWidget 展示和操作
(一)设计数据库
(二)涉及知识点
(三)QListWIdget 列表条目控件
1、界面建立
2、数据库操作代码
三、数据库模型高级接口 QSqlQueryModel使用和改进
(一)功能:Read-only data model for SQL result sets
知识点一:QSqlQueryModel模型基本使用
知识点二:QSqlQureyModel可编辑接口重写
知识点三:自定义接口函数
(二)QSqlQueryModel自定义高级接口应用:
一、QT SQL简介
应用程序操作数据库,需要数据库驱动,如:SQLITE,MySQL... ...
(一)、QT SQL对数据库支持
在QT中,QT 为SQL数据库提供支持的基本模块。Qt SQL的API分为不同层:
1、驱动层
驱动层 对于QT是基于C++来实现的框架,该层主要包括QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorbase、QSqlDriverPlugin and QSqlResult。这一层提供了特定数据库和SQL API层之间的底层桥梁。
2、SQL API层
SQL API层 对于SQL API 层提供了数据库的访问相关类,其中,QSqlDataBase类进行连接,QSqlQuery完成数据库的交互。除此之外,还有QSqlError、QSqlField、QSqlIndex and QSqlRecord类。
3、用户接口层
用户接口层 用户接口层的几个类实现将数据库中的数据链接到窗口部件上,这些类是使用模型/视图框架实现的,他们是更高层次的抽象,主要包括QSqlQureyModel,QSqlTableModel and QSqlRelationalTableModel。
(二)SQLite数据库初识
对于数据库操作流程主要分为:
- 第一步:在项目管理文件(.pro)中增加数据库模块
- 第二步:查看QT 对数据库的驱动的类型的支持
- 第三步:连接和打开数据库
- 第四步:访问数据库
- 第五步:关闭数据库
1、第一步:在项目管理文件(.pro)中增加数据库模块
2、第二步:查看QT 对数据库的驱动的类型的支持
显示支持的数据库驱动,MySql在QT中不直接支持,可通过以下几种方式:
- ODBC连接Qt连接MySQL数据库最详细的教程_qt mysql_joey小天使的博客-CSDN博客、
- MySQL Community ServerQt零基础系列10:windows 环境下如何添加MYSQL数据库驱动(补充内容) - 知乎 (zhihu.com)
- 下载驱动QMYSQL driver
3、第三步:连接和打开数据库
4、第四步: 访问数据库
5、第五步:关闭数据库
db.close();
(三)QtSqlite数据库接口介绍和使用
表1 模块包含的主要类的功能
Qt SQL采用的是MVC设计思想来处理数据,现对其主要类进行说明
1、QSqlDataBase
QSqlDataBase用于建立与数据库的连接,在建立连接时,加载数据库驱动的时候,可以设置数据库类型和数据库名字。除此之外,还可以通过接口设置数据数据库名字、主机名、用户名和密码,其主要接口说明见表2。
表2 QSqlDatabase操作主要接口
2、QSqlQuery
QSqlQuery执行各种SQL语句的类,在打开成功连接的数据库后,则可以通过QsqlQuery的接口来访问数据库中的内容,其主要接口说明如下表3。
表3 QSqlQuery操作主要接口
- 数据库图形工具使用——SQLite Expert Professional 5
3、数据库中的数据操作 (增查更删、显示UI上)
(1)插入和查询
- 插入操作语法:
- 查询操作语法:
- 如果想要查询所以的字段内容,可以采用:select * from 表名
(2)更新和删除
- 更新的操作语法
- 删除的操作语法
- 显示在UI上:利用查询功能
二、QT SQL案例:案例描述 数据在控件 QListWidget 展示和操作
(一)设计数据库
利用 qt 数据库,创建一个公司数据库(company. db),在该表中,创建一个员工表 (employee),员工主要包括:用户名和密码 都使用字符串类型。自己设计一个数据库用来存储公司员工的信息,并且可以通过界面来完成操作
数据库:company. db
员工表:staff
字段名有 id name age address salary
(二)涉及知识点
- 知识点一:UI界面设计一个QListWIdget
- 知识点二:sqlite数据生成
- 知识点三:sqlite数据UI联动
(三)QListWIdget 列表条目控件
1、界面建立
建立mainwindow.ui是主界面和itemfrom.ui 是条目界面
图1 项目文件 图2 条目界面新建过程(项目右键-->Add New)
图3 mainwindow.ui 主界面及其相关命名
图4 itemfrom.ui 条目界面及label命名
2、数据库操作代码
(添加、更新、删除、查询按钮需要跳转到槽)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"itemfrom.h"
#include<QListWidgetItem>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//1、根据数据库类型 连接数据库
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("company.db");
//2、打开数据库
if(!db.open())
{
qDebug()<<"open error"<<db.lastError();
}
//3、根据需求 创建数据库中所需要的表
QSqlQuery query;
//员工表:staff
//字段名有 id name age address salary
#if 0
QString sqlCreateTable = QString("create table staff(id integer primary key autoincrement,"
"name varchar(20),"
"age int,"
"address varchar(50),"
"salary int);");
if(!query.exec(sqlCreateTable))
{
qDebug()<<"create table error"<<db.lastError();
}
//插入
QString sqlInsert = QString("insert into staff(name,age,address,salary) "
"values('张三',20,'广州天河区','12000');");
if(!query.exec(sqlInsert))
{
qDebug()<<"insert table error"<<db.lastError();
}
#endif
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnAdd_clicked()
{
//[1] 获取UI控件上的内容
QString name = ui->lineEdit_name->text();
QString age = ui-> lineEdit_age->text();
QString address = ui->lineEdit_address->text();
QString salary = ui->lineEdit_salary->text();
//[2] 通过数据库接口的访问,将数据插入到数据库中
QSqlQuery query;
QString sqlInsert = QString("insert into staff(name,age,address,salary) "
"values('%1',%2,'%3',%4);").arg(name)
.arg(age.toInt())
.arg(address)
.arg(salary.toInt());//查询数据库数据
if(!query.exec(sqlInsert))
{
qDebug()<<"insert table error"<<db.lastError();
}
}
void MainWindow::on_btnUpdate_clicked()
{
ui->listWidget->clear();
QSqlQuery query;
QString id = ui->lineEdit_ID->text();
QString name = ui->lineEdit_name->text();
QString age = ui-> lineEdit_age->text();
QString address = ui->lineEdit_address->text();
QString salary = ui->lineEdit_salary->text();
QString sqlUpdate_name = QString("update staff set name = '%1' where id = %2;").arg(name).arg(id.toInt());//查询数据库数据
if(!query.exec(sqlUpdate_name))
{
qDebug()<<"update_name table error"<<db.lastError();
}
// QString sqlUpdate_age = QString("update staff set age = '%1' where id = %2;").arg(age.toInt()).arg(id.toInt());//查询数据库数据
// if(!query.exec(sqlUpdate_age))
// {
// qDebug()<<"update_age table error"<<db.lastError();
// }
// QString sqlUpdate_address = QString("update staff set address = '%1' where id = %2;").arg(address).arg(id.toInt());//查询数据库数据
// if(!query.exec(sqlUpdate_address))
// {
// qDebug()<<"update_address table error"<<db.lastError();
// }
// QString sqlUpdate_salary = QString("update staff set salary = '%1' where id = %2;").arg(salary.toInt()).arg(id.toInt());//查询数据库数据
// if(!query.exec(sqlUpdate_salary))
// {
// qDebug()<<"update_salary table error"<<db.lastError();
// }
}
void MainWindow::on_btnDelete_clicked()
{
//[1]删除数据库中的记录
QSqlQuery query;
int id = ui->lineEdit_ID->text().toInt();
QString sqlDelete = QString("delete from staff where id = %1;").arg(id);//查询数据库数据
if(!query.exec(sqlDelete))
{
qDebug()<<"delete table error"<<db.lastError();
}
//[2]同时删除UI控件上的内容,下标从0开始
ui->listWidget->takeItem(id-1);
}
void MainWindow::on_btnSearch_clicked()
{
ui->listWidget->clear();//在查询数据之前,将列表中的数据清空
QSqlQuery query;
//[1]向数据库 下达查询数据的命令
QString sqlSelect = QString("select * from staff;");//查询数据库数据
if(!query.exec(sqlSelect))
{
qDebug()<<"select table error"<<db.lastError();
}
//[2]遍历数据库记录
while(query.next())
{
int id = query.value("id").toInt();
QString name = query.value("name").toString();
int age = query.value("age").toInt();
QString address = query.value("address").toString();
int salary = query.value("salary").toInt();
qDebug()<<"id = "<<id<<" name = "<<name<<" age = "<<age<<" address = "<<address<<" salary = "<<salary;
//[3]每遍历一条记录,就要更新到UI控件上
//[3.1]创建一个列表条目
itemFrom* staffitem = new itemFrom;//new一个自定义的条目控件staffitem
staffitem->setStaffInfo(id,name,age,address,salary);
QListWidgetItem* item = new QListWidgetItem;//new一个listWidget的条目item
int w = staffitem->width();
int h = staffitem->height();
item->setSizeHint(QSize(w,h));//将item的宽高 与自定义的条目staffitem大小设置一致
ui->listWidget->addItem(item);//将item增加到listWidget上
ui->listWidget->setItemWidget(item,staffitem);//再给item设置 对应控件条目staffitem
}
}
三、数据库模型高级接口 QSqlQueryModel使用和改进
(一)功能:Read-only data model for SQL result sets
以只读模型方式来访问数据库,将得到询问结果集
解释:以只读访问查询数据库数据,并把数据存放在一个结果集,数据不能修改,如果想要修改,必须进行其他操作(重写虚函数)。
知识点一:QSqlQueryModel模型基本使用
//使用QSqlQueryModel
//[1]创建QSqlQueryModel对象,并设置相关的表头信息
QSqlQueryModel *model=new QSqlQueryModel;
//执行sql语句 //将查询的结果转换成 model对象
model->setQuery("select name,age,address,salary from staff");
//根据需求设置表头信息
model->setHeaderData(0,Qt::Horizontal,tr("Name"));
model->setHeaderData(1,Qt::Horizontal,tr("Age"));
model->setHeaderData(2,Qt::Horizontal,tr("Address"));
model->setHeaderData(3,Qt::Horizontal,tr("Salary"));
//[2]给ui控件设置一个模型
QTableView *view = new QTableView(ui->centralwidget);
view->setFixedSize(QSize(this->width(),this->height()));
view->setModel(model);//相当于将数据联动 UI控件上
//将view 显示出来
view->show();
知识点二:QSqlQureyModel可编辑接口重写
默认情况下是只读,要使得可读可写,必须创建子类并且重写setData()和flags()函数。另外一个选择是QSqlTableModel,它提供基于简单database表的可读可写模型。
1、接口一:
[virtual] bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
2、接口二: [override virtual] Qt::ItemFlags flags(const QModelIndex &index) const
editquerymodel.cpp
#include "editquerymodel.h"
#include<QSqlQuery>
editQueryModel::editQueryModel()
{
}
bool editQueryModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
//[1]判断列是否为有效的列 员工---Id 用户名 年龄 地址 薪资
if(index.column() < 1 ||index.column() > 4)
return false;
//获取列所对应的id
QModelIndex primaryIndex= QSqlQueryModel::index(index.row(),0);
int id = this->data(primaryIndex).toInt();//获取字段表中的id
//在修改行之前,将数据清除,将整个model清空
this->clear();
bool ok;
//根据需求修改对应的列
if(index.column() ==1)//用户名对应第一列
{
ok = setName(id,value.toString());
}
//刷新数据
refresh();
return ok;
}
Qt::ItemFlags editQueryModel::flags(const QModelIndex &index) const
{
//[1]获取当前单元格的编辑状态
Qt::ItemFlags flag = QSqlQueryModel::flags(index);
//[2]给现有的标志增加可编辑的标志
flag = flag | Qt::ItemIsEditable;//给它设置一个可编辑的状态
return flag;
}
void editQueryModel::refresh()
{
//执行查询 将数据库的数据查询出来,转换成一个model
this->setQuery("select * from staff");
this->setHeaderData(0,Qt::Horizontal,"Name");
}
bool editQueryModel::setName(int useId, const QString &name)
{
//执行name的更新
QSqlQuery query;
query.prepare("update staff set name = ? where id = ?");
query.addBindValue(name);
query.addBindValue(useId);
return query.exec();
}
editquerymodel.h
#ifndef EDITQUERYMODEL_H
#define EDITQUERYMODEL_H
#include<QSqlQueryModel>
class editQueryModel : public QSqlQueryModel
{
public:
editQueryModel();
//重写基类的虚函数
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);//操作数据库
Qt::ItemFlags flags(const QModelIndex &index) const;//给一个单元框属性 可编辑的状态
private:
//自定义接口函数
//更新数据
void refresh();
//根据需求来定义修改表中的内容的接口
bool setName(int useId,const QString& name);
};
#endif // EDITQUERYMODEL_H
知识点三:自定义接口函数
refresh()、setName()
(二)QSqlQueryModel自定义高级接口应用:
1、案例描述
通过重写QSqlQueryModel虚函数,实现对QSqlQueryModel的改造,让改造后的editquerymodel实现可读可写。下列函数editquerymodel实现了对第1列name的修改,并通过QTableView控件来实现staff表格的展示。
2、案例实现
1)新建mainwindow项目
2)新建c++ class:项目右键--->Add New...--->c++--->c++ class
(生成 editquerymodel.cpp、editquerymodel.h两个文件)
3)在.pro文件中增加sql
4)editquerymodel.h接口类的声明
#ifndef EDITQUERYMODEL_H
#define EDITQUERYMODEL_H
#include<QSqlQueryModel>
class editQueryModel : public QSqlQueryModel
{
public:
editQueryModel();
//重写基类的虚函数
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);//操作数据库
Qt::ItemFlags flags(const QModelIndex &index) const;//给一个单元框属性 可编辑的状态
private:
//自定义接口函数
//更新数据
void refresh();
//根据需求来定义修改表中的内容的接口
bool setName(int useId,const QString& name);
};
#endif // EDITQUERYMODEL_H
5)editquerymodel.cpp接口类的实现
#include "editquerymodel.h"
#include<QSqlQuery>
editQueryModel::editQueryModel()
{
}
bool editQueryModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
//[1]判断列是否为有效的列 员工---Id 用户名 年龄 地址 薪资
if(index.column() < 1 ||index.column() > 4)
return false;
//获取列所对应的id
QModelIndex primaryIndex= QSqlQueryModel::index(index.row(),0);
int id = this->data(primaryIndex).toInt();//获取字段表中的id
//在修改行之前,将数据清除,将整个model清空
this->clear();
bool ok;
//根据需求修改对应的列
if(index.column() ==1)//用户名对应第一列
{
ok = setName(id,value.toString());
}
//刷新数据
refresh();
return ok;
}
Qt::ItemFlags editQueryModel::flags(const QModelIndex &index) const
{
//[1]获取当前单元格的编辑状态
Qt::ItemFlags flag = QSqlQueryModel::flags(index);
//[2]给现有的标志增加可编辑的标志
if(index.column()==1)//当是第一列的时候
{
flag = flag | Qt::ItemIsEditable;//给它设置一个可编辑的状态
return flag;
}
}
void editQueryModel::refresh()
{
//执行查询 将数据库的数据查询出来,转换成一个model
this->setQuery("select * from staff");
this->setHeaderData(0,Qt::Horizontal,"ID");
this->setHeaderData(1,Qt::Horizontal,"Name");
this->setHeaderData(2,Qt::Horizontal,"Age");
this->setHeaderData(3,Qt::Horizontal,"Address");
this->setHeaderData(4,Qt::Horizontal,"Salary");
}
bool editQueryModel::setName(int useId, const QString &name)
{
//执行name的更新,相当于刷新接口
QSqlQuery query;
query.prepare("update staff set name = ? where id = ?");
query.addBindValue(name);
query.addBindValue(useId);
return query.exec();
}
6)mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QSqlDatabase>
#include<QSqlQueryModel>
#include<QSqlError>
#include<QtDebug>
#include<QSqlQuery>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QSqlDatabase m_db;
};
#endif // MAINWINDOW_H
7)mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<editquerymodel.h>
#include<QTableView>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setDatabaseName("compary.db");
if(!m_db.open())
{
qDebug()<<"open error"<<m_db.lastError();
}
QSqlQuery query;
#if 0
QString sqlCreatTable = QString("create table staff(id integer primary key autoincrement,"
"name varchar(20),"
"age int,"
"address varchar(50),"
"salary int);");
if(!query.exec(sqlCreatTable))
{
qDebug()<<"table create error"<<m_db.lastError();
}
//插入操作
QString sqlInsert = QString("insert into staff(name,age,address,salary) "
"values('张三',20,'广州天河区','12000');");
if(!query.exec(sqlInsert))
{
qDebug()<<"insert table error"<<m_db.lastError();
}
#endif
//[1]创建模型对象
editQueryModel *model = new editQueryModel;
model->setQuery("select * from staff");
model->setHeaderData(0,Qt::Horizontal,"ID");
model->setHeaderData(1,Qt::Horizontal,"Name");
model->setHeaderData(2,Qt::Horizontal,"Age");
model->setHeaderData(3,Qt::Horizontal,"Address");
model->setHeaderData(4,Qt::Horizontal,"Salary");
//[2]创建表格控件
QTableView *view = new QTableView(ui->centralwidget);
view->setFixedSize(QSize(this->width(),this->height()));
view->setModel(model);
view->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
四、总结
本文通过学习QSqlDataBase、QSqlQuery、QSqlQueryModel等QT数据库接口,实现对数据库的基本操作、数据的UI控件显示,其中UI控件使用了QListWidget、QTableView,控件的异同请参考博客:QTableView、QTreeView、QListWIdget相同点和区别(异同)_qtreeview与qtreewidget的区别_三公子Tjq的博客-CSDN博客