Starting QTimer In A QThread

前端 未结 6 2236
醉梦人生
醉梦人生 2020-12-01 11:05

I am trying to start a QTimer in a specific thread. However, the timer does not seem to execute and nothing is printing out. Is it something to do with the timer, the slot o

相关标签:
6条回答
  • 2020-12-01 11:37
    m_thread = new QThread(this);
    QTimer* timer = new QTimer(0); // _not_ this!
    timer->setInterval(1);
    timer->moveToThread(m_thread);
    // Use a direct connection to whoever does the work in order
    // to make sure that doIt() is called from m_thread.
    worker->connect(timer, SIGNAL(timeout()), SLOT(doIt()), Qt::DirectConnection);
    // Make sure the timer gets started from m_thread.
    timer->connect(m_thread, SIGNAL(started()), SLOT(start()));
    m_thread->start();
    
    0 讨论(0)
  • 2020-12-01 11:48

    You need an event loop to have timers. Here's how I solved the same problem with my code:

    MyThread::MyThread() {
    }
    
    void MyThread::run() {
        QTimer* timer = new QTimer(this);
        timer->setInterval(1);
        timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt()));
        timer->start();
    
        /* Here: */
        exec();             // Starts Qt event loop and stays there
       // Which means you can't have a while(true) loop inside doIt()
       // which instead will get called every 1 ms by your init code above.
    }
    
    void MyThread::doIt(){
        cout << "it works";
    }
    

    Here's the relevant piece of the documentation that none of the other posters mentioned:

    int QCoreApplication::exec()

    Enters the main event loop and waits until exit() is called. Returns the value that was set to exit() (which is 0 if exit() is called via quit()). It is necessary to call this function to start event handling. The main event loop receives events from the window system and dispatches these to the application widgets. To make your application perform idle processing (i.e. executing a special function whenever there are no pending events), use a QTimer with 0 timeout. More advanced idle processing schemes can be achieved using processEvents().

    0 讨论(0)
  • 2020-12-01 11:50

    A QTimer only works in a thread that has an event loop.

    http://qt-project.org/doc/qt-4.8/QTimer.html

    In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.

    0 讨论(0)
  • 2020-12-01 11:55

    As I commented (further information in the link) you are doing it wrong :

    1. You are mixing the object holding thread data with another object (responsible of doIt()). They should be separated.
    2. There is no need to subclass QThread in your case. Worse, you are overriding the run method without any consideration of what it was doing.

    This portion of code should be enough

    QThread* somethread = new QThread(this);
    QTimer* timer = new QTimer(0); //parent must be null
    timer->setInterval(1);
    timer->moveToThread(somethread);
    //connect what you want
    somethread->start();
    

    Now (Qt version >= 4.7) by default QThread starts a event loop in his run() method. In order to run inside a thread, you just need to move the object. Read the doc...

    0 讨论(0)
  • 2020-12-01 12:01

    You can use the emit signal and start the timer inside the emitted slot function

    main.cpp

    #include "MyThread.h"
    #include <iostream>
    using namespace std;
    
    int main(int argc, char *argv[]) {
        MyThread t;
        t.start();
        while(1);
    }
    

    MyThread.h

    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    
    #include <QTimer>
    #include <QThread>
    #include <iostream>
    
    class MyThread : public QThread {
        Q_OBJECT
    public:
        MyThread();
        QTimer *mTimer;
    signals:
       start_timer();
    public slots:
        void doIt();
        void slot_timer_start();
    protected:
        void run();
    };
    
    #endif  /* MYTHREAD_H */
    

    MyThread.cpp

    #include "MyThread.h"
    
    using namespace std;
    
    MyThread::MyThread() {
        mTimer = new QTimer(this);
        connect(this,SIGNAL(start_timer()),this, SLOT(slot_timer_start()));
        connect(mTimer,SIGNAL(timeout()),this,SLOT(doIt()));
    
    }
    
    void MyThread::run() {
        emit(start_timer());
        exec();
    }
    
    void MyThread::doIt(){
        cout << "it works";
    }
    void MyThread::slot_timer_start(){
        mTimer->start(1000);
    }
    
    0 讨论(0)
  • 2020-12-01 12:01

    I have created an example that calls the timer within a lambda function:

    #include <QCoreApplication>
    #include <QObject>
    #include <QTimer>
    #include <QThread>
    #include <QDebug>
    #include <memory>
    
    int main(int argc, char** argv)
    {
        QCoreApplication app(argc, argv);
    
        QThread* thread = new QThread(&app);
        QObject::connect(thread, &QThread::started, [=]()
        {
            qInfo() << "Thread started";
            QTimer* timer1 = new QTimer(thread);
            timer1->setInterval(100);
            QObject::connect(timer1, &QTimer::timeout, [=]()
            {
                qInfo() << "Timer1 " << QThread::currentThreadId();
            });
            timer1->start();
        });
        thread->start();
    
        QTimer timer2(&app);
        QObject::connect(&timer2, &QTimer::timeout, [=]()
        {
            qInfo() << "Timer2 " << QThread::currentThreadId();
        });
        timer2.setInterval(100);
        timer2.start();
    
        return app.exec();
    }
    
    0 讨论(0)
提交回复
热议问题