让QTimer 跑在其余线程. 通常写法以下. oop
1. 在main thread中为worker thread指定定时器. post
QThread* thread = new QThread(this); thread->start(); QTimer *timer = new QTimer(0); timer->setInterval(100); timer->moveToThread(thread); connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection); connect(thread, SIGNAL(started()), timer,SLOT(start()));
须要注意几个地方.ui
1) QTimer 不能指定parent, 不然 会出现警告 " QObject::moveToThread: Cannot move objects with a parent"this
由于moveToThread 没法移动有parent的object. spa
2) QTimer 须要用moveToThread 来改变线程相关性. 这样emit signal的时候才会在worker线程. 线程
3) connect timeout时, 须要附加参数Qt::DirectConnection, blog
根据Qt的文档中事件
Qt::AutoConnection 0 (default) If the signal is emitted from a different thread than the receiving object, the signal is queued, behaving as Qt::QueuedConnection. Otherwise, the slot is invoked directly, behaving as Qt::DirectConnection. The type of connection is determined when the signal is emitted. Qt::DirectConnection 1 The slot is invoked immediately, when the signal is emitted. Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
connect默认参数为AutoConnection, 因此当slot的object是main线程时, 会自动post 事件到main线程. 指定DirectConnection 才会直接调用slot. 即在worker线程中处理. 文档
4) 若是直接 timer->start(); 的话, 会有警告: QObject::startTimer: Timers can only be used with threads started with QThreadget
timer 只能在同一个线程中建立和启动. (使用moveToThread 能够修改). 这里写"同一个线程" 彷佛描述不太准确. 但大概就是这个意思.
connect(thread, SIGNAL(started()), timer,SLOT(start()));
因此须要这样启动.
其实也能够这样取巧:
QThread* thread = new QThread(this); thread->start(); QTimer *timer = new QTimer(0); timer->setInterval(100); connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection); //connect(thread, SIGNAL(started()), timer,SLOT(start())); timer->start(); timer->moveToThread(thread);
5) 由于timer 没有指定parent, 因此不会自动销毁.
2. 在worker线程中启动QTimer.
class Worker :public QThread { Q_OBJECT public: Worker(MyClass *parent); virtual ~Worker(){} void run(); MyClass *timerReceiver; }; Worker::Worker(MyClass *parent) : QThread(parent) { timerReceiver = parent; } void Worker::run() { QTimer *timer = new QTimer(this); timer->setInterval(100); connect(timer, SIGNAL(timeout()), timerReceiver, SLOT(onTimeout()), Qt::DirectConnection); timer->start(); exec(); return; }
MyClass 是一个UI窗口. 相似以下.
class MyClass : public QMainWindow { Q_OBJECT public: MyClass(QWidget *parent = 0); ~MyClass(); public slots: void onTimeout(); private: Ui::MyClassClass ui; }; MyClass::MyClass(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); Worker *thread = new Worker(this); //QThread* thread = new QThread(this); thread->start(); } MyClass::~MyClass() { } void MyClass::onTimeout() { }
so. 能够看到. 若是timer是在worker 线程中建立的话. 即不须要moveToThread来修改线程相关性.
timer->start()也能够直接调用.
但仍然须要指定 Qt::DirectConnection. 由于timerReceiver 是在main thread中.
若是timerReceiver 也在worker线程中建立, 则不须要指定 Qt::DirectConnection.
void Worker::run() { TestObject *timerReceiver = new TestObject(this); QTimer *timer = new QTimer(this); timer->setInterval(100); connect(timer, SIGNAL(timeout()), timerReceiver, SLOT(onTimeout())); timer->start(); exec(); return; }
class TestObject : public QObject { Q_OBJECT public: TestObject(QObject *parent) : QObject(parent) {} public slots : void onTimeout(){} };
看起来和平时用的如出一辙. →_→