Qt 中使用 moveToThread 多线程踩坑记录

embedded/2025/1/15 1:28:03/

关于QT Widget 其它文章请点击这里:     QT Widget


今天在使用 Qt 的 moveToThread 实现多线程时,遇到了两个常见的坑,在这里记录一下,供自己和大家参考。

一、继承于QWidget 的控件不能在子线程中运行

Qt 的规定是:所有 UI 操作必须在主线程中执行。因此,QWidget 及其子类只能在主线程中创建和更新,不能移动到子线程中,也不能在子线程中直接操作 UI。

错误示例:

以下代码试图将继承自 QWidget 的 CompWord 移动到子线程:

class CompWorkBase : public QWidget
...
class CompWord :  public CompWorkBase
...
CompWord *_cmp_word = new CompWord(ui->wgt_Work);
QThread* _workerThread = new QThread();
_cmp_word->moveToThread(_workerThread);

运行后报错:

QObject::moveToThread: Cannot move objects with a parent

这是因为 CompWord 继承自 QWidget,而 QWidget 的实例必须在主线程中运行,因此不能将 _cmp_word 移动到子线程。

二、 QAxObject(以及 COM 组件)不能在子线程中实例化

在将 CompWord 的界面与逻辑分离后,又遇到了第二个坑:QAxObject 不能在子线程中实例化。这是由于 COM 的限制,默认情况下,COM 对象的创建和调用必须在主线程中进行。

原因:

COM 对象(如 Microsoft Word 的接口)基于单线程单元(STA,Single-Threaded Apartment)模型。STA 模型要求 COM 对象的创建和使用必须在同一个线程中进行,而该线程通常是 GUI 主线程。

如果在子线程中实例化 QAxObject,会导致 QAxBase::setControl 方法失败。

错误示例:

	...ReportWorker * _reportWorker = new ReportWorker();QThread*  _threadWorker = new QThread();_reportWorker->moveToThread(_threadWorker);// 连接信号槽connect(_threadWorker, &QThread::started, _reportWorker, &ReportWorker::reportInit);     // 线程初始化_threadWorker->start();

子线程的初始化逻辑如下:

void ReportWorker::reportInit() {wordApp = std::make_unique<QAxObject>("Word.Application");
}

运行后报错:

QAxBase::setControl: requested control Word.Application could not be instantiated
Failed to initialize Word.Application.

这说明 COM 对象(如 QAxObject)的实例化必须在主线程完成。


关于QT Widget 其它文章请点击这里:     QT Widget


http://www.ppmy.cn/embedded/153986.html

相关文章

双模充电桩发展前景:解锁新能源汽车未来的金钥匙,市场潜力无限

随着全球能源转型的浪潮席卷而来&#xff0c;新能源汽车行业正以前所未有的速度蓬勃发展&#xff0c;而作为其坚实后盾的充电基础设施&#xff0c;特别是双模充电桩&#xff0c;正逐渐成为推动这一变革的关键力量。本文将从多维度深入剖析双模充电桩的市场现状、显著优势、驱动…

go中协程的生命周期

在 Go 中&#xff0c;协程&#xff08;goroutine&#xff09;的生命周期大致可以分为以下几个阶段&#xff1a; 1. 创建阶段 协程的创建通常是通过 go 关键字来启动的。例如&#xff1a; go func() {// 协程执行的代码 }()当执行 go func() 时&#xff0c;Go 会在后台启动一…

《零基础Go语言算法实战》【题目 2-18】获取结构体中字段的 tag 值

《零基础Go语言算法实战》 【题目 2-18】获取结构体中字段的 tag 值 在 Go 语言中&#xff0c;使用 json 包时&#xff0c;在结构体中的字段前会加上 tag&#xff0c;有没有什么办法可以获 取到这个 tag 的内容呢&#xff1f;举例说明。 【解答】 tag 信息可以通过 reflec…

MySQL 与 Redis 的数据一致性问题

读数据的逻辑基本一致问题1: 一致性有哪些?MySQL 与 Redis 的数据一致性方案有哪些?先写MySQL还是先写Redis?缓存数据是更新还是清除?强一致还是最终一致?问题: 如果mysql写成功了,但是Redis写(删除)失败了怎么办?重试机制的幂等问题如何解决? 方案1: 先更新 MySQL 再清…

2025年01月11日Github流行趋势

项目名称&#xff1a;xiaozhi-esp32 项目地址url&#xff1a;https://github.com/78/xiaozhi-esp32项目语言&#xff1a;C历史star数&#xff1a;2433今日star数&#xff1a;321项目维护者&#xff1a;78, MakerM0, whble, nooodles2023, Kevincoooool项目简介&#xff1a;构建…

Leetcode - 147双周赛

目录 一、3407. 子字符串匹配模式二、3408. 设计任务管理器三、3409. 最长相邻绝对差递减子序列四、3410. 删除所有值为某个元素后的最大子数组和 一、3407. 子字符串匹配模式 题目链接 字符串匹配问题&#xff0c;把字符串 p 分成两段 、&#xff0c;i 是 ’ * ’ 的下标&am…

React 进阶之路:深入详解事件绑定的多样方式与区别,促使更加容易理解

React 中的事件绑定是处理用户交互的一个重要方面。React 的事件系统与传统的 DOM 事件系统有所不同&#xff0c;它在设计时考虑了性能、可维护性和易用性&#xff0c;因此 React 提供了多种方式来绑定事件处理程序。理解这些绑定方式及其区别&#xff0c;有助于在实际项目中做…

open3d+opencv实现矩形框裁剪点云操作(C++)

&#x1f451;主页&#xff1a;吾名招财 &#x1f453;简介&#xff1a;工科学硕&#xff0c;研究方向机器视觉&#xff0c;爱好较广泛… ​&#x1f4ab;签名&#xff1a;面朝大海&#xff0c;春暖花开&#xff01; open3dopencv实现矩形框裁剪点云操作&#xff08;C&#xff…