在Qt控制台应用程序中,为什么要正确退出代码需要QTimer?

时间:2018-06-23 10:29:25

标签: qt

我已经编写了这段代码,以在线方式查看示例,这些示例说明了我应该如何运行一个控制台程序,该程序不仅可以运行并退出,而且可以运行。基于Qt控制台应用程序。在这里,我希望它退出。除QTimer::singleShot行外,我几乎了解所有内容。如果该行被注释掉,则该应用程序将运行但不会退出。如果保留,应用程序将按预期运行并退出。谁能向我解释为什么?

dostuff.h

#ifndef DOSTUFF_H
#define DOSTUFF_H

#include <QObject>
#include <iostream>

class DoStuff: public QObject
{
    Q_OBJECT
public :
    DoStuff(QObject *parent = 0);

public slots:
    void run();

signals:
    void finished();
};

#endif // DOSTUFF_H

执行dostuff.cpp

#include "dostuff.h"

DoStuff::DoStuff(QObject *parent):QObject(parent)
{

}

void DoStuff::run(){
    for (int i = 0; i < 10000; i++){
        std::cout << "Processing " << i << std::endl;
    }
    emit(finished());
}

我的main.cpp

#include <QCoreApplication>
#include <QTimer>
#include "dostuff.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    DoStuff *dostuff = new DoStuff(&a);
    QObject::connect(dostuff,SIGNAL(finished()),&a,SLOT(quit()));
    dostuff->run();

    // WHY THIS??
    QTimer::singleShot(10,dostuff,SLOT(run()));

    return a.exec();
}

1 个答案:

答案 0 :(得分:1)

QTimer不需要正确退出;您只需要提供一种方法使您的应用程序在某个时候中断事件循环。在GUI应用程序中,当最后一个窗口关闭时,Qt does that automatically

在控制台应用程序中,您可以:

  • 在没有事件循环的情况下运行您的应用程序(如果您的应用程序中有直接的简单控制流)。

  • 或者(如果您需要事件循环来处理某些事件或跨线程信号/插槽),则需要有一些事件使您的应用程序中断事件循环并退出。该事件仅应在应用程序完成其工作时触发。


问题中的代码示例非常简单,不需要事件循环即可正常运行。 QTimer在您的代码中的唯一作用是将执行延迟10毫秒。这是不运行事件循环的相同代码示例:

#include <QtCore>

class DoStuff: public QObject
{
    Q_OBJECT
public :
    DoStuff(QObject *parent = 0) : QObject(parent) {}

public slots:
    void run() {
        for (int i = 0; i < 10000; i++){
            qInfo() << "Processing " << i;
        }
        emit finished();
    }

signals:
    void finished();
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    DoStuff dostuff;
    QObject::connect(&dostuff, &DoStuff::finished,
                     &a, &QCoreApplication::quit);
    dostuff.run();

    return 0; //no event loop required
}


#include "main.moc"

如果启动事件循环,则可能会注意到在不使用QTimer::singleShot时退出槽不起作用。这样做的原因是,quit在事件循环甚至尚未开始之前就已被调用(并且该调用完全无效)。因此,根据docs,建议使用排队连接连接到quit

  

优良作法是始终使用QueuedConnection将信号连接到此插槽。如果在控制进入主事件循环之前(例如在“ int main”调用exec()之前)发出了连接到该插槽的信号(未排队),则该插槽无效,并且应用程序永不退出。使用排队连接可确保直到控制权进入主事件循环后才调用该插槽。

因此,如果您想在上面的代码中有一个事件循环,则只需使用connect Qt::QueuedConnection

#include <QtCore>

class DoStuff: public QObject
{
    Q_OBJECT
public :
    DoStuff(QObject *parent = 0) : QObject(parent) {}

public slots:
    void run() {
        for (int i = 0; i < 10000; i++){
            qInfo() << "Processing " << i;
        }
        emit finished();
    }

signals:
    void finished();
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    DoStuff dostuff;
    QObject::connect(&dostuff, &DoStuff::finished,
                     &a, &QCoreApplication::quit,
                     Qt::QueuedConnection);
    //                   ^^^^^^^^^^^^^^^^
    //                   use a queued connection
    dostuff.run();

    return a.exec(); //start an event loop
}


#include "main.moc"