Qt多线程[QMessageBox]Cannot set parent, new parent is in a different thread以及connect注意事项

多线程不允许操作UI!!!


场景:

在子线程的工作函数中,我想将错误以弹窗的形式显示出来,并qDebug一起打印出来,于是封装了一个Tools类,信号从Tools::msg( )中发出来,由Mainwindow接收,msg( )在子线程中调用。


问题:

1. 关于在多线程中调用QMessageBox弹窗的问题
2. 涉及多线程的connect对象问题
3. 涉及多线程的connect lamda表达式的注意事项


伪代码及分析:

//Tools类
class Tools
{
	/**省略多余部分**/
	public msg(const QString &str){
		emit sigShowMsg(str);
		qDebug(str);
	}
}

//在Mainwindow中连接信号与槽函数
Tools tool;
connect(&tool, &Tools::sigShowMsg, [=](const QString &str){
		QMessageBox::critical(this, "Error", str);
});

//在子线程中调用msg()函数,显示错误信息弹窗
Tools tool;
bool ret = work();
if(!ret){
	tool.msg(str);
}

这时发现,当msg( )中qDebug信息被打印时,对应的错误弹窗并没有出现。也就是说信号发出,槽函数未执行。

首先排除了信号与槽在对象实例化之前进行连接而导致的槽函数不执行,难道是槽函数有问题?
我突然想到,Mainwindow中的tool对象和子线程中的tool对象并不是同一个,只是恰好名字相同,而在connect中被声明信号来源的tool就是在Mainwindow中从来没有发送信号的tool对象,而不是在子线程中调用错误弹窗提示msg( )的tool对象!(验证截图在文章最后)

于是乎,我将Tools类改写成饿汉式的单例模式:

connect(Tools::getInstance(), &Tools::sigShowMsg, [=](const QString &str){
		QMessageBox::critical(this, "Error", str);
});

OK,弹窗触发了,但是又出现了新问题:
此时触发子线程中的错误弹窗将会出现QObject::setParent: Cannot set parent, new parent is in a different thread的输出信息

百度得知,在子线程操纵UI便会有次报错。可是在connect中,信号的来源是Tools,槽函数在主线程调用,为什么还会有这个问题呢?

罪魁祸首 ---> lamda表达式
看看下面两种写法有啥区别?

//槽函数在this(即MainWindow)调用
connect(Tools::getInstance(), &Tools::sigErrMsg, this, [=](const QString &str){
        QMessageBox::critical(NULL, "Error", str);
});

//槽函数在信号来源处(子线程)调用
connect(Tools::getInstance(), &Tools::sigErrMsg, [=](const QString &str){
        QMessageBox::critical(NULL, "Error", str);
});

在connect中指明了槽函数在this中执行后,我第一次觉得这个带着醒目红色叉叉的error弹窗是那么的顺眼!
所以在使用lamda表达式时,一定要注意槽函数的作用域!


最后献上验证截图,在lamda槽函数中打印了当前线程ID:

//主线程
connect(Tools::getInstance(), &Tools::sigLogInfo, this, [=](){
        qDebug() << QThread::currentThreadId();
});

//子线程
connect(Tools::getInstance(), &Tools::sigLogInfo, [=](){
		qDebug() << QThread::currentThreadId();
});

在这里插入图片描述
在这里插入图片描述

  • 12
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Qt中,QMessageBox是一个弹窗对话框类,通常在主线程中使用。如果在子线程中尝试实例化或使用QMessageBox,会导致程序报错。这是因为Qt中的UI操作必须在主线程中执行,这是Qt的设计原则之一。 要在子线程中使用QMessageBox,可以通过信号与槽机制来实现。具体步骤如下: 1. 在子线程中创建一个信号,用于发出弹窗的请求信号。 2. 在主线程中实例化QMessageBox类,并将其连接到子线程发出的信号的槽函数中。 3. 当子线程发出弹窗请求信号时,主线程中的槽函数会被调用,这样就可以在主线程中显示QMessageBox弹窗。 这种方式可以避免在子线程中直接实例化QMessageBox导致程序卡退的问题。通过信号与槽机制,可以确保UI操作在主线程中执行,保证程序的正常运行。引用<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [QT-——QTimer QMessageBox 线程 主线程 UI之间的联系](https://blog.csdn.net/qq_41077484/article/details/124826330)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [PyQt5在另一个线程使用QMessageBox弹窗](https://blog.csdn.net/Cecile0828/article/details/130803832)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Qt多线程[QMessageBox]Cannot set parent, new parent is in a different thread以及connect注意事项](https://blog.csdn.net/weixin_48424192/article/details/123379105)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值