Qt学习第5天:线程与数据库【笔记】
文章目录1. 线程为什么需要使用线程线程使用线程关闭2. 数据库数据库连接数据库插入数据库删除和遍历可视化操作数据库1. 线程为什么需要使用线程线程使用线程关闭2. 数据库数据库连接数据库插入数据库删除和遍历可视化操作数据库...
·
1. 线程
为什么需要使用线程
- 当界面中处理很复杂的数据时,可能会造成界面未响应,这时可以把数据处理放在线程中来处理
- 多任务处理
线程使用
主线程:UI
Qt 4中比较简单
自定义一个类,继承于QThread
class MyThread:public QThread
{
public:
void run();//只有这一个才是线程处理函数(和主线程不在同一线程)
}
void MyThread::run()
{
QThread::sleep(5);//模拟复杂数据处理
emit isDone();
}
主线程中:
//启动线程
//不能直接调用run()
//start()间接调用run()
MyThread thread;
thread.start();
注意,线程号是有限的,要养成良好的习惯,用完以后关闭线程!
线程关闭
对于线程的关闭,不推荐使用terminal(),该函数不管是否处理完当前数据,都会直接关闭。
推荐使用quit()
Demo如下:
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QTimer> // 定时器头文件
#include "mythread.h" //线程头文件
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = nullptr);
~MyWidget();
void dealTimeout(); //定时器槽函数
void dealDone(); //线程结束槽函数
void stopThread(); //停止线程槽函数
private slots:
void on_pushButton_clicked();
private:
Ui::MyWidget *ui;
QTimer *myTimer; //声明变量
MyThread *thread; //线程对象
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
#include <QDebug>
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
myTimer = new QTimer(this);
//只要定时器启动,自动触发timeout信号
connect(myTimer,&QTimer::timeout,this,&MyWidget::dealTimeout);
//分配空间
thread = new MyThread(this);
connect(thread,&MyThread::isDone,this,&MyWidget::dealDone);
//当按窗口右上角x时,窗口触发destroyed()信号
connect(this,&MyWidget::destroyed,this,&MyWidget::stopThread);
}
void MyWidget::dealTimeout()
{
static int i = 0;
i++;
//设置lcd的值
ui->lcdNumber->display(i);
}
MyWidget::~MyWidget()
{
delete ui;
}
void MyWidget::on_pushButton_clicked()
{
//如果定时器没有工作,才启动
if(myTimer->isActive() == false)
{
myTimer->start(500);
}
/***************************************
* 未使用线程前的测试代码
***************************************/
/*
//非常复杂的数据处理,耗时较长
//此处模拟
QThread::sleep(3);
//处理完数据后,关闭定时器
//myTimer->stop();
qDebug() <<"over";
//什么时候用线程?
//处理数据很复杂的时候,数据处理就应该放在线程而不是界面
*/
//启动线程,处理数据
thread->start();
}
void MyWidget::dealDone()
{
qDebug() << "it is over";
myTimer->stop();//关闭定时器
}
void MyWidget::stopThread()
{
//停止线程
thread->quit();
//等待线程处理完手头工作
thread->wait();//阻塞线程,直到线程完成
qDebug() << "退出线程";
/* 注释thread->wait()时,调试记录如下(线程正在执行,关闭窗口):
* 退出线程
* QThread: Destroyed while thread is still running
* 14:19:36: The program has unexpectedly finished.
*/
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
protected:
//QThread的虚函数
//线程处理函数
//不能直接调用,通过start()间接调用
void run();
signals:
void isDone();
public slots:
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
MyThread::MyThread(QObject *parent) : QThread(parent)
{
}
void MyThread::run()
{
//很复杂的数据处理
//需要耗时5s
sleep(5); //处理完了需要告诉一声:已经处理完了
emit isDone();
}
Qt 5中的线程
- 设定一个类,继承于QObject
- 类中设置一个线程函数(只有一个是线程函数)

mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
//线程处理函数
void myTimeout();
void setFlag(bool flag = true);
signals:
void mySignal();
public slots:
private:
bool isStop;
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QThread>
#include <QDebug>
MyThread::MyThread(QObject *parent) : QObject(parent)
{
isStop = false;
}
void MyThread::myTimeout()
{
while (isStop == false)
{
//每隔1s发一个信号
QThread::sleep(1);
emit mySignal();
qDebug() << "子线程号:" <<QThread::currentThread();
if(true == isStop)
{
break;
}
}
}
void MyThread::setFlag(bool flag)
{
isStop = flag;
}
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include "mythread.h"
#include <QThread>
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = nullptr);
~MyWidget();
void dealSignal();
void dealClose();
signals:
void startThread(); //启动子线程的信号
private slots:
void on_butttonStart_clicked();
void on_buttonStop_clicked();
private:
Ui::MyWidget *ui;
MyThread *myT;
QThread *thread;
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDebug>
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
//动态分配空间,不能指定父对象
myT = new MyThread;
//创建子线程
thread = new QThread(this);
//把自定义的线程加入子线程中
myT->moveToThread(thread);
connect(myT,&MyThread::mySignal,this,&MyWidget::dealSignal);
qDebug() << "主线程号:" <<QThread::currentThread();
connect(this,&MyWidget::startThread,myT,&MyThread::myTimeout);
connect(this,&MyWidget::destroyed,this,&MyWidget::dealClose);
}
MyWidget::~MyWidget()
{
delete ui;
}
void MyWidget::on_butttonStart_clicked()
{
if(thread->isRunning() == true)
{
return;
}
//启动线程,但是没有线程处理函数
thread->start();
myT->setFlag(false);
// 不能直接调用线程处理函数
// 直接调用会导致:线程处理函数和主线程是在同一个线程
//myT->myTimeout();//反例
//只能通过signal - slot 方式调用
emit startThread();
}
void MyWidget::dealSignal()
{
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
void MyWidget::on_buttonStop_clicked()
{
if(thread->isRunning() == false)
{
return;
}
// 由于quit()退出线程的方式很温柔,
// 而且线程的工作是个死循环,退不出来,因此这种方法不可行
// 解决方案:在while(1)中加入一个标志位
myT->setFlag(true);
thread->quit();
thread->wait();
}
void MyWidget::dealClose()
{
//槽函数就是函数,可以直接调
on_buttonStop_clicked();
delete myT;//防止内存泄露
}
注意:
线程处理函数内部,不允许操作图形界面
纯数据处理,在后台运行!!
connect()第五个参数的作用,只有在多线程时才有意义
连接方式:默认,队列,直接
默认的时候:如果是多线程,默认使用队列;如果单线程,默认使用直接方式
队列:槽函数所在的线程和接收者一样
直接:槽函数所在线程和发送者一样
线程画图示例
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QImage>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
//线程处理函数
void drawImage();
signals:
void updateImage(QImage temp);
public slots:
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QPainter>
#include <QPen>
#include <QBrush>
MyThread::MyThread(QObject *parent) : QObject(parent)
{
}
void MyThread::drawImage()
{
//定义QImage绘图设备
QImage image(500,500,QImage::Format_ARGB32);
//定义画家,指定绘图设备
QPainter p(&image);
//定义画笔对象
QPen pen;
pen.setWidth(5);//设置画笔宽度
//把画笔交给画家
p.setPen(pen);
//定义画刷
QBrush brush;
brush.setStyle(Qt::SolidPattern);//设置样式
brush.setColor(Qt::red);//设置颜色
//把画刷交给画家
p.setBrush(brush);
//定义5个点
QPoint a[]
{
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500)
};
p.drawPolygon(a,5);
//通过信号发送图片
emit updateImage(image);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "mythread.h"
#include <QThread>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
//重写绘图事件
void paintEvent(QPaintEvent *);
void getImage(QImage);//槽函数
void dealClose();//退出窗口时关闭线程
private:
Ui::Widget *ui;
QImage image;
MyThread *myT;//自定义线程对象
QThread *thread;//子线程
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//自定义类对象,分配空间,不可指定父对象
myT = new MyThread;
//创建子线程
thread = new QThread(this);
//把自定义模块添加到子线程
myT->moveToThread(thread);
//启动子线程,但是并没有启动线程处理函数
thread->start();
//线程处理函数,必须通过signal - slot 调用
connect(ui->pushButton,&QPushButton::pressed,myT,&MyThread::drawImage);
connect(myT,&MyThread::updateImage,this,&Widget::getImage);
connect(this,&Widget::destroyed,this,&Widget::dealClose);
}
Widget::~Widget()
{
delete ui;
}
void Widget::dealClose()
{
//退出子线程
thread->quit();
//回收资源
thread->wait();
delete myT;
}
void Widget::getImage(QImage temp)
{
image = temp;
update();//更新窗口,间接调用paintEvent()
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this);//创建画家,指定绘图设备为窗口
p.drawImage(50,50,image);
}
2. 数据库
以MySQL为例,使用前需要先添加sql模块,并且将libmysql.dll放到D:\Qt\Qt5.12.1\5.12.1\mingw73_64\bin下(以实际安装目录为准)
数据库连接
#include <QSqlDatabase>
...
//添加MySQL数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
//连接数据库
db.setHostName("127.0.0.1");//数据库服务器IP
db.setUserName("root");//数据库用户名
db.setPassword("123456");//数据库用户密码
db.setDatabaseName("info");//使用哪个数据库
...
数据库插入
#include <QSqlQuery>
#include <QVariantList>
...
QSqlQuery query;
//直接通过sql语句创建表
//query.exec("create table student(id int primary key auto_increment,name varchar(255),age int,score int);");
//插入
//query.exec("insert into student(id,name,age,score) values(1,'mike',18,59)");
//批量插入
//obdc风格
/*
//预处理语句
// ? 相当于占位符
query.prepare("iinsert into student(name,age,score) values(?,?,?);");
//给字段设置内容 list
QVariantList nameList;
nameList << "xiaoming" << "xiaolong" << "xiangliang";
QVariantList ageList;
ageList << 11 << 22 << 33;
QVariantList scoreList;
scoreList << 59 << 69 << 79;
//给字段绑定相应的值,按顺序绑定,否则会出问题
query.addBindValue(nameList);
query.addBindValue(ageList);
query.addBindValue(scoreList);
//执行预处理命令
query.execBatch();
*/
//oracle风格
//占位符 : + 自定义名字
query.prepare("iinsert into student(name,age,score) values(:name,:age,:score);");
QVariantList nameList;
nameList << "xiaoA" << "xiaoB" << "xiangC";
QVariantList ageList;
ageList << 21 << 12 << 43;
QVariantList scoreList;
scoreList << 49 << 29 << 59;
//给字段绑定
query.bindValue(":name",nameList);
query.bindValue(":age",ageList);
query.bindValue(":score",scoreList);
//执行预处理命令
query.execBatch();
...
数据库删除和遍历
留坑
可视化操作数据库
留坑
更多推荐



所有评论(0)