当前位置: 首页 > news >正文

Qt QML创建多线程(示例存读数据库)

最近做了个小项目,发现当数据库中数据量过大时,GUI界面就会卡死,因为耗时的读取操作会阻塞主线程。为了解决这个问题,我就使用了多线程来稍微重构了一下,用子线程来处理这类耗时任务,而让主线程负责绘制界面,从而保持界面响应

那么如何创建一个子线程来与主线程进行数据交互呢,下面我来码个例子:

一、创建类

创建继承QObject的主线程类和子线程类,并声明槽函数和信号

//MainThread.h#ifndef MAINTHREAD_H
#define MAINTHREAD_H#include <QObject>
#include "multithread.h"
#include <QThread>class MainThread : public QObject
{Q_OBJECT
public:explicit MainThread(QObject *parent = nullptr);~MainThread();    //析构函数,当程序退出时自动调用private slots:void getdata();    //释放dataready信号void loaddata(const QVariantList &data);    //释放dataload信号signals:void to_getdata(const QVariantList &data);    //通知子线程去准备数据void to_loaddata();    //通知子线程去加载数据void dataready();    //子线程数据准备完毕void dataload(const QVariantList &data);    //子线程数据加载完毕private:MultiThread *worker;    //工作类对象QThread *workthread;    //子线程对象
};#endif // MAINTHREAD_H
//MultiThread.h#ifndef MULTITHREAD_H
#define MULTITHREAD_H#include <QObject>
#include <QSqlDatabase>class MultiThread : public QObject
{Q_OBJECT
public:explicit MultiThread(QObject *parent = nullptr);~MultiThread();public slots:void do_getdata(const QVariantList &data);    //处理保存数据void do_loaddata();    //处理读取数据signals:void dataready(const QVariantList &data);    //数据保存结束void datachange();    //数据读取结束private:void init();    //初始化创建QSqlDatabase db;
};#endif // MULTITHREAD_H

二、实现子线程槽函数

我们先实现子线程中实际处理数据的槽函数,例子中就是实现了一下数据库的存读操作,并在操作结束后发出信号来通知主线程

//MultiThread.cpp#include "multithread.h"
#include <QSqlQuery>
#include <QSqlDatabase>
#include <QSqlError>MultiThread::MultiThread(QObject *parent): QObject{parent}
{init();
}MultiThread::~MultiThread()
{if(db.open()){db.close();}
}void MultiThread::do_getdata(const QVariantList &data)
{QSqlQuery cleardata(db);cleardata.exec("DELETE FROM sample");QSqlQuery insertdata(db);insertdata.prepare("INSERT INTO sample (number,name,major)""VALUES (?,?,?)");for(const QVariant &piece:data){QVariantMap map;map=piece.toMap();insertdata.addBindValue(map["number"]);insertdata.addBindValue(map["name"]);insertdata.addBindValue(map["major"]);if(!insertdata.exec()){qWarning()<<"子线程添加数据失败"<<insertdata.lastError().text();}}emit datachange();    //发出保存数据操作结束的信号qDebug()<<"子线程保存成功";
}void MultiThread::do_loaddata()
{QVariantList list;QSqlQuery query(db);query.exec("SELECT * FROM sample");while(query.next()){QVariantMap map;map["number"]=query.value(0).toInt();map["name"]=query.value(1).toString();map["major"]=query.value(2).toString();list.append(map);}qDebug()<<"子线程读取成功";emit dataready(list);    //发出读取数据操作结束的信号
}void MultiThread::init()
{if(QSqlDatabase::contains("example")){db=QSqlDatabase::database("example");}else{db=QSqlDatabase::addDatabase("QSQLITE","example");}db.setDatabaseName("sample.db");if(!db.open()){qDebug()<<"子线程打开数据库失败"<<db.lastError().text();}QSqlQuery query(db);query.prepare("CREATE TABLE IF NOT EXISTS sample(""number INTEGER PRIMARY KEY,""name TEXT,""major TEXT"")");if(!query.exec()){qWarning()<<"子线程创建数据库失败"<<query.lastError().text();}
}

三、在主线程类中实现信号与槽的连接

信号与槽机制实现主线程和子线程的交互,并发出信号通知GUI界面更新操作

