QThread 与QObject::moveToThread在UI中的应用

1. QThread的两种用法

第一种用法就是继承QThread,然后覆写 virtual void run(), 这种用法的缺点是不能利用信号槽机制。

第二种用法就是创建一个线程,创建一个对象,再将对象moveToThread, 这种可以充分利用信号槽机制,与UI框架完美融合。这与std::thread也是不一样的地方。

2. moveToThread用法讲解

示例地址:MultiThread/QThreadDemo · 沁明/QtDemo - 码云 - 开源中国 (gitee.com)

直接调用 QObject::moveToThread() 函数,将继承自 QObject 的对象移到线程里面。此时该对象的 槽函数运行在另一个线程里面。 也就是说,当有信号绑定到该对象的槽函数的时候,并发送信号,该槽函数就运行在另一个线程里,否则该函数仍然运行在对象所在的线程中。

1)先创建一个QObject的子类。

它要运行的函数都可以在子线程中运行。

worker.h

#ifndef WORKER_H
#define WORKER_H#include <QObject>class Worker : public QObject
{Q_OBJECT
public:explicit Worker(QObject *parent = nullptr);public slots:void workSlot();void msg1Slot(const QString &m1);void msg3Slot(const QString &m3);signals:void msg1(const QString &m1);void msg2(const QString &m2);
};#endif // WORKER_H

 worker.cpp

#include "worker.h"#include <QDebug>
#include <QThread>Worker::Worker(QObject *parent) : QObject{parent} {connect(this, &Worker::msg1, this, &Worker::msg1Slot);
}void Worker::workSlot() {qDebug() << "QThread begin";qDebug() << "child thread id" << QThread::currentThreadId();qDebug() << "QThread end";// 线槽函数已经执行完进入线程exec()中,可以通过发射信号重新让槽函数在线程中执行。也可以通过// quit() 退出线程exec()。
}void Worker::msg1Slot(const QString &m1) {qDebug() << QThread::currentThreadId() << "receive msg1 " << m1;
}void Worker::msg3Slot(const QString &m3) {qDebug() << QThread::currentThreadId() << "receive msg3 " << m3;
}

2)创建worker对象

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), thread(nullptr) {ui->setupUi(this);worker = new Worker;qDebug() << "主线程" << QThread::currentThreadId();connect(worker, &Worker::msg2, this, &MainWindow::msg2Slot);connect(this, &MainWindow::msg3, worker, &Worker::msg3Slot);
}

直接在窗口构造函数中创建worker对象,程序运行期间这个对象不会被析构。

由于要使用moveToThread函数,所以worker不能设置父对象的,必须为空。

绑定了两个槽函数,分别用来响应消息2和消息3, 但是消息2的槽在窗口对象上,消息3的槽函数在worker对象上。

3)如果不创建子线程,看看3条消息的执行线程在哪?

 如果没有启用子线程的时候,3条消息执行函数都在主线程上。

4)启用子线程之后,3条消息的执行线程是什么?

void MainWindow::on_pushButtonStart_clicked() {qDebug() << "on_pushButtonStart_clicked线程" << QThread::currentThreadId();if (thread)return;thread = new QThread;worker->moveToThread(thread);QObject::connect(thread, &QThread::started, worker, &Worker::workSlot);QObject::connect(thread, &QThread::finished, this,&MainWindow::workerDetach);thread->start();
}

 这里创建了子线程,然后将worker对象移动线程内执行。 

workSlot()执行完毕之后其实线程并没有结束,它会执行exec()进入线程的消息循环

void Worker::workSlot() {qDebug() << "QThread begin";qDebug() << "child thread id" << QThread::currentThreadId();qDebug() << "QThread end";// 线槽函数已经执行完进入线程exec()中,可以通过发射信号重新让槽函数在线程中执行。也可以通过// quit() 退出线程exec()。
}

后面在worker上的信号或者槽绑定的触发都会进行响应。

 使用QThread启动子线程之后,消息1和消息3 的槽函数在子线程上执行了。

但是消息2的槽函数仍在主线程上。

重新复习一下信号槽绑定

Worker::Worker(QObject *parent) : QObject{parent} {connect(this, &Worker::msg1, this, &Worker::msg1Slot);
}

  connect(worker, &Worker::msg2, this, &MainWindow::msg2Slot);connect(this, &MainWindow::msg3, worker, &Worker::msg3Slot);

可以看出槽函数的执行线程就是对象所在的线程。

在创建了子线程之后,worker的执行线程已经发生了变化,所以消息1、3执行线程也变成了子线程。

5)停止子线程之后,恢复原来线程

QObject::connect(thread, &QThread::finished, this,&MainWindow::workerDetach);void MainWindow::workerDetach() {qDebug() << "workerDetach线程" << QThread::currentThreadId();worker->moveToThread(QThread::currentThread());
}

设置在线程退出之后重新移动对象到主线程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/31469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python中元组的常用方法

元组的基本使用 t (1, 2, 3) print(t)统计元组元素出现的次数 t (11, 11, 22, 22, 33, 33, 33, 33, 33) print(t, type(t))print(t.count(33))元组的遍历 t (1, 2, 3)for i in t:print(i)print("-" * 33) for i in range(len(t)):print(t[i])print("-&quo…

c,c++,qt从入门到地狱

前言 1 你所能用的正与你手写的效率相同2 你不需要为你没有用到的特性付出 (无脑的调用函数or公式的空壳人类请出门右转)c 001 scanf and strcpy "_s"bug? 微软官方说明1 Visual Studio 库中的许多函数、成员函数、函数模板和全局变量已弃用,改用微软新增的强化函数…

P3056 [USACO12NOV] Clumsy Cows S

[USACO12NOV] Clumsy Cows S 题目描述 Bessie the cow is trying to type a balanced string of parentheses into her new laptop, but she is sufficiently clumsy (due to her large hooves) that she keeps mis-typing characters. Please help her by computing the min…

RK3588 开启HDCP

主题&#xff1a;按照文档配置无法使能HDCP1.4、HDCP2.3 描述&#xff1a; 按照文档配置无法使能HDCP1.4、HDCP2.3,具体操作如下&#xff1a; 1、dts使能使能hdcp1节点&#xff1a; &hdcp1 { status "okay"; }; 2、DWC_HDCP2_BASE_ESM_Firmware 解压…

浅析Node.js中http代理的实现

文章目录 前言ReadableStream和WritableStreamreq.pipe小结 前言 起因是狼书卷1中的API Proxy例子&#xff0c;代码如下&#xff1a; const http require(http) const fs require(fs)const app http.createServer((req, res) > {if (/remote req.url) {res.writeHead(…

canal 服务安装

简介&#xff1a;Canal 是阿里巴巴开源的一个基于 MySQL 数据库增量日志解析的中间件&#xff0c;用于提供准实时的数据同步功能。 准备工作 1.修改配置文件 ,需要先开启 Binlog 写入功能&#xff0c;配置 binlog-format 为 ROW 模式&#xff0c;my.cnf 中配置如下&#xf…

五种实用方法!手把手教你系统盘瘦身

随着电脑的使用时间变长&#xff0c;电脑硬盘会逐渐被各种类型的数据占满&#xff0c;其中系统盘的可用空间也在慢慢变小。这是因为系统在运行过程中会产生大量临时文件和缓存文件&#xff0c;同时&#xff0c;系统的每一次更新升级也都会生成相关的文件夹存放在系统盘中&#…

LeetCode题练习与总结:克隆图--133

一、题目描述 给你无向 连通 图中一个节点的引用&#xff0c;请你返回该图的 深拷贝&#xff08;克隆&#xff09;。 图中的每个节点都包含它的值 val&#xff08;int&#xff09; 和其邻居的列表&#xff08;list[Node]&#xff09;。 class Node {public int val;public L…

阐述一下Golang中defer的原理

基本用法 在Go语言中&#xff0c;defer关键字用于在函数返回前执行一段代码或调用一个清理函数。这对于处理文件关闭、解锁或者返回一些资源到资源池等操作非常有用。 其基本用法如下所示&#xff1a; package mainimport "fmt"func main() {example() }func exam…

如何使用Rekono结合多种工具自动完成渗透测试

关于Rekono Rekono是一款功能强大的自动化渗透测试工具&#xff0c;该工具能够结合其他多种网络安全工具并以自动化的形式完成整个渗透测试过程。在工具运行的过程中所收集到的数据将通过电子邮件或Telegram同时发送给用户&#xff0c;如果需要更加高级的漏洞管理功能&#xf…

浏览器(Browser):轻量级浏览器,高效浏览新体验

在可的哥桌面&#xff08;Codigger Desktop&#xff09;&#xff0c;我们始终秉持创新精神&#xff0c;致力于提供卓越的用户体验。如今&#xff0c;我们激动地宣布一项全新功能的发布——轻量级浏览器Browser。这款浏览器的推出&#xff0c;正是我们对用户体验追求的再次体现&…

设施布置之车间布局优化SLP分析

一 物流分析&#xff08;Flow Analysis&#xff09; 的基本方法 1、当物料移动是工艺过程的主要部分时&#xff0c;物流分析就是工厂布置设计的核心工作&#xff0c;也是物料搬运分析的开始。 2、零部件物流是该部件在工厂内移动时所走过的路线&#xff0c; 物流分析不仅要考虑…

智慧水务十大预测

智慧水务是指利用现代信息技术&#xff0c;如物联网(IoT)、大数据、云计算、人工智能(AI)等&#xff0c;对水务系统进行智能化改造和管理&#xff0c;以提高水资源的利用效率、保障供水安全、降低运营成本和环境影响。以下是对智慧水务未来发展的十大预测&#xff1a; 数字化转…

免费ai写作?这三款软件是你的好帮手!

在信息爆炸的今天&#xff0c;自媒体已成为越来越多人展现自我、分享知识的平台。然而&#xff0c;对于许多自媒体创作者来说&#xff0c;写作过程中的灵感枯竭、文笔不畅等问题常常困扰着他们。幸运的是&#xff0c;随着人工智能技术的飞速发展&#xff0c;免费AI写作软件应运…

小程序onLoad 和 onShow

onLoad 和 onShow 是小程序页面的生命周期函数&#xff0c;它们在不同的时机触发&#xff0c;具有不同的用途和执行顺序 1.onLoad: &#xff08;1&#xff09;onLoad 在页面加载时触发&#xff0c;仅执行一次。 &#xff08;2&#xff09;用于页面的初始化操作&#xff0c;例如…

2024全国高校名单发布,电子版下载!

今天&#xff0c;教育部网站发布了《全国高等学校名单》。截至2024年6月20日&#xff0c;全国高等学校共计3117所&#xff0c;其中&#xff1a;普通高等学校2868所&#xff0c;含本科学校1308所、高职&#xff08;专科&#xff09;学校1560所&#xff1b;成人高等学校249所。本…

java试卷练习1

试卷练习1 一、单项选择题。 在每小题列出的四个备选项中只有一个选项是符合目的要求的&#xff0c;请将其代码填写在 题后的括号内。 1、Java 语言中&#xff0c;byte 类型占用的二进制位数是&#xff1a;&#xff08;D&#xff09; A、1 位 B、2 位 C、4 位 D、8 位 解释…

任务4.8.3 利用SparkSQL统计每日新增用户

实战概述&#xff1a;利用SparkSQL统计每日新增用户 任务背景 在大数据时代&#xff0c;快速准确地统计每日新增用户是数据分析和业务决策的重要部分。本任务旨在使用Apache SparkSQL处理用户访问历史数据&#xff0c;以统计每日新增用户数量。 任务目标 处理用户访问历史数…

简单了解雪花算法

雪花算法是什么 不多解释。看一看 具体是怎么 生产 唯一ID 的。 ID 由多个数据组合拼接成64位&#xff0c;分别是 时间戳 服务器节点ID 序列号&#xff0c;每个数据项占的位数不固定&#xff0c;可以根据实际需求设置。首位 1 个二进制位 是 符号位。 public long allocate(l…

数字样机:飞行器状态控制系统仿真

引言&#xff1a;数字样机起源于20世纪90年代&#xff0c;是一种用数字化模型代替实际物理样机进行仿真分析的技术。 传统的飞行器研发流程往往遵循一套特定的循环结构&#xff1a;在设计初期&#xff0c;工程人员需要对飞行器提供一个综合的设计思路&#xff08;初期蓝图&…