【问题标题】:Proper way to close QCoreApplication关闭 QCoreApplication 的正确方法
【发布时间】:2015-05-29 15:53:16
【问题描述】:

我正在制作一个用于从 FTP 服务器下载文件的 Qt5 QCoreApplication(从 HTTP 开始,现在已切换)。

我的程序要关闭时遇到问题。在我将exit(0) 添加到downloader.cpp 之后,我的程序现在结束了,但是我收到以下错误:

QWaitCondition:在线程仍在等待时销毁。

我的代码如下:

main.cpp

#include <QCoreApplication>
#include <downloader.h>

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

    Downloader d;
    d.doDownload();

    a.exec();
}


**downloader.cpp**

#include "downloader.h"

Downloader::Downloader(QObject *parent) :
    QObject(parent)
{
}

void Downloader::doDownload() {

manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

manager->get(QNetworkRequest(QUrl("ftp://ftp.fao.org/Public/GIEWS/windisp/40manual/wd4en.pdf")));
}


void Downloader::replyFinished (QNetworkReply *reply)
{

    if(reply->error()) {
        qDebug() << "ERROR!";
        qDebug() << reply->errorString();
    }
    else

    {
        qDebug() << "Download finished!";

        QFile *file = new QFile("C:/Users/jelicicm/Desktop/wd4en.pdf");

        if(file->open(QFile::Append))
        {
            file->write(reply->readAll());
            file->flush(); file->close();
            qDebug() <<"Downloaded file size:" <<(file->size())/1024<<"KB";
        }
        delete file;
    }

    reply->deleteLater();
    exit(0);

}

我得到以下输出:

下载完成!下载的文件大小... QWaitCondition: Destroyed 而线程仍在等待。

据我所知,我想象的一切都完成了。下载文件,并显示其大小。但我想这个错误一定意味着什么。

有人可以向我解释这个错误是什么,为什么会发生以及如何修补它?

【问题讨论】:

  • 尝试使用 qApp->exit(0)。由于您的下载器类是一个 QObject,您还可以创建并发出一个信号来代替“完成”之类的退出调用,并将下载器的“完成”连接到“QCoreApplication::quit()”插槽。
  • qApp->exit(0) 没有什么好处。将尝试通过连接两个信号来做点什么...谢谢您的回复!

标签: qt download ftp qt5 qcoreapplication


【解决方案1】:

您的代码存在一些问题。您将 Qt 视为本质上是程序性的,而它实际上是通过主循环进行事件驱动的。

首先,在QApplication循环开始之前调用qApp-&gt;exit(0)是错误的。根据 Qt,“如果事件循环没有运行,这个函数什么也不做。”你的事件循环还没有运行,因为你在调用 exec 之前调用了 doDownload

其次,当您运行QApplication::exec 时,您还没有创建任何要调度的顶级窗口或事件。我不确定当你打电话给exec 没有工作要做时会发生什么。当然,从语义上讲,对exec 的调用什么也不做。从技术上讲......也许它可能导致线程错误。同样,我不确定,但我知道您不应该以这种方式使用 exec

运行你的主事件循环做你所有花哨的 Qt 东西。这允许 Qt 调用您的代码。将插槽 doDownload 和信号 finished 添加到您的 Downloader

class Downloader : public QObject 
{
  Q_OBJECT

public:
  Downloader(QObject * parent = nullptr);

private slots:
  void doDownload();

signals:
  void finished();
}

...

void Downloader::doDownload() 
{
  // Same implementation as before
  // Emit signal when finished
  emit finished();
}

然后通过调用exec 并启动主循环来建立控制反转后调用您的插槽:

#include <QCoreApplication>
#include "Downloader.h"

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

  Downloader d;

  // Quit application when work is finished
  QObject::connect(&d, SIGNAL(finished()), &a, SLOT(quit())); // changed the 
  //variable name 'app' to 'a'

  // Run the user-hook (doDownload) from the application event loop.
  QTimer::singleShot(0, &d, SLOT(doDownload()));

  return a.exec();
}

现在 Qt 将调用您的代码。无需显式退出应用程序,只需 emit finished() 即可正确清理所有内容。

如果这能解决您的问题,请告诉我。如果没有,可能还有其他鱼要炸。

【讨论】:

  • 感谢您的回复!多亏了你,我的代码才能正常工作。我将我的'doDownload()' 定义为一个公共插槽,并且我正在从'replyFinished' 发送'emit' 信号。我没有阅读“QTimer”,因为我认为它不能以这种方式使用。现在会学习。再次感谢!
  • exec() 调用只是简单地旋转事件循环。如果没有事件进入,则循环就在那里,永远等待它们。它无害但无用。最小的情况是#include &lt;QCoreApplication&gt; int main(int argc, char ** argv) { QCoreApplication app(argc, argv); return app.exec(); } - 它会永远挂起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
相关资源
最近更新 更多