QObject::startTimer: таймеры могут использоваться только с потоками, запущенными с QThread

Я пытаюсь запустить таймер в цикле событий рабочего потока, но я получаю эту ошибку:QObject::startTimer: Timers can only be used with threads started with QThread

Что не так с этим?

#include <QObject>
#include <QThread>
#include <QTimer>

class A : public QObject
{
    Q_OBJECT
public:
    A();

private:
    QThread m_workerThread;
    QTimer m_myTimer;

};

A::A()
{
    this->moveToThread(&m_workerThread);
    m_myTimer.moveToThread(&m_workerThread);
    m_workerThread.start();
    m_myTimer.start(1000);
}

3 ответа

Инициализируйте свой таймер в любом месте, но запустите его прямо при запуске потока (присоедините его к сигналу QThread::start):

class A : public QObject
{
    Q_OBJECT
public:
    A();

private slots:
    void started();
    void timeout();

private:
    QThread m_workerThread;
    QTimer m_myTimer;
};

A::A()
{
    moveToThread(&m_workerThread);

    connect(&m_workerThread, SIGNAL(started()), this, SLOT(started()));
    connect(&m_myTimer, SIGNAL(timeout()), this, SLOT(timeout()));

    m_myTimer.setInterval(1000);
    m_myTimer.moveToThread(&m_workerThread);

    m_workerThread.start();
}

void A::started()
{
    timer.start();
}

void A::timeout()
{
    // timer handler
}

Я думаю, что я понял это, я попытался запустить таймер из потока GUI, после того, как я переместил его в рабочий поток, вот как это работает:

class A : public QObject
{
    Q_OBJECT
public:
    A();

private:
    QThread m_workerThread;
    QTimer m_myTimer;

public slots:
    void sl_startTimer();
};

A::A()
{
    this->moveToThread(&m_workerThread);
    m_myTimer.moveToThread(&m_workerThread);
    m_workerThread.start();
    QMetaObject::invokeMethod(this, "sl_startTimer", Qt::QueuedConnection);
}

void A::sl_startTimer()
{
    m_myTimer.start(1000);
}

Надеюсь, это будет полезно:

class ReadYoloResult : public QObject
{
    Q_OBJECT
public:
    ReadYoloResult(QObject *parent = 0);
    void startTimer();
    QThread workerThread;

private:
    QTimer *timer;

public slots:
    void timerSlot();
};

ReadYoloResult::ReadYoloResult(QObject * parent)
{
    this->moveToThread(&workerThread);
    timer = new QTimer();
    connect(timer,SIGNAL(timeout()),this,SLOT(timerSlot()));

    workerThread.start();

    //timer->start(1000);
}

void ReadYoloResult::startTimer(){
    timer->start(100);
}
void ReadYoloResult::timerSlot(){
    qDebug()<<"In timer slot";
}

Этот подход кажется мне немного опасным. Перемещая QObject на QThreadвы делаете поток ответственным за события объекта (сигналы, слоты, сообщения и т. д.). Однако при удалении объекта поток будет удален раньше самого объекта, что может привести к непредвиденным последствиям.

Рекомендуемый подход состоит в том, чтобы создать экземпляр потока и объекта отдельно.

Другие вопросы по тегам