[英]How to emit cross-thread signal in Qt?
Qt documentation states that signals and slots can be direct
, queued
and auto
. Qt 文档指出信号和槽可以是direct
、 queued
和auto
。
It also stated that if object that owns slot 'lives' in a thread different from object that owns signal, emitting such signal will be like posting message - signal emit will return instantly and slot method will be called in target thread's event loop.它还指出,如果拥有插槽的对象“生活”在与拥有信号的对象不同的线程中,则发出此类信号就像发布消息一样 - 信号发射将立即返回,并且将在目标线程的事件循环中调用插槽方法。
Unfortunately, documentation do not specify that 'lives' stands for and no examples is available.不幸的是,文档没有说明“生活”代表什么,也没有可用的例子。 I have tried the following code:我尝试了以下代码:
main.h:
class CThread1 : public QThread
{
Q_OBJECT
public:
void run( void )
{
msleep( 200 );
std::cout << "thread 1 started" << std::endl;
MySignal();
exec();
}
signals:
void MySignal( void );
};
class CThread2 : public QThread
{
Q_OBJECT
public:
void run( void )
{
std::cout << "thread 2 started" << std::endl;
exec();
}
public slots:
void MySlot( void )
{
std::cout << "slot called" << std::endl;
}
};
main.cpp:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
CThread1 oThread1;
CThread2 oThread2;
QObject::connect( & oThread1, SIGNAL( MySignal() ),
& oThread2, SLOT( MySlot() ) );
oThread1.start();
oThread2.start();
oThread1.wait();
oThread2.wait();
return a.exec();
}
Output is:输出是:
thread 2 started
thread 1 started
MySlot()
is never called :(. What I'm doing wrong? MySlot()
永远不会被调用 :(。我做错了什么?
There are quite a few problems with your code :您的代码有很多问题:
This code would most likely work (though I have not tested it) and I think it does what you want it to do :这段代码很可能会工作(虽然我没有测试过),我认为它可以做你想要它做的事情:
class MyObject : public QObject
{
Q_OBJECT
public slots:
void MySlot( void )
{
std::cout << "slot called" << std::endl;
}
};
class CThread1 : public QThread
{
Q_OBJECT
public:
void run( void )
{
std::cout << "thread 1 started" << std::endl;
int i = 0;
while(1)
{
msleep( 200 );
i++;
if(i==1000)
emit MySignal();
}
}
signals:
void MySignal( void );
};
class CThread2 : public QThread
{
Q_OBJECT
public:
void run( void )
{
std::cout << "thread 2 started" << std::endl;
exec();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
CThread1 oThread1;
CThread2 oThread2;
MyObject myObject;
QObject::connect( & oThread1, SIGNAL( MySignal() ),
& myObject, SLOT( MySlot() ) );
oThread2.start();
myObject.moveToThread(&oThread2)
oThread1.start();
return a.exec();
}
Now MyObject will live in thread2 (thanks to moveToThread).现在 MyObject 将存在于 thread2 中(感谢 moveToThread)。
MySignal should be sent from thread1 (thought I'm not sure on that one, it might be sent from main thread, it doesn't really matter). MySignal 应该从 thread1 发送(我不确定那个,它可能是从主线程发送的,这并不重要)。
No event loop is needed in thread1 since emitting a signal doesn't need an event loop. thread1 中不需要事件循环,因为发出信号不需要事件循环。 An event loop is needed in thread2 (lanched by exec()) to receive the signal.在线程 2(由 exec() 启动)中需要一个事件循环来接收信号。
MySlot will be called in thread2. MySlot 将在 thread2 中调用。
While Aiua's answer is good, I want to point out some issues with QThread and Qt 4.6 or 4.7.虽然 Aiua 的回答很好,但我想指出 QThread 和 Qt 4.6 或 4.7 的一些问题。
This article sums it up: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/本文总结: http : //blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
Unfortunately the problem stems from a lack of updates to documentation.不幸的是,问题源于缺乏对文档的更新。 Prior to Qt 4.4 QThread had no default run() implementation, which meant that you had to subclass QThread in order to use it.在 Qt 4.4 之前,QThread 没有默认的 run() 实现,这意味着您必须继承 QThread 才能使用它。
If you're using Qt 4.6 or 4.7 then you almost certainly should not subclass QThread.如果你正在使用Qt 4.6或者4.7,那么你几乎肯定不应该继承的QThread。
The key to getting slots to execute in a worker thread is to use the moveToThread method as Aiua pointed out.正如 Aiua 指出的那样,让插槽在工作线程中执行的关键是使用 moveToThread 方法。
you should emit the signal to start your thread function like你应该发出信号来启动你的线程函数,比如
emit operateCut(examId,examName_examTemplate[examName].studentIdRec,examName_examTemplate[examName].choiceRecA,examName_examTemplate[examName].choiceRecB,examName_examTemplate[examName].objectRecA,examName_examTemplate[examName].objectRecB);
you can add more than one argument in this signal您可以在此信号中添加多个参数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.