QThread and QTimer

c++, qt, qthread, qtimer

Solution

You don't need to subclass QThread in this particular case. And in general, abstain from subclassing QThread unless you are sure it is what you need.

Here is a quick example how to setup a worker and timer in a thread and launch it:

the worker class:

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = 0) : QObject(parent) {}

signals:
    void doSomething();

public slots:
    void trigger() {
        emit doSomething();
    }
};

main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MainThreadObject o;

    QThread *thread = new QThread;
    Worker w;
    QTimer timer;
    timer.setInterval(1000);

    timer.moveToThread(thread);
    w.moveToThread(thread);

    QObject::connect(thread, SIGNAL(started()), &timer, SLOT(start()));
    QObject::connect(&w, SIGNAL(doSomething()), &o, SLOT(doSomething()));
    QObject::connect(&timer, SIGNAL(timeout()), &w, SLOT(trigger()));

    thread->start();

    return a.exec();
}

So, we have the `MainThreadObject` which represents a QObject derived living in the main thread. We create the timer and `Worker` object, which is just used to wrap a signal and slot to avoid the need of subclassing QThread. The timer is setup and it and the worker are moved to the new thread, the thread `started()` signal is connected to the timer `start()` slot, the worker `doSomething()` signal is connected to the main thread object `doSomething()` slot, and finally the timer `timeout()` signal is connected to the worker `trigger()` slot. Then the thread is started which initiates the entire chain in the event loop.

As a result, the `MainThreadObject::doSomething()` is called every second, with the signal emitted from the secondary thread.

Problem

I'm working on an application developed with Qt 4.6. I want to create a custom timer that counts in a separate thread. However, I want this timer to be able to send signals to the main thread. I subclassed QThread but it doesn't seem to work. Here is Timer.h: ``` #ifndef TIMER_H #define TIMER_H #include <QtCore/QObject> #include <QtCore/QThread> #include <QtCore/QTimer> class Timer : public QThread { Q_OBJECT public: explicit Timer(QObject *parent = 0); ~Timer(); // true if the timer is active bool isCounting(); // start the timer with a number of seconds void startCounting(int value = 300); void stopCounting(); // the number of seconds to reach int maximum(); // the current value of the timer int value(); // elapsed time since the timer has started int elapsedTime(); signals: // sent when the timer finishes to count void timeout(); // an event is emited at each second when the timer is active void top(int remainingSeconds); protected: // launch the thread //virtual void run(); private slots: // decrements the remaining time at each second and emits top() void timerEvent(); private: QTimer* _timer; // remaining time int _left; // number of seconds at timer startup int _maximum; }; #endif // TIMER_H ``` And Timer.cpp: ``` #include "Timer.h" Timer::Timer(QObject *parent) : QThread(parent) { _timer = new QTimer(this); _maximum = 0; _left = 0; connect(_timer, SIGNAL(timeout()), this, SLOT(timerEvent())); } Timer::~Timer() { delete _timer; } bool Timer::isCounting() { // test if timer still active return _timer->isActive(); } void Timer::startCounting(int value) { qDebug() << QString("Start timer for %1 secs").arg(QString::number(value)); if(_left != 0 || _timer->isActive()) { _timer->stop(); } _maximum = value; _left = value; // emit the first top emit top(_left); // start the timer: 1000 msecs _timer->start(1000); // start the thread start(); } void Timer::stopCounting() { qDebug() << QString("Stopping timer at %1 secs => %2 secs remaining.").arg(QString::number(elapsedTime()), QString::number(_left)); // stop timer _timer->stop(); _left = 0; _maximum = 0; // kill thread terminate(); } int Timer::maximum() { return _maximum; } int Timer::value() { return _left; } void Timer::timerEvent() { qDebug() << "Timer event"; if(--_left == 0) { // stop timer _timer->stop(); // emit end of timer emit timeout(); // stop thread terminate(); } else { // emit a signal at each second emit top(_left); } } int Timer::elapsedTime() { return (_maximum - _left); } ``` EDIT I realized the object I tried to move to another thread was actually a singleton. It could lead to a problem (see here).

Original source