可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to start a QTimer in a specific thread. However, the timer does not seem to execute and nothing is printing out. Is it something to do with the timer, the slot or the thread?
main.cpp
#include "MyThread.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
MyThread t;
t.start();
while(1);
}
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QTimer>
#include <QThread>
#include <iostream>
class MyThread : public QThread {
Q_OBJECT
public:
MyThread();
public slots:
void doIt();
protected:
void run();
};
#endif /* MYTHREAD_H */
MyThread.cpp
#include "MyThread.h"
using namespace std;
MyThread::MyThread() {
moveToThread(this);
}
void MyThread::run() {
QTimer* timer = new QTimer(this);
timer->setInterval(1);
timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt()));
timer->start();
}
void MyThread::doIt(){
cout << "it works";
}
回答1:
As I commented (further information in the link) you are doing it wrong :
- You are mixing the object holding thread data with another object (responsible of
doIt()
). They should be separated.
- There is no need to subclass
QThread
in your case. Worse, you are overriding the run
method without any consideration of what it was doing.
This portion of code should be enough
QThread* somethread = new QThread(this);
QTimer* timer = new QTimer(0); //parent must be null
timer->setInterval(1);
timer->moveToThread(somethread);
//connect what you want
somethread->start();
Now (Qt version >= 4.7) by default QThread
starts a event loop in his run()
method. In order to run inside a thread, you just need to move the object. Read the doc...
回答2:
m_thread = new QThread(this);
QTimer* timer = new QTimer(0); // _not_ this!
timer->setInterval(1);
timer->moveToThread(m_thread);
// Use a direct connection to whoever does the work in order
// to make sure that doIt() is called from m_thread.
worker->connect(timer, SIGNAL(timeout()), SLOT(doIt()), Qt::DirectConnection);
// Make sure the timer gets started from m_thread.
timer->connect(m_thread, SIGNAL(started()), SLOT(start()));
m_thread->start();
回答3:
A QTimer
only works in a thread that has an event loop.
http://qt-project.org/doc/qt-4.8/QTimer.html
In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.
回答4:
You can use the emit signal and start the timer inside the emitted slot function
main.cpp
#include "MyThread.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
MyThread t;
t.start();
while(1);
}
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QTimer>
#include <QThread>
#include <iostream>
class MyThread : public QThread {
Q_OBJECT
public:
MyThread();
QTimer *mTimer;
signals:
start_timer();
public slots:
void doIt();
void slot_timer_start();
protected:
void run();
};
#endif /* MYTHREAD_H */
MyThread.cpp
#include "MyThread.h"
using namespace std;
MyThread::MyThread() {
mTimer = new QTimer(this);
connect(this,SIGNAL(start_timer()),this, SLOT(slot_timer_start()));
connect(mTimer,SIGNAL(timeout()),this,SLOT(doIt()));
}
void MyThread::run() {
emit(start_timer());
exec();
}
void MyThread::doIt(){
cout << "it works";
}
void MyThread::slot_timer_start(){
mTimer->start(1000);
}
回答5:
You need an event loop to have timers. Here's how I solved the same problem with my code:
MyThread::MyThread() {
}
void MyThread::run() {
QTimer* timer = new QTimer(this);
timer->setInterval(1);
timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt()));
timer->start();
/* Here: */
exec(); // Starts Qt event loop and stays there
// Which means you can't have a while(true) loop inside doIt()
// which instead will get called every 1 ms by your init code above.
}
void MyThread::doIt(){
cout << "it works";
}
Here's the relevant piece of the documentation that none of the other posters mentioned:
int QCoreApplication::exec()
Enters the main event loop and waits until exit() is called. Returns
the value that was set to exit() (which is 0 if exit() is called via
quit()). It is necessary to call this function to start event
handling. The main event loop receives events from the window system
and dispatches these to the application widgets. To make your
application perform idle processing (i.e. executing a special function
whenever there are no pending events), use a QTimer with 0 timeout.
More advanced idle processing schemes can be achieved using
processEvents().
回答6:
I have created an example that calls the timer within a lambda function:
#include <QCoreApplication>
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QDebug>
#include <memory>
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
QThread* thread = new QThread(&app);
QObject::connect(thread, &QThread::started, [=]()
{
qInfo() << "Thread started";
QTimer* timer1 = new QTimer(thread);
timer1->setInterval(100);
QObject::connect(timer1, &QTimer::timeout, [=]()
{
qInfo() << "Timer1 " << QThread::currentThreadId();
});
timer1->start();
});
thread->start();
QTimer timer2(&app);
QObject::connect(&timer2, &QTimer::timeout, [=]()
{
qInfo() << "Timer2 " << QThread::currentThreadId();
});
timer2.setInterval(100);
timer2.start();
return app.exec();
}