Запуск QTimer В QThread
Я пытаюсь запустить QTimer в определенном потоке. Однако таймер, похоже, не выполняется, и ничего не распечатывается. Это как-то связано с таймером, шлиц или резьба?
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";
}
6 ответов
как я прокомментировал (дополнительная информация по ссылке), вы делаете это неправильно:
- вы смешиваете объект, содержащий данные потока, с другим объектом (ответственным за
doIt()
). Они должны быть разделены. - нет необходимости в подклассе
QThread
в вашем случае. Хуже того, вы переопределяетеrun
метод без учета того, что он делает.
этой части кода должно быть достаточно
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();
Сейчас (Qt версия >= 4.7) по умолчанию QThread
запускает цикл событий в его run()
метод. Чтобы запустить внутри потока, вам просто нужно переместить объект. читать Доку...
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();
на QTimer
работает только в потоке, который имеет цикла обработки событий.
http://qt-project.org/doc/qt-4.8/QTimer.html
в многопоточных приложениях вы можете использовать QTimer в любом потоке, который имеет цикл событий. Чтобы запустить цикл событий из потока без GUI, используйте QThread:: exec(). Qt использует сродство потоков таймера, чтобы определить, какой поток будет излучать сигнал timeout (). Из-за этого вы должны запустить и остановить таймер в его потоке; это не можно запустить таймер из другого потока.
вы можете использовать сигнал испускания и запустить таймер внутри функции испускаемого слота
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);
}
вам нужен цикл обработки событий для таймеров. Вот как я решил ту же проблему с моим кодом:
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";
}
вот соответствующая часть документации, которую ни один из других плакатов не упомянул:
int QCoreApplication:: exec ()
входит в основной цикл событий и ожидает вызова exit (). Возвращается значение, которое было установлено в exit () (которое равно 0, если exit () вызывается через покидать.))( Это надо назвать функция запуска события обращение. Основной цикл событий получает события из оконной системы и отправляет их в виджеты приложений. Сделать ваше приложение выполняет простаивающую обработку (т. е. выполнение специальной функции всякий раз, когда нет ожидающих событий), используйте QTimer с таймаутом 0. Более продвинутые схемы обработки холостого хода могут быть достигнуты с использованием processEvents().
Я создал пример, который вызывает таймер в лямбда-функции:
#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();
}