QObject::startTimer: 定时器只能在使用QThread启动的线程中使用。

8

我正试图在工作线程的事件循环中启动一个计时器,但是我遇到了这个错误:

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);
}
4个回答

3

在任何地方初始化您的计时器,但是在线程启动时立即开始它(将其附加到 QThread::started 信号):

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
}

1
我想我已经明白了,我试图从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);
}

3
计时器应该位于大部分信号接收者所在的线程中。否则,当发射线程停滞时,会阻塞接收者线程。 - Kuba hasn't forgotten Monica
1
我脑子里有点混乱,还停留在单线程状态。但是,如果整个对象都位于线程中,我就不需要将驻留在该对象中的计时器移动到另一个线程中了... - Sebastian Lange
@SebastianLange 您的意思是当 QTimer 成员变量改为 QTimer *,并添加一个类似 sl_init() 的槽函数,在其中分配 'new QTimer(this)' 时?我想您是对的,但这样会增加更多的代码。我更喜欢少一些代码。 - user2950911

0

这种方法对我来说有点危险。通过将 QObject 移动到 QThread 上,您使线程负责对象的事件(信号、槽、消息等)。然而,当对象被删除时,线程将在对象本身之前被删除,这可能会导致一些意外的行为。

推荐的方法 是分别实例化线程和对象。


0
希望这对你有所帮助:
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";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接