//MainThread.cpp#include "mainthread.h"
#include <QThread>MainThread::MainThread(QObject *parent): QObject{parent}
{workthread=new QThread(this);    //创建子线程,当主线程销毁时worker=new MultiThread();    //创建工作类的实例worker->moveToThread(workthread);    //将其移动至子线程//线程管理,防止内存泄漏connect(workthread,&QThread::finished,worker,&QObject::deleteLater);    //当子线程结束时,调用worker->deleteLater(),即自动销毁工作类对象connect(workthread,&QThread::finished,workthread,&QObject::deleteLater);    //同上,当子线程结束时,销毁子线程本身//存读操作connect(this,&MainThread::to_getdata,worker,&MultiThread::do_getdata);    //存储操作//当MainThread对象发出to_getdata信号时,worker会在子线程接收并调用do_getdata槽函数connect(worker,&MultiThread::datachange,this,&MainThread::getdata);    //当woker完成do_getdata后发出datachange信号,MainThread对象调用getdata槽函数发出dataready信号,通知GUI界面加载数据connect(this,&MainThread::to_loaddata,worker,&MultiThread::do_loaddata);    //读取操作connect(worker,&MultiThread::dataready,this,&MainThread::loaddata);workthread->start();    //启动子线程
}MainThread::~MainThread()
{workthread->quit();    //发出退出请求workthread->wait();    //阻塞调用线程,确保子线程退出
}void MainThread::getdata()
{emit dataready();
}void MainThread::loaddata(const QVariantList &data)
{emit dataload(data);
}

四、QML示例

我在main.qml中写了个ListView来演示了一下存读操作

//main.qmlimport QtQuick
import QtQuick.Controls.Material
import mainthread 1.0Window {width: 640height: 480visible: truetitle: qsTr("Hello World")//ListModel先填写数据,保存后注释掉,再次打开验证读取ListModel{id:examplemodel// ListElement{//     number:12//     name:"小明"//     major:"计算机"// }// ListElement{//     number:16//     name:"小李"//     major:"土木工程"// }}ListView{anchors.centerIn: parentwidth: 290height: 480model:examplemodelclip:truespacing:40delegate: Rectangle{width: 290height: 30Row{spacing: 50Text {text:model.numberanchors.verticalCenter: parent.verticalCenterfont.pixelSize: 20}Text {text:model.nameanchors.verticalCenter: parent.verticalCenterfont.pixelSize: 20}Text {text:model.majoranchors.verticalCenter: parent.verticalCenterfont.pixelSize: 20}}}Component.onCompleted: {maintd.to_loaddata()    //组件加载完毕时发出to_loaddata信号,请求子线程加载}}Button{anchors.right: parent.rightanchors.top: parent.topheight: 60width: 100text: "保存"onClicked: {let data=[]for(let i=0;i<examplemodel.count;i++){let getdata=examplemodel.get(i)data.push({number:getdata.number,name:getdata.name,major:getdata.major})}maintd.to_getdata(data)    //点击保存发出to_getdata信号,请求子线程保存}}MainThread{id:maintdonDataready:{    //信号处理器,当MainThread发出dataready信号时,打印“保存成功”console.log("保存成功")}onDataload: (data)=>{    //当MainThread发出dataload信号时,捕获data,更新examplemodelexamplemodel.clear()for(let i=0;i<data.length;i++){examplemodel.append(data[i])}}}
}

简单来说,整体逻辑其实就是,在QML中发出信号,请求子线程处理任务,子线程完成操作后发出信号通知主线程,主线程调用槽函数接收数据并再次发出信号通知QML,QML通过信号处理器捕获信号并响应。

通过使用多线程,便能够实现先弹出加载动画,等到数据加载完毕后再显示等效果,从而提升界面流畅度。同时,多个线程也能够并行执行多个任务,有效的提高处理性能

http://www.dtcms.com/a/431756.html

相关文章:

  • 2026届计算机毕业设计选题推荐
  • 邹城市网站建设长春网站建设方案外包
  • 合肥建公司网站万户信息 做网站怎么样
  • 第十篇:告别new和delete:RAII机制与智能指针导论
  • 做搜狗pc网站优化快速深圳企业模板建站
  • 深度学习第十章 循环神经网络
  • 设计一个外贸网站需要多少钱wordpress 博客地址更改
  • ASP网站建设实训报告总结大德通众包做网站怎么样
  • 查询网站死链接温州百度快速排名优化
  • 网站建设全包哪家便宜怎么在网站上做按钮
  • 永州网站建设哪家好中信建设有限责任公司深圳中信金融中心项目工期专业招标
  • 八年级信息网站怎么做网站设计的价格
  • OSPF Init 状态 概念及题目
  • 事件相关电位(Event-Related Potential,ERP)
  • 运营一个网站的成本wordpress 网站小模块
  • 怀化市建设局网站地址wordpress建什么站
  • 网站域名解析怎么做wordpress筛选最新文章
  • 【知识科普】JSON数据格式详细介绍
  • wordpress站酷首页wordpress引用jquery
  • 深度学习中的池化(Pooling)技术:原理、实现与应用
  • 手机响应式网站建设公司做电商必须知道的网站
  • Linux任务上下文切换context_switch函数的实现
  • 移动网站开发教学大纲安装wordpress 000
  • 《小米 17:创新与争议并存的科技新品》
  • thinkphp怎么做网站壹六八信息科技网站建设
  • 网站建站企业wex5 后端实现全网站开发
  • leetcode 47 全排列II
  • 注册公司是在哪个网站有哪些做普洱茶网站的
  • Vscode安装Element ui
  • Unity游戏基础-1(安装~工作区构建)