0

我已经编写了这段代码,查看了我应该如何运行一个控制台程序的在线示例,该程序不只是运行和退出,而一个确实如此。基于 Qt 控制台应用程序。这里的这个,我希望它退出。除了这条线,我几乎什么都懂QTimer::singleShot。如果该行被注释掉,应用程序将运行但不会退出。如果离开,应用程序将按预期运行并退出。谁能向我解释为什么?

材料.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();
}
4

1 回答 1

3

QTimer不需要正确退出;您只需要提供一种方法来让您的应用程序在某个时候中断事件循环。在 GUI 应用程序中,当最后一个窗口关闭时,Qt会自动执行此操作。

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

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

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


您在问题中的代码示例非常简单,不需要事件循环即可正常运行。代码中唯一的影响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是在事件循环开始之前调用(并且调用根本没有效果)。这就是为什么根据文档,建议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"
于 2018-06-23T10:37:43.190 回答