简体   繁体   English

QTimer不调用超时槽

[英]QTimer doesn't call timeout slot

I was trying to use a QTimer within different QThread , but I couldn't connect to the QTimer 's timeout() slot. 我试图在不同的QThread使用QTimer ,但无法连接到QTimertimeout()插槽。

What am I doing wrong? 我究竟做错了什么?

Here is my code: 这是我的代码:

extern MainWindow *mainClass;

class myObj : public QObject
{
    Q_OBJECT
public:
    explicit myObj(QObject *parent = 0);
    ~myObj();
    QThread workerThread;

    int percent;
    QTimer *percentTimer;

public slots:
    void doWork();
    void percentUpdate();
    void startFunction();

signals:
    void start();
    void UpdateResult();
};

myObj::myObj(QObject *parent) : QObject(parent)
{
    moveToThread(&workerThread);

    connect(&workerThread, SIGNAL(finished()), this, SLOT(deleteLater()));
    connect(this, SIGNAL(UpdateResult()), mainClass, SLOT(on_UpdateResult()));
    connect(&workerThread, SIGNAL(started()), this, SLOT(doWork()));
    connect(this, SIGNAL(start()), this, SLOT(startFunction()));

    percent++;
    percentTimer = new QTimer();
    percentTimer->moveToThread(&workerThread);
    percentTimer->setInterval(1000);
    connect(percentTimer, SIGNAL(timeout()), this,SLOT(percentUpdate()));

}

myObj::~myObj() {
    workerThread.quit();
    workerThread.wait();
    if (percentTimer) percentTimer->deleteLater();
}

void myObj::doWork()
{
    emit start();
    workerThread.exec();    
}

void myObj::startFunction()
{
    percentTimer->start();
    QThread::sleep(60);
    percentTimer->stop();    
}

void myObj::percentUpdate()
{
    qDebug() << "In Timer" << percent++;
    emit UpdateResult();

}

This is because you are trying to start your QTimer from a different thread than the one that created it. 这是因为您试图从与创建它的线程不同的线程中启动QTimer。 When using QTimer and threads, you should be very careful to create your QTimer in the thread that will control it. 使用QTimer和线程时,应该非常小心在将控制它的线程中创建QTimer。

From QTimer class documentation : QTimer类文档

In multithreaded applications, you can use QTimer in any thread that has an event loop. 在多线程应用程序中,可以在具有事件循环的任何线程中使用QTimer。 To start an event loop from a non-GUI thread, use QThread::exec(). 要从非GUI线程启动事件循环,请使用QThread :: exec()。 Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Qt使用计时器的线程关联性来确定哪个线程将发出timeout()信号。 Because of this, you must start and stop the timer in its thread ; 因此, 您必须在其线程中启动和停止计时器 it is not possible to start a timer from another thread. 无法从另一个线程启动计时器。

In your case percentTimer = new QTimer(); 在您的情况下, percentTimer = new QTimer(); is executed from the main thread, (even though you used moveToThread before, this is still the main thread executing it), while your doWork and start signals are emitted from workerThread . 从主线程执行(即使您之前使用过moveToThread ,但仍是执行它的主线程),而doWorkstart信号是从workerThread发出的。

You can for instance do your new QTimer from a void init() slot called from your workerThread , rather than in the constructor, to ensure that the QTimer is created and owned by the proper thread. 例如,您可以从workerThread调用的void init()插槽中而不是在构造函数中执行new QTimer ,以确保QTimer由适当的线程创建和拥有。

myObj::myObj(QObject *parent) : QObject(parent), percentTimer(nullptr)
{
    moveToThread(&workerThread);

    connect(&workerThread, SIGNAL(finished()), this, SLOT(deleteLater()));
    connect(this, SIGNAL(UpdateResult()), mainClass, SLOT(on_UpdateResult()));
    connect(&workerThread, SIGNAL(started()), this, SLOT(init()));
    connect(&workerThread, SIGNAL(started()), this, SLOT(doWork()));
    connect(this, SIGNAL(start()), this, SLOT(startFunction()));

    percent++;
}

void myObj::init() {
    percentTimer = new QTimer();
    percentTimer->setInterval(1000);
    connect(percentTimer, SIGNAL(timeout()), this, SLOT(percentUpdate()));
}

First of all, you should shart workerThread to let myObj work in its context (start it after creating required connections because slots connected to start signal possibly would not be executed otherwise). 首先,您应该使用workerThread来让myObj在其上下文中工作( 创建所需的连接启动它因为连接到start信号的插槽可能不会执行)。 Instead of using QThread::sleepFor you should use something like this: 而不是使用QThread::sleepFor您应该使用这样的东西:

QEventLoop loop;
QTimer::singleShot(60000, &loop, SLOT(exit()));
loop.exec();

to create delays, because QThread::sleepFor freezes overall thread execution. 创建延迟,因为QThread::sleepFor冻结了整个线程的执行。 And so none of your events will be processed that bound to this thread. 因此,绑定到该线程的事件都不会被处理。

workerThread.exec() is useless here. 这里的workerThread.exec()是没有用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM