c++qtqthreadqt-signalsqtimer

How to use a QTimer only after a QThread is started


I would like to use a QTimer in my MainWindow application. The timer should start when the thread is started. I have tried:

ct_thread.h

#include <QtCore>
#include <QThread>
#include <QTimer>

class CT_Thread : public QThread
{
    Q_OBJECT
public:
    explicit CT_Thread(QObject* parent = 0);
    QTimer* timer;
    void run();

private slots:
    void on_timer();
};

ct_thread.cpp (Version 1)

#include "ct_thread.h"
#include "mainwindow.h"
#include <QtCore>
#include <QDebug>

CT_Thread::CT_Thread(QObject* parent) :
    QThread(parent)
{}

void CT_Thread::run()
{
    timer = new QTimer(0);
    connect(timer, SIGNAL(timeout()), this, SLOT(on_timer()));
    timer->start(1000);

    // do something else
}

void CT_Thread::on_timer()
{
    qDebug() << "Hello World!";
}

This does not reach the "Hello World!", i.e. the connection does not work properly.

Alternatively, I tried connecting in the constructor. This connects the Slot but the timer starts when opening the GUI and not when the user starts ct_thread.

ct_thread.cpp (Version 2)

CT_Thread::CT_Thread(QObject* parent) :
    QThread(parent)
{
    timer = new QTimer(0);
    connect(timer, SIGNAL(timeout()), this, SLOT(on_timer()));
    timer->start(1000);
}

void CT_Thread::run()
{
    
    // do something else
}

void CT_Thread::on_timer()
{
    qDebug() << "Hello World!";
}

What do I do wrong and how do I have to phrase it?

Thanks in advance!


Solution

  • I'm assuming the timer should be handled within the thread.

    You are missing an event loop in the thread. QThread can be implemented with or without event loop. A timer needs an event loop (it cannot just interrupt the code it currently executes in the thread and call the on_timer() method preemtively instead).

    Calling exec() will run the event loop for the thread.

    void CT_Thread::run()
    {
        timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(on_timer()));
        timer->start(1000);
    
        // do something else
        exec();
    }
    

    Note that I also gave the timer a parent to avoid a memory leak.

    Note that a timer can also signal an event cross thread (thread affinity matters for that case). By default the thread affinity is the thread that created the object, therefore in your first example, the timer has the tread affinity set to the CT_Thread instance and will post it's event on the thread's event loop.