文章目录
0 什么情况需要数据库
使用一个东西务必是有原因。那为什么使用数据库?
- 1 大规模的数据需要处理(比如上千上万的数据量)
- 2 需要把数据信息存储起来,无论是本地还是服务上,而不是断电后数据信息就消失了。
如果不是上面的原因化,一般可以使用数组来处理。
1 Qt使用数据库
- 1 .pro文件中添加
QT+=sql
- 2 单独建立一个头文件来处理数据库连接,如建立头文件
#ifndef CONNECTION_H
#define CONNECTION_H
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>
static bool createConnection(){
//连接第一个数据库
//QMYSQL
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "connection1");//需要使用的数据库驱动和联检建立的名称(方便建立多个数据库连接【使用不同的数据库时】区分)
db.setHostName("127.0.0.1");//连接地址
db.setUserName("root");//数据库账户
db.setPassword("root");//密码
db.setPort(8889);//端口
//test_majiang.db
db.setDatabaseName("test_majiang");//需要用到的数据库
if (!db.open()) {//如果数据库连接失败,则弹出
//critical(QWidget *parent, const QString &title,
//const QString &text,
//QMessageBox::StandardButtons buttons = Ok,
//QMessageBox::StandardButton defaultButton = NoButton)
QMessageBox::critical(0, "Cannot open database",
"Unable to establish a database connection", QMessageBox::Cancel);
return false;
}
return true;
}
#endif // CONNECTION_H
如果需要移除一个数据库连接,可以使用。
QSqlDatabase::close();//关闭数据库
QSqlDatabase::removeDatabase();//移除该连接
一般常使用的数据库驱动是MYSQL和QSQLITE。二者区别在于,前者用于服务器存储信息,后者用于本地存储信息。并且QSQLITE主要用于嵌入式,占用资源非常低,占用内存小,通常几百k就搞定。
2 使用数据库
连接上数据库一般就是使用数据库,进行对数据库的增删改查。
这里有三种方法。
2.1 使用QSqlQuery
头文件
#include "connection.h"
#include <QVariant>
#include <QSqlDriver>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlError>
2.1.1 使用数据库前的准备:
//创建数据库连接
if(!createConnection()) return 1;//返回情况可以替换,视不同情况而定
//指定某个数据库连接
QSqlDatabase db2 = QSqlDatabase::database("connection1");
2.1.2 开始对数据进行操作:
首先创建QSqlQuery 对象,然后进行操作。
QSqlDatabase db2 = QSqlDatabase::database("connection2");
QSqlQuery query2(db2);
2.1.3 进行创表和插入值:
// qDebug() << "connection2:";
//创建表,并插入值
query2.exec("create table student (id int primary key,"
"name varchar(20))");
query2.exec("insert into student values(0, 'Mike')");
query2.exec("insert into student values(1, 'Lili')");
query2.exec("insert into student values(2, 'Jame')");
2.1.4 批量处理
上面的单条在这里插入代码片
插入语句明显比较麻烦,可以使用批量插入数据:
query2.exec("insert into student(id,name) values(3,'Qinsong')");//单挑操作
//名称绑定
query2.prepare("insert into student(id, name) values(:id, :name)");
int idValue = 4;
QString nameValue = "Songjiang";
query2.bindValue(":id", idValue);//绑定数据
query2.bindValue(":name", nameValue);
query2.exec();//执行
//位置绑定
query2.prepare("insert into student(id, name) values(?, ?)");
int idValue2 = 5;
QString nameValue2 = "LingChong";
query2.addBindValue(idValue2);//绑定数据
query2.addBindValue(nameValue2);
if(!query2.execBatch()) qDebug() <<"位置绑定:" <<query2.lastError() <<endl;//如果执行不成功执行
//批量处理
query2.prepare("insert into student(id, name) values(?,?)");
QVariantList ids;
ids << 6 << 7 << 8;
query2.addBindValue(ids);
QVariantList names;
names << "Qinghua" << "Nanda" << "Zhongkeda";
query2.addBindValue(names);
if(!query2.execBatch()) qDebug() << query2.lastError()<< endl;
2.1.5 进行查询并输出查询结果:
query2.exec("select * from student");//执行sql语句
while(query2.next()){
qDebug()<< query2.value(0).toInt() << query2.value(1).toString();
}
2.1.6 查看数据驱动支持特性
查看当前数据库是否是支持某特性,比如当前记录的索引数(即结果条数):
int numRows;
if(db2.driver()->hasFeature(QSqlDriver::QuerySize)){//是否该特性
qDebug()<< "has feature:query size";
numRows = query2.size();
}else{
qDebug() << "no feature:query size";
query2.last();
numRows = query2.at() + 1;//使用at,需要之前使用quey2.next()遍历所有select搜索后的结果,而使用query2.size()则不需要
}
//此处执行上面的查询操作,下面的操作才有意义
qDebug() << "row number: " << numRows;
//指向索引为1的记录,即第二条记录
query2.seek(1);
//返回当前索引值
qDebug() << "current index:" << query2.at();
//获得当前行的记录
QSqlRecord record = query2.record();
//获得记录中"id"和"name"两个字段的值
int id = record.value("id").toInt();
QString name = record.value("name").toString();
qDebug() <<"id" << id << "name:" <<name;
//获得索引为1的字段,即第二个字段
QSqlField field = record.field(1);
//输出字段名和字段值,结果为"name"和"MaLiang"
qDebug() << "second field:" << field.name()
<< "field value:" << field.value().toString();
2.1.7 事务(使数据操作变为原子性)
如果中间有一步sql操作执行出错,则全部sql操作都不执行。
QSqlDatabase db2 = QSqlDatabase::database("connection2");
QSqlDatabase::database().transaction();//开始(类似于mutex线程锁)
QSqlQuery query(db2);//此语句必须在上面一条语句的后面
//执行sql操作
QSqlDatabase::database().commit();//结束
2.2 使用QSqlQueryModel查询模型
优势:
- 这是基于sql查询的只读模型,编写sql语句变得容易。
文件头:
#include <QSqlQueryModel>
QSqlDatabase db = QSqlDatabase::database("connection1");
QSqlQueryModel *model = new QSqlQueryModel(this);
model->setQuery("select * from student", db);
model->setHeaderData(0, Qt::Horizontal, tr("学号"));
model->setHeaderData(1, Qt::Horizontal, tr("姓名"));
model->setHeaderData(2, Qt::Horizontal, tr("课程"));
QTableView *view = new QTableView(this);
view->setModel(model);
setCentralWidget(view);
2.3 使用QSqlTableModel表格模型
先上结果:
优势:
- 编译的代码很容易适应其他的数据源,例如后面如果要使用xml文件来存储数据,只需要更换数据模型。
- 提供了一次只能操作一个sql表的读/写模型,可以浏览和修改独立的sql表,并且只需编写很少的代码,无需了解sql语句。
2.3.1 准备
头文件:
#include <QSqlTableModel>
QSqlTableModel* model;//创建对象指针
2.3.2 进行操作:
QSqlDatabase db = QSqlDatabase::database("connection1");
model = new QSqlTableModel(this, db);//由于在窗口的类中创建对象,因此实例化对象时,使用this指针(指向操作函数的指针)作为父对象
model->setTable("student");
model->select();//执行
//设置编辑策略
model->setEditStrategy(QSqlTableModel::OnManualSubmit);//对所有模型改变立即用到数据库
ui->tableView->setModel(model);
常见操作:
// 提交修改按钮
void MainWindow::on_pushButton_clicked()
{
// 开始事务操作
model->database().transaction();
if (model->submitAll()) {
if(model->database().commit()) // 提交
QMessageBox::information(this, tr("tableModel"),
tr("数据修改成功!"));
} else {
model->database().rollback(); // 回滚
QMessageBox::warning(this, tr("tableModel"),
tr("数据库错误: %1").arg(model->lastError().text()),
QMessageBox::Ok);
}
}
// 撤销修改按钮
void MainWindow::on_pushButton_2_clicked()
{
model->revertAll();
}
// 查询按钮,进行筛选
void MainWindow::on_pushButton_5_clicked()
{
QString name = ui->lineEdit->text();
// 根据姓名进行筛选,一定要使用单引号
model->setFilter(QString("name = '%1'").arg(name));
model->select();
}
// 显示全表按钮
void MainWindow::on_pushButton_6_clicked()
{
model->setTable("student");
model->select();
}
// 按id升序排列按钮
void MainWindow::on_pushButton_7_clicked()
{
//id字段,即第0列,升序排列
model->setSort(0, Qt::AscendingOrder);
model->select();
}
// 按id降序排列按钮
void MainWindow::on_pushButton_8_clicked()
{
model->setSort(0, Qt::DescendingOrder);
model->select();
}
// 删除选中行按钮
void MainWindow::on_pushButton_4_clicked()
{
// 获取选中的行
int curRow = ui->tableView->currentIndex().row();
// 删除该行
model->removeRow(curRow);
int ok = QMessageBox::warning(this,tr("删除当前行!"),
tr("你确定删除当前行吗?"), QMessageBox::Yes, QMessageBox::No);
if(ok == QMessageBox::No)
{ // 如果不删除,则撤销
model->revertAll();
} else { // 否则提交,在数据库中删除该行
model->submitAll();
}
}
// 添加记录按钮
void MainWindow::on_pushButton_3_clicked()
{
// 获得表的行数
int rowNum = model->rowCount();
int id = 10;
// 添加一行
model->insertRow(rowNum);
model->setData(model->index(rowNum, 0), id);
// 可以直接提交
//model->submitAll();
}
2.4 使用QSqlRelationalTableModel
先上结果:
优势:
- 1 在QSqlTableModel基础上提供了对外键(一个表的一字字段和另一个表中的主键字段之间的映射)的支持。
文件头:
#include <QSqlRelationalTableModel>
操作:
QSqlDatabase db = QSqlDatabase::database("connection1");
QSqlRelationalTableModel* model = new QSqlRelationalTableModel(this, db);
model->setTable("student");
model->setRelation(2, QSqlRelation("course","id","name"));
model->select();
QTableView* view = new QTableView(this);
view->setModel(model);
setCentralWidget(view);
view->setItemDelegate(new QSqlRelationalDelegate(view));
3 实际应用(登陆)
先上结果:
谈起使用数据库,对于新手来说,最常见的就是实现登陆账户密码的登陆。
3.1 连接数据库
#ifndef CONNECTION_H
#define CONNECTION_H
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>
static bool createConnection(){
//连接第一个数据库
//QMYSQL
QSqlDatabase db2 = QSqlDatabase::addDatabase("QMYSQL", "connection1");
db2.setHostName("127.0.0.1");
db2.setUserName("root");
db2.setPassword("root");
db2.setPort(8889);
//test_majiang.db
db2.setDatabaseName("test_majiang");
if (!db2.open()) {
//critical(QWidget *parent, const QString &title,
//const QString &text,
//QMessageBox::StandardButtons buttons = Ok,
//QMessageBox::StandardButton defaultButton = NoButton)
QMessageBox::critical(0, "Cannot open database",
"Unable to establish a database connection", QMessageBox::Cancel);
return false;
}
return true;
}
#endif // CONNECTION_H
3.2 登陆
一般登陆界面都使用QDialog窗口,为什么呢?
QWidget类是所有用户界面对象的基类。 窗口部件是用户界面的一个原子:它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己的表现。每一个窗口部件都是矩形,并且它们按Z轴顺序排列的。一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分。
QMainWindow 类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态变得更容易。继承使创建当用户点击菜单项或者工具条按钮时被调用的槽成为可能。你也可以使用Qt设计器来创建主窗口。
QDialog类是对话框窗口的基类。对话框窗口是主要用于短期任务以及和用户进行简要通讯的顶级窗口。QDialog可以是模式的也可以是非模式的。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。
QDialog 是最普通的顶级窗口。不被嵌入到一个父窗口部件的窗口部件被叫做顶级窗口部件。通常情况下,顶级窗口部件是有框架和标题栏的窗口(尽管如果使用了一定的窗口部件标记,创建顶级窗口部件时也可能没有这些装饰。)在Qt中,QMainWindow和和不同的QDialog的子类是最普通的顶级窗口。
如果是顶级对话框,那就基于QDialog创建,如果是主窗体,那就基于QMainWindow,如果不确定,或者有可能作为顶级窗体,或有可能嵌入到其他窗体中,则基于QWidget创建。当然了,实际中,你还可以基于任何其他部件类来派生。看实际需求了,比如QFrame、QStackedWidget等等。
此处参考:原文链接:https://blog.csdn.net/ikahn/article/details/6706284
QDialog窗口类的cpp编码:
#include "login.h"
#include "ui_login.h"
#include "connection.h"
#include <QMessageBox>
#include <QDebug>
#include <QWidget>
#include <QStackedWidget>
#include <QSqlError>
Login::Login(QWidget *parent) :
QDialog(parent),
ui(new Ui::Login)
{
ui->setupUi(this);
ui->passwordLineEdit->setEchoMode(QLineEdit::Password);
//设置窗体背景
QPalette palette;
palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/img1.png").scaled(this->size())));//自适应窗口大小
this->setPalette(palette);
this->setWindowTitle("测试登陆界面");
}
Login::~Login()
{
delete ui;
}
//登陆按钮逻辑
void Login::on_loginButton_clicked()
{
QString name = ui->accountLineEdit->text();
QString password = ui->passwordLineEdit->text();
if(name.isEmpty()){
QMessageBox::information(this, tr("请输入账号"),tr("请先输入账号再登陆,谢谢!"),
QMessageBox::Ok);
ui->accountLineEdit->setFocus();
}else if(password.isEmpty()){
QMessageBox::information(this, tr("请输入密码"),tr("请先输入密码再登陆,谢谢!"),
QMessageBox::Ok);
ui->passwordLineEdit->setFocus();
}else{
if(!createConnection()){
QMessageBox::information(this, tr("提示"),tr("请先连接网络,谢谢!"),
QMessageBox::Ok);
}else{
QSqlDatabase db = QSqlDatabase::database("connection1");
QSqlQuery query(db);
QString str = QString("select * from user where account = '%0' and password = '%1'").arg(name).arg(password);
query.exec(str);
int record = query.size();
qDebug() << "record:" << record<< endl;
// while(query.next()){
// qDebug() << query.value(0).toInt() <<query.value(1).toInt()
// <<query.value(2).toString() <<query.value(3).toString();
// }
//未连接上数据库返回-1,连接上查询失败返回0,查到返回1
if(record == -1 || record == 0){
QMessageBox::information(this,tr("提示"),tr("用户名或密码错误!"),QMessageBox::Ok);
ui->passwordLineEdit->clear();
ui->passwordLineEdit->setFocus();
}else{
QMessageBox::information(this,tr("提示"),tr("登陆成功!"),QMessageBox::Ok);
QDialog::accept();
}
}
}
}
主函数:
#include "mywidget.h"
#include <QApplication>
#include "login.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
Login dlg;
if (dlg.exec() == QDialog::Accepted) {
w.show();
return a.exec();
} else {
return 0;
}
}