Qt文档说明信号和插槽可以是 direct
, queued
和 auto
.
它还声明,如果拥有插槽的对象'生命'在与拥有信号的对象不同的线程中,则发出此类信号就像发布消息一样 - 信号发出将立即返回,并且将在目标线程的事件循环中调用slot方法 .
遗憾的是,文档没有指定“生命”代表并且没有可用的示例 . 我试过以下代码:
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();
}
输出是:
thread 2 started
thread 1 started
MySlot()
从未被召唤:( . 我做错了什么?
2 回答
你的代码有很多问题:
如Evan所说,emit关键字缺失
所有对象都存在于主线程中,只有run方法中的代码存在于其他线程中,这意味着将在主线程中调用MySlot槽并且我想要你想要的是什么
你的插槽将永远不会被调用,因为主事件循环永远不会被启动:你的两次调用wait()只会在很长一段时间后超时(并且你认为这也是你想要的,无论如何它们真的没有用在你的代码中 .
这段代码最有可能工作(虽然我没有测试过),我认为它可以做你想做的事情:
现在MyObject将存在于thread2中(感谢moveToThread) .
MySignal应该从thread1发送(我以为我不确定那个,它可能是从主线程发送的,它并不重要) .
thread1中不需要事件循环,因为发出信号不需要事件循环 . thread2中需要一个事件循环(由exec()加载)以接收信号 .
MySlot将在thread2中调用 .
不要为Qt 4.4继承QThread
虽然Aiua的答案很好,但我想指出QThread和Qt 4.6或4.7的一些问题 .
本文总结了这一点:http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
缺乏关于Qt的文档
不幸的是,问题源于缺乏文档更新 . 在Qt 4.4之前,QThread没有默认的run()实现,这意味着你必须继承QThread才能使用它 .
如果您使用的是Qt 4.6或4.7,那么您几乎肯定不应该继承QThread .
使用moveToThread
获取插槽在工作线程中执行的关键是使用moveToThread方法,如Aiua指出的那样 .