Qt学习第5天:线程与数据库【笔记】
发布日期:2021-07-01 04:00:45 浏览次数:2 分类:技术文章

本文共 9712 字,大约阅读时间需要 32 分钟。

文章目录

1. 线程

为什么需要使用线程

  1. 当界面中处理很复杂的数据时,可能会造成界面未响应,这时可以把数据处理放在线程中来处理
  2. 多任务处理

线程使用

主线程: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 
#include
// 定时器头文件#include "mythread.h" //线程头文件namespace Ui {
class MyWidget;}class MyWidget : public QWidget{
Q_OBJECTpublic: 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 
#include
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 
class MyThread : public QThread{
Q_OBJECTpublic: 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中的线程
  1. 设定一个类,继承于QObject
  2. 类中设置一个线程函数(只有一个是线程函数)
    在这里插入图片描述
    mythread.h
#ifndef MYTHREAD_H#define MYTHREAD_H#include 
class MyThread : public QObject{
Q_OBJECTpublic: 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 
#include
MyThread::MyThread(QObject *parent) : QObject(parent){
isStop = false;}void MyThread::myTimeout(){
while (isStop == false) {
//每隔1s发一个信号 QThread::sleep(1); emit mySignal(); qDebug() << "子线程号:" <

mywidget.h

#ifndef MYWIDGET_H#define MYWIDGET_H#include 
#include "mythread.h"#include
namespace Ui {
class MyWidget;}class MyWidget : public QWidget{
Q_OBJECTpublic: 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 
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() << "主线程号:" <
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 
#include
class MyThread : public QObject{
Q_OBJECTpublic: explicit MyThread(QObject *parent = nullptr); //线程处理函数 void drawImage();signals: void updateImage(QImage temp);public slots:};#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"#include 
#include
#include
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 
#include "mythread.h"#include
namespace Ui {
class Widget;}class Widget : public QWidget{
Q_OBJECTpublic: 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 
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. 数据库

以为例,使用前需要先添加sql模块,并且将libmysql.dll放到D:\Qt\Qt5.12.1\5.12.1\mingw73_64\bin下(以实际安装目录为准)

数据库连接

#include 
... //添加MySQL数据库 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); //连接数据库 db.setHostName("127.0.0.1");//数据库服务器IP db.setUserName("root");//数据库用户名 db.setPassword("123456");//数据库用户密码 db.setDatabaseName("info");//使用哪个数据库 ...

数据库插入

#include 
#include
... 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(); ...

数据库删除和遍历

留坑

可视化操作数据库

留坑

转载地址:https://miracle.blog.csdn.net/article/details/105907737 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Qt学习第6天:xml 【笔记】
下一篇:“由于找不到Qtxxxx.dll,无法继续执行代码”问题的解决

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月25日 22时20分29秒