1.基本知识的学习
Qt 提供了 QtSql 模块来提供平台独立的基于 SQL 的数据库操作。这里我们所说的“平台独立”,既包括操作系统平台,有包括各个数据库平台。另外,我们强调了“基于 SQL”,因为 NoSQL 数据库至今没有一个通用查询方法,所以不可能提供一种通用的 NoSQL 数据库的操作。Qt 的数据库操作还可以很方便的与 model/view 架构进行整合。通常来说,我们对数据库的操作更多地在于对数据库表的操作,而这正是 model/view 架构的长项。
Qt 使用QSqlDatabase表示一个数据库连接。更底层上,Qt 使用驱动(drivers)来与不同的数据库 API 进行交互。Qt 桌面版本提供了如下几种驱动:
2.小细节
找到系统中所有可用的数据库驱动的名字列表。我们只能使用出现在列表中的驱动。由于默认情况下,QtSql 是作为 Qt 的一个模块提供的。为了使用有关数据库的类,我们必须早 .pro 文件中添加这么一句:
3.QT 的数据库的使用 :qt----QSqlDatabase数据库
建立一个类:
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QSqlDatabase database;//建立了数据库的对象
void connectDb();//数据库的初始化
void createTable();//建表
bool isStudentExist(int);//判断 这个id 是否存在
int beforeId;
int beforeAge;
QString beforeName;
private slots:
void btnInsterSlot();//添加信息的按键槽函数
void btnDeleteSlot();//删除信息的按键槽函数
void btnUpdateSlot();//根据学生信息里面的id 来进行 数据更改
void btnSelectSlot();//更新ui 设计界面的数据
};
4.数据库的初始化:
void Dialog::connectDb()//数据库 初始化函数
{
//使用Sqlite的驱动获得数据库连接的对象
database = QSqlDatabase::addDatabase("QSQLITE");
//设置数据库文件的名称
database.setDatabaseName("Student_info.db");
//设置用户名 密码
database.setUserName("she001");//用户名
database.setPassword("123");//密码
if(database.open())
{
qDebug() << "数据库连接成功";
//连接成功,建表
createTable();
}
else
{
//连接失败
QSqlError error = database.lastError();
QMessageBox::critical(this,"错误",error.text());
}
}
5.增加数据
void Dialog::btnInsterSlot()//添加信息的按键槽函数
{
QString name = ui->lineEdit_name->text();//提取输入框的信息 (姓名)
if (name == "")//判断信息是否为空
{
QMessageBox::warning(this,"警告","请输入完整的信息");//警告的提示框
return;
}
int id = ui->spinBox_id->value();//提取id 的大小
int age = ui->spinBox_age->value();//提取的 年龄的大小
QSqlQuery sq;//创建分类表
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "INSERT INTO student VALUES(?,?,?)";
//预处理
sq.prepare(sql);//绑定函数 因为在prepare()中虽然是标准的SQL指令,但是对于具体的数值类的量不可能在string表示出来
//占位符数据替换
sq.addBindValue(id);
sq.addBindValue(name);
sq.addBindValue(age);
//执行sql语句
if(sq.exec())//绑定成功后调用exec()就可以执行插入操作,写入数据库,成功与否就看exec()返回值了。
{
btnSelectSlot();//更新ui 设计界面的数据
QMessageBox::information(this,"通知","添加成功");
}
else
{
QString errorMsg = sq.lastError().text();
QMessageBox::critical(this,"错误",errorMsg);
}
}
6.删除数据
void Dialog::btnDeleteSlot()//删除学生的信息
{
int id = ui->spinBox_id->value();//提取 数据库里面 唯一的key 这个是 删除数据的关键
//判断是否存在
if(!isStudentExist(id))
{
QMessageBox::warning(this,"警告","此学号的学生不存在");
return;
}
QSqlQuery sq;
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "DELETE FROM student WHERE id=:id";
//预处理
sq.prepare(sql);
//占位符数据替换
sq.addBindValue(id);
//执行sql语句
if(sq.exec())
{
btnSelectSlot();//更新ui 设计界面的数据
QMessageBox::information(this,"通知","删除成功");
}
else
{
QString errorMsg = sq.lastError().text();//信息错误的字符串
QMessageBox::critical(this,"删除失败",errorMsg);//错误提示框 加载错误提示信息字符串 弹出提示框
}
}
7.修改个别的数据
void Dialog::btnUpdateSlot()//根据学生信息里面的id 来进行 数据更改
{
QString name = ui->lineEdit_name->text();//提取学生的名字
if (name == "")
{
QMessageBox::warning(this,"警告","请输入完整的信息");
return;
}
int id = ui->spinBox_id->value();//提取信息
int age = ui->spinBox_age->value();
//判断是否存在
if(!isStudentExist(id))
{
QMessageBox::warning(this,"警告","此学号的学生不存在");
return;
}
QSqlQuery sq;
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "UPDATE student SET name=:name,age=:age WHERE id=:id";
//预处理
sq.prepare(sql);//绑定函数
//占位符数据替换
sq.addBindValue(name);
sq.addBindValue(age);
sq.addBindValue(id);
//执行sql语句
if(sq.exec())
{
btnSelectSlot();
QMessageBox::information(this,"通知","修改成功");
}
else
{
QString errorMsg = sq.lastError().text();
QMessageBox::critical(this,"修改失败",errorMsg);
}
}
8.所有的代码:
ui 设计界面
SOL .pro
QT += core gui sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
dialog.cpp
HEADERS += \
dialog.h
FORMS += \
dialog.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QDebug> //输出文字
#include <QSqlDatabase> //qt有关数据库操作常用QSqlDatabase这个类来操作,使用这个类时,首先在模块中添加 Qt += sql 然后再添加头文件 #include <QtSql>
#include <QSqlError> //错误信息提示
#include <QSqlQuery> //
#include <QMessageBox> //信息框
//Qt中使用QDialog来实现对话框,QDialog继承自QWidget
//,对话框分为两种,一种是模态对话框、 另一种是非模态对话框。即阻塞和非阻塞对话框,而模态对话框又有两种:
//应用程序级别的和窗口级别的,分别指完成对话框之前阻塞整个应用和阻塞关联窗口。
//exec() 和 open() 分别为应用程序级别和窗口级别的模态对话框,show()则为非模态对话框。
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QSqlDatabase database;//建立了数据库的对象
void connectDb();//数据库的初始化
void createTable();//建表
bool isStudentExist(int);//判断 这个id 是否存在
int beforeId;
int beforeAge;
QString beforeName;
private slots:
void btnInsterSlot();//添加信息的按键槽函数
void btnDeleteSlot();//删除信息的按键槽函数
void btnUpdateSlot();//根据学生信息里面的id 来进行 数据更改
void btnSelectSlot();//更新ui 设计界面的数据
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) ://构造函数
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
setWindowTitle("数据库增删改查");//改变ui界面窗口的题目
QWidget::setWindowState(Qt::WindowActive);
setWindowFlags(Qt::WindowStaysOnTopHint);
connectDb();//数据库 初始化函数
connect(ui->pushButton_insert,SIGNAL(clicked()),this,SLOT(btnInsterSlot()));//按键与槽函数连接
connect(ui->pushButton_delete,SIGNAL(clicked()),this,SLOT(btnDeleteSlot()));
connect(ui->pushButton_select,SIGNAL(clicked()),this,SLOT(btnSelectSlot()));
connect(ui->pushButton_update,SIGNAL(clicked()),this,SLOT(btnUpdateSlot()));
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
Dialog::~Dialog()//析构函数
{
//关闭数据库
if(database.isOpen())
database.close();
delete ui;
}
void Dialog::connectDb()//数据库 初始化函数
{
//使用Sqlite的驱动获得数据库连接的对象
database = QSqlDatabase::addDatabase("QSQLITE");
//设置数据库文件的名称
database.setDatabaseName("Student_info.db");
//设置用户名 密码
database.setUserName("she001");//用户名
database.setPassword("123");//密码
if(database.open())
{
qDebug() << "数据库连接成功";
//连接成功,建表
createTable();
}
else
{
//连接失败
QSqlError error = database.lastError();
QMessageBox::critical(this,"错误",error.text());
}
}
void Dialog::createTable()//建立一个数据表
{
//创建一个数据库操作对象
QSqlQuery sq; //创建分类表
QString sql = "CREATE TABLE Student(id INTEGER PRIMARY KEY,\
name TEXT NOT NULL,age INTEGER)";
if(sq.exec(sql))
qDebug() << "建表成功";
else
qDebug() << sq.lastError().text();//输出错误的原因
}
void Dialog::btnInsterSlot()//添加信息的按键槽函数
{
QString name = ui->lineEdit_name->text();//提取输入框的信息 (姓名)
if (name == "")//判断信息是否为空
{
QMessageBox::warning(this,"警告","请输入完整的信息");//警告的提示框
return;
}
int id = ui->spinBox_id->value();//提取id 的大小
int age = ui->spinBox_age->value();//提取的 年龄的大小
QSqlQuery sq;//创建分类表
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "INSERT INTO student VALUES(?,?,?)";
//预处理
sq.prepare(sql);//绑定函数 因为在prepare()中虽然是标准的SQL指令,但是对于具体的数值类的量不可能在string表示出来
//占位符数据替换
sq.addBindValue(id);
sq.addBindValue(name);
sq.addBindValue(age);
//执行sql语句
if(sq.exec())//绑定成功后调用exec()就可以执行插入操作,写入数据库,成功与否就看exec()返回值了。
{
btnSelectSlot();//更新ui 设计界面的数据
QMessageBox::information(this,"通知","添加成功");
}
else
{
QString errorMsg = sq.lastError().text();
QMessageBox::critical(this,"错误",errorMsg);
}
}
void Dialog::btnDeleteSlot()//删除学生的信息
{
int id = ui->spinBox_id->value();//提取 数据库里面 唯一的key 这个是 删除数据的关键
//判断是否存在
if(!isStudentExist(id))
{
QMessageBox::warning(this,"警告","此学号的学生不存在");
return;
}
QSqlQuery sq;
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "DELETE FROM student WHERE id=:id";
//预处理
sq.prepare(sql);
//占位符数据替换
sq.addBindValue(id);
//执行sql语句
if(sq.exec())
{
btnSelectSlot();//更新ui 设计界面的数据
QMessageBox::information(this,"通知","删除成功");
}
else
{
QString errorMsg = sq.lastError().text();//信息错误的字符串
QMessageBox::critical(this,"删除失败",errorMsg);//错误提示框 加载错误提示信息字符串 弹出提示框
}
}
// 更新固定学号的人
void Dialog::btnUpdateSlot()//根据学生信息里面的id 来进行 数据更改
{
QString name = ui->lineEdit_name->text();//提取学生的名字
if (name == "")
{
QMessageBox::warning(this,"警告","请输入完整的信息");
return;
}
int id = ui->spinBox_id->value();//提取信息
int age = ui->spinBox_age->value();
//判断是否存在
if(!isStudentExist(id))
{
QMessageBox::warning(this,"警告","此学号的学生不存在");
return;
}
QSqlQuery sq;
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "UPDATE student SET name=:name,age=:age WHERE id=:id";
//预处理
sq.prepare(sql);//绑定函数
//占位符数据替换
sq.addBindValue(name);
sq.addBindValue(age);
sq.addBindValue(id);
//执行sql语句
if(sq.exec())
{
btnSelectSlot();
QMessageBox::information(this,"通知","修改成功");
}
else
{
QString errorMsg = sq.lastError().text();
QMessageBox::critical(this,"修改失败",errorMsg);
}
}
void Dialog::btnSelectSlot()//更新ui 设计界面的数据
{
//清空之前的显示
ui->tableWidget->setRowCount(0);
QSqlQuery sq;
QString sql = "SELECT * FROM student ";
//执行sql语句
if(sq.exec(sql))
{
//遍历
while(sq.next())
{
int id = sq.value("id").toInt();//获取当前表里面的数据的值 id
QString name =sq.value("name").toString();//获取当前表里面的数值 name
int age =sq.value("age").toInt();//获取当前表里面的数值 age
qDebug() << id << name << age;//在下面的数据输出框 输出当前的提取的数据
//获取当前表格中的行数
int rowCount = ui->tableWidget->rowCount();
//添加空白行
ui->tableWidget->insertRow(rowCount);
//给空白行添加数据
ui->tableWidget->setItem(rowCount,0,new QTableWidgetItem(QString::number(id)));//第几行 添加数据 参数1 行数 参数2 列数 参数3 QTableWidgetItem 指明QTableWidget中的一个Item。Item通常包含文本、图标、checkbox。
ui->tableWidget->setItem(rowCount,1,new QTableWidgetItem(name));
ui->tableWidget->setItem(rowCount,2,new QTableWidgetItem(QString::number(age)));
}
}
else
{
QString errorMsg = sq.lastError().text();
QMessageBox::critical(this,"执行失败",errorMsg);
}
}
bool Dialog::isStudentExist(int id)//判断 这个id 是否存在
{
QSqlQuery sq;
//防止sql注入问题,预处理(:id,:name,:age)
QString sql = "SELECT * FROM student WHERE id=:id";
//预处理
sq.prepare(sql);
//占位符数据替换
sq.addBindValue(id);
//执行sql语句
if(sq.exec())
{
return sq.next();
}
else
{
return false;
}
}
mian.cpp
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
9.基本操作的提示
1、创建数据库
1 2 3 4 5 6 7 |
|
2、数据库的增删改查(查询命令就是SQL的通用命令)
1.创建一张表
1 2 3 4 5 6 |
|
2.查询/获取键值
1 2 3 4 |
|
3.修改/写入数据库
1 2 3 4 5 6 7 8 |
|
10.知识的补充
Qt中的Qt SQL模块提供了对数据库的支持,模块中类可分为三层:驱动层,sql接口层,用户层。
驱动层:(QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlDriverPlugin)为具体的数据库和SQL接口层之间提供了底层的桥梁;
SQL接口层:(QSqlDatabase,QSqlQuery,QSqlError,QSqlRecord)提供了对数据库的访问,其中QSqlDatabase类用来创建连接,QSqlQuery类可以使用SQL语句来实现与数据库交互;
用户接口层:(QSqlTableModel,QSqlQueryModel,QSqlRelationalTableModel)实现了将数据库中的数据链接到窗口部件上,这些类是使用模型/视图框架实现的,它们是更高层次的抽象;
创建一个数据库
格式为:create database 数据库名;
例:create database test;
创建一个表
格式为:create table 表名(内容 类型);
例:create table student(number int , name char(32), score double);
向表中插入信息
格式为:insert into 表名 values(表中的内容);
例:insert into student values(1, 'xiaoming', 99);
从表格中删除信息
格式为:delete from 表名 where 列名 = 条件;
例:delete from student where name = 'xiaoming';
查询表中的内容
格式为:select 列名 from 表名 where 列名 = 条件;
例:select score from student where name = 'xiaoming';
我们可以用这样的语句查询所有的信息
select * from student;
修改表中的数据
格式为:update 表名 set 列名 = 新内容 where 列名 = 条件;
例:update student set score = 66 where name = 'xiaoming';
从数据库中删除一个表
格式为:drop table 表名;
例:drop table student;
11.别的版本的代码
#include "sqlitedatabase.h"
SqliteDatabase::SqliteDatabase()
{
qDebug() << "hhh";
// initPickNameDB();
}
void SqliteDatabase::initPickNameDB()
{
// 创建并打开数据库
QSqlDatabase database;
database = QSqlDatabase::addDatabase("QSQLITE");
// qDebug() << QApplication::applicationDirPath();
database.setDatabaseName(QApplication::applicationDirPath() + "/CONFIG/" + "PickNameDB.sqlite3");
if(!database.open())
{
qDebug() << "Error: Failed to connect database." << database.lastError();
}
else
{
qDebug() << "Succeed to connect database.";
}
// 创建表格 先清空一下表
QSqlQuery sql_query = database.exec("DROP TABLE department");
sql_query = database.exec("DROP TABLE person");
if(!sql_query.exec("create table department (Id int primary key not null, "
"DeptName vchar(50) not null )"))
{
qDebug() << "Error: Fail to create department table." << sql_query.lastError();
}
else
{
qDebug() << "Department table created!";
}
if(!sql_query.exec("create table person (Id int primary key not null , "
"DeptID integer not null , "
"PerName vchar(50) not null, "
"foreign key(DeptID) references department (Id))"))
{
qDebug() << "Error: Fail to create person table." << sql_query.lastError();
}
// 填充表
// sql_query.exec("insert into department (id, name) values (1, '办领导')");
// sql_query.exec("insert into department (id, name) values (2, '综合处')");
// sql_query.exec("insert into department (id, name) values (3, '政策法规处')");
// sql_query.exec("insert into department (id, name) values (4, '机构改革处')");
// sql_query.exec("insert into department (id, name) values (5, '党群政法行政机构编制管理处')");
// sql_query.exec("insert into department (id, name) values (6, '政府行政机构编制管理处')");
// sql_query.exec("insert into department (id, name) values (7, '市县行政机构编制管理处')");
// sql_query.exec("insert into department (id, name) values (8, '事业机构编制管理处')");
// sql_query.exec("insert into department (id, name) values (9, '事业单位登记管理处')");
// sql_query.exec("insert into department (id, name) values (10, '机构编制监督检查处')");
// sql_query.exec("insert into department (id, name) values (11, '人事处')");
// sql_query.exec("insert into department (id, name) values (12, '机关党委')");
// sql_query.exec("insert into department (id, name) values (13, '省机构编制电子政务中心')");
// sql_query.exec("insert into department (id, name) values (14, '省机构编制研究中心')");
// 批量填充表
QStringList deptNames;
deptNames << "办领导" << "综合处" << "政策法规处" << "机构改革处"
<< "党群政法行政机构编制管理处" << "政府行政机构编制管理处"
<< "市县行政机构编制管理处" << "事业机构编制管理处" << "事业单位登记管理处"
<< "机构编制监督检查处" << "人事处" << "机关党委"
<< "省机构编制电子政务中心" << "省机构编制研究中心";
// 绑定关键字后才能进行操作
sql_query.prepare("INSERT INTO department (Id, DeptName) "
"VALUES (:Id, :DeptName)");
qint8 i = 0;
foreach (QString deptName, deptNames)
{
sql_query.bindValue(":Id", i + 1);
sql_query.bindValue(":DeptName", deptName);
if(!sql_query.exec())
{
qDebug() << "Error: Fail." << sql_query.lastError();
}
i++;
}
// 读取sqlite
department dept;
QVector<department> tmpDept; // 数据库缓存
sql_query.exec("SELECT * FROM ");
}
12.Qt实现Excel表格的读写操作(office,WPS)
我们用QT经常会将表格的数据导入数据库或者将数据库中的数据导出为*.xls/*.xlsx。使用比较多的就是用QAxObject对象进行操作。一般首先会连接数据库:
QAxObject *excel = new QAxObject(this); //连接Excel控件
excel->setControl("Excel.Application");
但是很多人的电脑上并没有安装office,这样会导致运行失败,如果安装了WPS,我们可以
QAxObject *excel = new QAxObject(this); //连接Excel控件
excel->setControl("ket.Application");
这说明office和WPS是兼容的,我们只需要修改这一行代码就可以了。
另外,附上详细的代码说明:
void Window::importExcelToDatabase()
{
QString strFilePathName = QFileDialog::getOpenFileName(this,QStringLiteral("选择Excel文件"),"",tr("Exel file(*.xls *.xlsx)"));
if(strFilePathName.isNull())
{
return ;
}
QAxObject *excel = new QAxObject(this); //连接Excel控件
if (excel->setControl("Excel.Application"))
{
}
else
{
excel->setControl("ket.Application"); //连接Excel控件
}
excel->setProperty("Visible", false); //不显示窗体
QAxObject* workbooks = excel->querySubObject("WorkBooks"); //获取工作簿集合
workbooks->dynamicCall("Open(const QString&)", strFilePathName); //打开打开已存在的工作簿
QAxObject* workbook = excel->querySubObject("ActiveWorkBook"); //获取当前工作簿
QAxObject* sheets = workbook->querySubObject("Sheets"); //获取工作表集合,Sheets也可换用WorkSheets
QAxObject* sheet = workbook->querySubObject("WorkSheets(int)", 1);//获取工作表集合的工作表1,即sheet1
QAxObject* range = sheet->querySubObject("UsedRange"); //获取该sheet的使用范围对象
QVariant var = range->dynamicCall("Value");
delete range;
QVariantList varRows = var.toList(); //得到表格中的所有数据
if(varRows.isEmpty())
{
return;
}
const int rowCount = varRows.size();
QStringList m_userid,m_card_id,m_action;
for(int i = 1; i < rowCount; ++i) //
{
QVariantList rowData = varRows[i].toList();
m_userid<<rowData[0].toString();
m_card_id<<rowData[1].toString();
m_action<<rowData[2].toString();
}
}
注意:对Excel文档的读写操作,如果数据量很大,最好使用多线程,否则会导致主界面的假死。)