【问题标题】:QObject::startTimer: Timers can only be used with threads started with QThreadQObject::startTimer:定时器只能用于以 QThread 启动的线程
【发布时间】:2014-04-19 10:35:35
【问题描述】:

我正在尝试在工作线程的事件循环中启动 Timer,但出现此错误: 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);
}

【问题讨论】:

    标签: qt qthread qtimer


    【解决方案1】:

    希望这会有所帮助:

    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";
    }
    

    【讨论】:

      【解决方案2】:

      在任何地方初始化你的计时器,但在线程启动时立即启动它(将它附加到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
      }
      

      【讨论】:

        【解决方案3】:

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

        recommended approach是分别实例化线程和对象。

        【讨论】:

          【解决方案4】:

          我想我想通了,我尝试从 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);
          }
          

          【讨论】:

          • @SebastianLange 计时器应该与大多数信号接收者所在的线程相同。否则,当发射器线程停止时,您将停止接收线程。
          • 真的。只是脑子里出了点问题,还是单枪匹马。但是,如果整个对象都位于线程中,我也不需要将驻留在该对象中的计时器移动到另一个线程......
          • @SebastianLange 你的意思是当 QTimer 成员改为 QTimer * 并且我添加了一个像 sl_init() 这样的插槽时,我在其中分配了“新 QTimer(this)”?我想你是对的,但是你有更多的代码。我喜欢更少的代码。
          猜你喜欢
          • 2017-01-11
          • 2015-08-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-23
          相关资源
          最近更新 更多