Démarrage De QTimer Dans Un QThread
j'essaie de démarrer un QTimer dans un thread spécifique. Cependant, la minuterie ne semble pas fonctionner et rien n'est imprimé. Est-ce que ça a quelque chose à voir avec la minuterie, la fente ou le fil?
main.rpc
#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.rpc
#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 réponses
Comme je l'ai commenté (plus d'informations dans le lien) vous faites du mal :
- vous mélangez l'objet contenant les données du thread avec un autre objet (responsable de
doIt()
). Ils doivent être séparés. - il n'y a pas besoin de sous-classe
QThread
dans votre cas. Pire, vous écrasez larun
méthode sans aucune considération de ce qu'elle faisait.
cette portion de code devrait suffire
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();
maintenant (version Qt >= 4.7) par défaut QThread
démarre une boucle d'événement dans sa run()
méthode. Afin de s'exécuter dans un thread, il vous suffit de déplacer l'objet. lire le doc...
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
ne fonctionne que dans un thread qui a une boucle d'événements.
http://qt-project.org/doc/qt-4.8/QTimer.html
dans les applications multithreaded, vous pouvez utiliser QTimer dans n'importe quel thread qui a une boucle d'événement. Pour lancer une boucle d'événement à partir d'un thread non-GUI, utilisez QThread::exec(). Qt utilise l'affinité du thread pour déterminer quel thread émettra le signal timeout (). Pour cette raison, vous devez démarrer et arrêter le minuteur dans son fil; il n'est pas possible de démarrer une minuterie à partir d'un autre thread.
vous pouvez utiliser le signal d'émission et démarrer la minuterie à l'intérieur de la fonction de fente émise
main.rpc
#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.rpc
#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);
}
Vous avez besoin d'une boucle pour avoir compteurs. Voici comment j'ai résolu le même problème avec mon 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";
}
Voici la question de la documentation qu'aucun des autres affiches mentionné:
int QCoreApplication:: exec ()
entre dans la boucle d'événement principal et attend que exit() soit appelé. Retourner la valeur qui a été définie pour la sortie() (qui est 0 si exit() est appelée par quitter.))( Il est nécessaire d'appeler cette fonction pour commencer événement manutention. La boucle principale reçoit les événements de la fenêtre système et envoie ceci aux widgets d'application. Pour faire de votre application effectuer un traitement inactif (c.-à-d. exécuter une fonction spéciale chaque fois qu'il n'y a pas d'événements en cours), utilisez un QTimer avec 0 timeout. Des schémas de traitement plus avancés peuvent être obtenus en utilisant processEvents ().
j'ai créé un exemple qui appelle le timer dans une fonction lambda:
#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();
}