[SOLVED] QNetworkAccessManager does not emit finished() signal



  • I am writing a little test program so I could figure out how QNetworkAccessManager works and get a QProgressDialog working with a download. The download appears to work as I can see it downloading in wireshark and the progress is working. However, the reply never emits finished() and I do not believe readyRead() is emitting as well. The file is not being saved for some reason and I do not know what else to do. I would really appreciate some help here.

    Here is the header:
    @#ifndef QTDOWNLOADER_H
    #define QTDOWNLOADER_H

    #include <QtGui/QMainWindow>
    #include <QProgressDialog>
    #include <QFile>
    #include <QtNetwork>
    #include <QUrl>
    #include <QTime>
    #include <QMessageBox>
    #include "ui_qtdownloader.h"

    class QtDownloader : public QMainWindow, public Ui::QtDownloaderClass
    {
    Q_OBJECT

    public:
    QtDownloader(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~QtDownloader();

    public slots:
    void downloadButtonPressed();
    void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
    void downloadFinished();
    void downloadReadyRead();
    void cancelDownload();

    private:
    QNetworkAccessManager manager;
    QFile *file;
    QTime downloadTime;
    QProgressDialog *progressDialog;
    QNetworkReply *reply;
    bool downloadRequestAborted;
    };

    #endif // QTDOWNLOADER_H
    @

    And here is the source:
    @#include "qtdownloader.h"

    QtDownloader::QtDownloader(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
    {
    setupUi(this);
    progressDialog = new QProgressDialog(this);
    connect(downloadButton, SIGNAL(clicked()), this, SLOT(downloadButtonPressed()));
    }

    QtDownloader::~QtDownloader()
    {
    delete progressDialog;
    progressDialog = NULL;
    }

    void QtDownloader::downloadButtonPressed()
    {
    QUrl url(urlLineEdit->text());
    QString filename = QFileInfo(url.path()).fileName();

    if(QFile::exists(filename))
    {
    if(QMessageBox::question(this, tr("Downloader"),
    tr("There already exists a file called %1 in "
    "the current directory. Overwrite?").arg(filename),
    QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
    == QMessageBox::No)
    return;
    QFile::remove(filename);
    }

    file = new QFile(filename);
    if(!file->open(QIODevice::WriteOnly))
    {
    QMessageBox::information(this, "Downloader",
    tr("Unable to save the file %1: %2.")
    .arg(filename).arg(file->errorString()));
    delete file;
    file = NULL;
    return;
    }

    downloadRequestAborted = false;
    reply = manager.get(QNetworkRequest(url));
    connect(reply, SIGNAL(finished()), this, SIGNAL(downloadFinished()));
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
    connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload()));
    connect(reply, SIGNAL(readyRead()), SIGNAL(downloadReadyRead()));

    progressDialog->setLabelText(tr("Downloading %1...").arg(filename));
    downloadButton->setEnabled(false);
    progressDialog->exec();
    }

    void QtDownloader::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
    {
    if(downloadRequestAborted)
    return;
    progressDialog->setMaximum(bytesTotal);
    progressDialog->setValue(bytesReceived);
    }

    void QtDownloader::downloadFinished()
    {
    if(downloadRequestAborted)
    {
    if(file)
    {
    file->close();
    file->remove();
    delete file;
    file = NULL;
    }
    reply->deleteLater();
    progressDialog->hide();
    return;
    }

    progressDialog->hide();
    file->flush();
    file->close();

    if(reply->error())
    {
    //Download failed
    QMessageBox::information(this, "Download failed", tr("Failed: %1").arg(reply->errorString()));
    }

    reply->deleteLater();
    reply = NULL;
    delete file;
    file = NULL;
    }

    void QtDownloader::cancelDownload()
    {
    downloadRequestAborted = true;
    reply->abort();
    downloadButton->setEnabled(true);
    }

    void QtDownloader::downloadReadyRead()
    {
    if(file)
    file->write(reply->readAll());
    }
    @

    I know finished is not getting emitted as the download button is never re-enabled. It does however when I cancel the download. I am really at a loss of words here.

    Thank you,
    Curtis



  • Also, if it helps, I am using Visual Studio Professional 2010 with the plugin and Qt version 4.7.3.



  • Hi,
    You have the mistake in connect statements, please change this two lines:
    @
    connect(reply, SIGNAL(finished()), this, SIGNAL(downloadFinished()));
    connect(reply, SIGNAL(readyRead()), SIGNAL(downloadReadyRead()));
    @

    to
    @
    connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
    connect(reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
    @



  • Thank you dakron! Wow, can't believe I did that. You know what they say, the more eyes the better.

    Thank you again.



  • [quote]
    I know finished is not getting emitted as the download button is never re-enabled. It does however when I cancel the download. I am really at a loss of words here.
    [/quote]
    First of all, you are not re-enabling the button in your code if the download is complete.
    Second I would suggest you add a call to downloadReadyRead() to your downloadFinished method, just in case that signal arrives before readyRead().



  • [quote author="dakron" date="1310419284"]Hi,
    You have the mistake in connect statements, please change this two lines:
    @
    connect(reply, SIGNAL(finished()), this, SIGNAL(downloadFinished()));
    connect(reply, SIGNAL(readyRead()), SIGNAL(downloadReadyRead()));
    @

    to
    @
    connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
    connect(reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
    @
    [/quote]

    Just as a side note, the this isn't needed.

    [quote]
    bool QObject::connect ( const QObject * sender, const char * signal, const char * method, Qt::ConnectionType type = Qt::AutoConnection ) const

    This function overloads connect().

    Connects signal from the sender object to this object's method.

    Equivalent to connect(sender, signal, this, method, type).
    [/quote]



  • [quote author="loladiro" date="1310420216"][quote]
    I know finished is not getting emitted as the download button is never re-enabled. It does however when I cancel the download. I am really at a loss of words here.
    [/quote]
    First of all, you are not re-enabling the button in your code if the download is complete.
    Second I would suggest you add a call to downloadReadyRead() to your downloadFinished method, just in case that signal arrives before readyRead().
    [/quote]

    1. Yeah, I noticed I wasn't re-enabling the button after download once it was working so I already added that.
    2. When would that happen out of curiosity? When the download happens so quick (ex. small file)?

    So something like this would be more appropriate?

    @void QtDownloader::downloadFinished()
    {
    if(downloadRequestAborted)
    {
    if(file)
    {
    file->close();
    file->remove();
    delete file;
    file = NULL;
    }
    reply->deleteLater();
    progressDialog->hide();
    downloadButton->setEnabled(true);
    return;
    }

    downloadReadyRead();
    progressDialog->hide();
    downloadButton->setEnabled(true);
    file->flush();
    file->close();

    if(reply->error())
    {
    //Download failed
    QMessageBox::information(this, "Download failed", tr("Failed: %1").arg(reply->errorString()));
    }

    reply->deleteLater();
    reply = NULL;
    delete file;
    file = NULL;
    }@



  • Concerning 2). I am actually not sure that it can happen (i have heard people say it does, but never experienced it myself - probably because I don't use it that much). The only way I could imagine that happening is that the order is mixed up, because of the threading within QNetworkAcccessManager. And I always thinks it's better to be safe than sorry ;)



  • [quote author="loladiro" date="1310420290"]
    [quote]
    bool QObject::connect ( const QObject * sender, const char * signal, const char * method, Qt::ConnectionType type = Qt::AutoConnection ) const

    This function overloads connect().

    Connects signal from the sender object to this object's method.

    Equivalent to connect(sender, signal, this, method, type).
    [/quote]

    [/quote]

    I noticed they were doing that in the "HTTP":http://doc.qt.nokia.com/latest/network-http.html example is some sections, but not in the startRequest part of the code. I just didn't really look to see why. Thank you for the info.



  • [quote author="loladiro" date="1310421072"]Concerning 2). I am actually not sure that it can happen (i have heard people say it does, but never experienced it myself - probably because I don't use it that much). The only way I could imagine that happening is that the order is mixed up, because of the threading within QNetworkAcccessManager. And I always thinks it's better to be safe than sorry ;)[/quote]

    Fair enough, wish there was a little better explanation, but I fall in the same boat as you. Better safe then sorry :) and thank you for the information on that as well.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.