user1787326
user1787326

Reputation: 31

Why does this Qt signal never get emitted?

I am trying to get data out of a web page, but the signal finished() never gets emitted!!! I know I must be doing something wrong, but can't figure out what it is.

# webservice.h
class WebService:public QObject
{
    Q_OBJECT

 public:
    explicit WebService(QObject *parent=0);
    void getRequest(const QString &urlString);

signals:
    void networkError(QNetworkReply::NetworkError ne);
    void finished(QNetworkReply*);

public slots:
    void parseNetworkResponse(QNetworkReply* finished);

private:
    QNetworkAccessManager *netMgr;

public:
    QByteArray data;
};

#webservice.cpp
WebService::WebService(QObject *parent):QObject(parent)
{
    netMgr = new QNetworkAccessManager;

    connect(netMgr, SIGNAL(finished(QNetworkReply*)),
                 this, SLOT(parseNetworkResponse(QNetworkReply*)));
}

void WebService::getRequest(const QString &urlString)
{
    QUrl url(urlString);
    QNetworkRequest req;
    emit finished(netMgr->get(req));
}

void WebService::parseNetworkResponse(QNetworkReply *finished)
{
    if (finished->error() != QNetworkReply::NoError)
    {
        emit networkError(finished->error());
        return;
    }

    data = finished->readAll();

   qDebug() << data;
}

data never gets assigned a value as expected.

Upvotes: 1

Views: 611

Answers (1)

Michael Burr
Michael Burr

Reputation: 340446

You aren't passing the url to the QNetworkRequest you create. Try:

QNetworkRequest req(url);

inside WebService::getRequest().

 


As requested, here's the source modified to allow it compile and work inside QtCreator as a single main.cpp file in a console application project:

#include <QCoreApplication>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QByteArray>
#include <QString>

#include <QDebug>

//# webservice.h
class WebService:public QObject
{
    Q_OBJECT

 public:
    explicit WebService(QObject *parent=0);
    void getRequest(const QString &urlString);

signals:
    void networkError(QNetworkReply::NetworkError ne);
    void finished(QNetworkReply*);

public slots:
    void parseNetworkResponse(QNetworkReply* finished);

private:
    QNetworkAccessManager *netMgr;

public:
    QByteArray data;
};

//#webservice.cpp
WebService::WebService(QObject *parent):QObject(parent)
{
    netMgr = new QNetworkAccessManager;

    connect(netMgr, SIGNAL(finished(QNetworkReply*)),
                 this, SLOT(parseNetworkResponse(QNetworkReply*)));
}

void WebService::getRequest(const QString &urlString)
{
    QUrl url(urlString);
    QNetworkRequest req(url);
    emit finished(netMgr->get(req));
}

void WebService::parseNetworkResponse(QNetworkReply *finished)
{
    if (finished->error() != QNetworkReply::NoError)
    {
        qDebug() << "QNetworkReply error: " << finished->error();
        emit networkError(finished->error());
        return;
    }

    data = finished->readAll();

   qDebug() << data;
}

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

    WebService web;
    web.getRequest("http://www.google.com");

    return a.exec();
}

#include "main.moc"

The minor modifications that were made:

  • added necessary headers
  • added a main() that called WebService::getRequest() with an appropriate URL
  • added #include "main.moc" to the end of the main.cpp file so qmake would "moc-ify" it properly as a single, self-contained .cpp file
  • made the fix mentioned above in the answer to the question
  • added a qDebug() output in the error case

One final thing that needed to be done was to add QT += network in the .pro file for the project so the Qt networking modules get added to the link step and to the header search path.


Update 15 Oct 2013

From your comments, it looks like you want the QNetworkAccessManager::get() call to be synchronous. I've added another version of your example program that will block in WebService::getRequest() until the request's finished signal is received. Note that this example doesn't perform much in the way of error handling, and would probably perform very badly if the netwrok request fails to complete in a timely manner. Dealing apprpriately with errors and timeouts would be necessary for anything but example or study code.

The basic idea in this example is that the signals emitted in the asynchronous Qt networking model are driven by the framework's event loop. So when a request is made, a new 'nested' event loop is created and the WebService::getRequest() function execs that loop (and stays there) until the handler of the finished signal tells the event loop to exit.

#include <QCoreApplication>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QUrl>

#include <QEventLoop>

#include <QByteArray>
#include <QString>

#include <QDebug>

//# webservice.h


class WebService:public QObject
{
    Q_OBJECT

 public:
    explicit WebService(QObject *parent=0);
    void getRequest(const QString &urlString);

signals:
    void networkError(QNetworkReply::NetworkError ne);
    //void finished(QNetworkReply*);

public slots:
    void parseNetworkResponse(QNetworkReply* finished);

private:
    QNetworkAccessManager *netMgr;
    QEventLoop request_event_loop;

public:
    QByteArray data;
};

//#webservice.cpp
WebService::WebService(QObject *parent):QObject(parent)
{
    netMgr = new QNetworkAccessManager;

    connect(netMgr, SIGNAL(finished(QNetworkReply*)),
                 this, SLOT(parseNetworkResponse(QNetworkReply*)));
}

void WebService::getRequest(const QString &urlString)
{
    QUrl url(urlString);
    QNetworkRequest req(url);
    netMgr->get(req);

    request_event_loop.exec();        // wait here until the WebService::parseNetworkResponse() slot runs
    // emit finished(netMgr->get(req));
}

void WebService::parseNetworkResponse(QNetworkReply *finished)
{
    qDebug() << "enter parseNetworkResponse()";

    if (finished->error() != QNetworkReply::NoError)
    {
        qDebug() << "QNetworkReply error: " << finished->error();
        emit networkError(finished->error());
    }
    else {
        data = finished->readAll();

        qDebug() << data;
    }

    qDebug() << "request_event_loop.exit()";
    request_event_loop.exit();
    qDebug() << "exit parseNetworkResponse()";
}

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

    WebService web;

    qDebug() << "main() getRequest()";
    web.getRequest("http://www.stackoverflow.com");
    qDebug() << "main() getRequest() completed";

    return a.exec();
}

#include "main.moc"

Upvotes: 1

Related Questions