【问题标题】:Qt QNetworkRequest hang, but I believe I'm in an event loopQt QNetworkRequest 挂起,但我相信我处于事件循环中
【发布时间】:2012-11-04 10:07:15
【问题描述】:

我正在运行 Qt 4.8.1

我正在尝试使用 QNetworkRequest 发送请求,但收到“QEventLoop:没有 QApplication 无法使用”错误。我相信我正在一个事件循环中运行。

void WebLoader::load()
{
    QNetworkRequest request;
    request.setUrl(QUrl("http://www.bbc.co.uk/"));

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

    QNetworkReply *reply = manager->get(request);
    connect(reply, SIGNAL(readyRead()), this, SLOT(checkForUpdateSlot()));
}

manager->get(reply) 调用永远不会返回。

单击菜单项时将调用此函数。在它的堆栈跟踪中有 QWidget::event(QEvent) 。应用程序肯定是在运行复杂 UI 的其余部分时运行的。

作为我尝试过的变体:

  1. 使用新的 QNetworkAccessManager(mainWindow) - mainWindow 继承自 QMainWindow
  2. 使用新的 QNetworkAccessManager(application) - 应用程序继承自 QApplication
  3. 从 customEvent 调用 load()
  4. 从计时器回调中调用 load()

[编辑]

我现在在 MainWindow 构造函数中构造 QNetworkAccessManager:

MainWindow::MainWindow() : queryAnalyser(NULL)
{
    manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(managerFinished(QNetworkReply*)));

managerFinished 未被调用。

我正在获取调试 IO: 'QObject:无法为不同线程中的父级创建子级。 (Parent是MainWindow(0x28fcd0),parent的线程是QThread(0x4862828),当前线程是QThread(0x7d90b70)'

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    WXApplication *a = WXApplication::getApp();

    MainWindow mainWin;

    mainWin.show();
    mainWin.checkArgs();
    return app.exec();
}

【问题讨论】:

  • manager->get(reply) 应该在 QNetworkAccessManager::finished(QNetworkReply*) 信号之后调用
  • 我现在把 QNetworkAccessManager 的构造放在 MainWindow 构造函数中: 'MainWindow::MainWindow() : queryAnalyser(NULL) { manager = new QNetworkAccessManager(this);连接(经理,信号(完成(QNetworkReply*)),这个,SLOT(managerFinished(QNetworkReply*)));'

标签: qt


【解决方案1】:

确保您的QNetworkAccessManager 在感知请求的方法结束时不会被破坏。如果它被销毁,您的请求将丢失,因为被销毁的QNetworkAccessManager 将无法将finished() 信号发送到连接的插槽。

这正是WebLoader::load(); 方法中发生的事情。 manager 变量只在方法执行过程中存在,方法会在你收到回复之前结束。

您可以将QNetworkAccessManager 放入一个全局变量中,并在每次需要时使用此全局变量:

文件.hpp:

//...

#include <QNetworkAccessManager>
extern QNetworkAccessManager QNAM;

//...

文件.cpp:

//...

#include "afile.hpp"
QNetworkAccessManager QNAM = QNetworkAccessManager();

//...

在您的代码中(例如WebLoader::load();):

//...
#include "afile.hpp"
//...
QNetworkAccessManager * manager = &QNAM;
//...

在请求中,设置一个原始对象来“标记”请求,并确保正确的方法会处理正确的回复:

void WebLoader::load()
{
    QNetworkRequest request;
    request.setUrl(QUrl("http://www.bbc.co.uk/"));
    request.setOriginatingObject(this);

    QNetworkAccessManager * manager = &QNAM;
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(checkForUpdateFinished(QNetworkReply*)));

    manager->get(request);
}

void WebLoader::checkForUpdateFinished(QNetworkReply* reply)
{
    if (reply == 0 || reply->request().originatingObject() != this)
    {
        return;
    }

    disconnect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(checkForUpdateFinished(QNetworkReply*)));

    // Reply treatment

    reply->deleteLater();

    // ...
}

在您的MainWindow 构造函数中,如果不需要,请忘记this,或者使用QNAM 全局变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多