Home > Software design >  How to use a QTimer only after a QThread is started
How to use a QTimer only after a QThread is started

Time:07-23

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!

CodePudding user response:

You can try to connect the private signal void QThread::started() ( https://doc.qt.io/qt-6/qthread.html#started) to a slot of your CT_Thread class. From there you can start your QTimer.

CodePudding user response:

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 is has the tread affinity set to the CT_Thread instance and will post it's event on the thread's event loop.

  • Related