当前位置:网站首页>QT中线程调用GUI主线程控件的问题
QT中线程调用GUI主线程控件的问题
2022-08-03 08:09:00 【天天进步2015】
之前写过一篇文章,是传界面指针到线程中去,从而在线程中操作主界面中控件。
今天发现,这种方法是极其错误的,文章我已经删掉,希望没有误人子弟。
前面转的两篇文章中对于为什么不能在线程中操纵界面控件指针有了很好的解释。下面在做下解释:
尽管QObject是可重入的,但GUI类,特别是QWidget与它的所有子类都是不可重入的。它们仅用于主线程。正如前面提到过 的,QCoreApplication:: exec() 也必须从那个线程中被调用。实践上,不会在别的线程中使用GUI类,它们工作在主线程上,把一些耗时的操作放入独立的工作线程中,当工作线程运行完成,把 结果在主线程所拥有的屏幕上显示。
下面的几个帖子是我在解决问题的过程中看到的几个很有帮助的帖子,一并贴下:
http://www.qtcn.org/bbs/read.php?tid=12121&keyword=%CF%DF%B3%CC
http://www.qtcn.org/bbs/read.php?tid=13508&keyword=%CF%DF%B3%CC
http://www.qtcn.org/bbs/read.php?tid=18586&keyword=%CF%DF%B3%CC
下面截取里面比较有价值的回复:
线程里面直接操作界面元素是肯定不行的,即使不总是出现错误,偶尔也会出莫明其妙,在 文档里面已经有说了,你再找找看,
你需要使用比如postEvent之类的异步处理方式.
至于进程中的那个错误,你设断点调试下吧.
不可以在非界面的进程中直接操作界面的
Qt的文档有这么说
据说4之前版本可以,没有试过
signal/slot目前有三种调用方式
1.DirectConnection
和以前一样,在emit处直接invoke你的slot 函数,一般情况是sender,receiver在同一线程
2.QueuedConnection
将 发送Event给你的receiver所在的线程
postEvent(QEvent::MetaCall,...)
slot 函数会在receiver所在的线程的event loop中进行处理,一般情况是sender,receiver不在同一线程
3.BlockingQueuedConnection
调 用sendEvent(QEvent::MetaCall,...),在receiver所在的线程处 理完成后才会返回;只能当sender,receiver不在同一线程时才可以
好了,上面的是说为什么不行的,那如果非要在非GUI线程里操作GUI线程里的控件,该怎么做呢?
答案是使用signal/slot。
在线程里的run()里定期emit signal,GUI线程里建立连接,写槽函数,注意connect的第五个参数应该使用Queued方式。
下面列个从QT论坛上找的例子,专门用来解释这个问题的
thread.h:
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
class Thread : public QThread
{
Q_OBJECT
public:
Thread();
signals:
void sendString(QString);
protected:
void run();
};
#endif // THREAD_H
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
class Thread;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private:
QTextEdit *m_textEdit;
Thread *m_thread;
};
#endif // WIDGET_H
thread.cpp:
#include "thread.h"
#include <QtCore/QTime>
Thread::Thread()
{
}
void Thread::run()
{
while(1)
{
emit sendString(QTime::currentTime().toString("hh:mm:ss.zzz"));
msleep(200);
}
}
widget.h:
#include <QtGui/QHBoxLayout>
#include "widget.h"
#include "thread.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_textEdit = new QTextEdit(this);
QHBoxLayout * layout = new QHBoxLayout(this);
layout->addWidget(m_textEdit);
setLayout(layout);
m_thread = new Thread();
connect(m_thread, SIGNAL(sendString(QString)), m_textEdit, SLOT(append(QString)));
m_thread->start();
}
Widget::~Widget()
{
}
main.cpp:
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
这个例子就演示了如何在非GUI线程里调GUI线程里的控件。
边栏推荐
猜你喜欢
随机推荐
mysql系统变量与状态变量
volta管理node版本
WordPress主题-B2美化通用子主题商业运营版
Karatsuba大数乘法的Verilog实现
编程踩坑合集
Fortify白盒神器20.1.1下载及安装(非百度网盘)
FusionAccess软件架构、FusionAccess必须配置的四个组件、桌面发放流程、虚拟机组类型、桌面组类型
pyspark df secondary sorting
解决GANs训练中模式崩塌/训练崩溃的十五个方法
NFT到底有哪些实际用途?
frp:开源内网穿透工具
【收获合辑】k-NN与检索任务的异同+jupyter转pdf
[Kaggle combat] Prediction of the number of survivors of the Titanic (from zero to submission to Kaggle to model saving and restoration)
HCIP实验(06)
Mysql如何对两张表的相同字段,同时查询两张数据表
Pop Harmony Basics Big Notes
word之个人设置
Guava的Service
swiper分类菜单双层效果demo(整理)
ArcEngine (5) use the ICommand interface to achieve zoom in and zoom out