Qt QNetworkAccessManager and Slot not working - c++

i am a beginner in c++ and i am trying to retrieve data from a website using http request and to download the data in a file .
I am using the classes :
QMainWindow
QtNetwork/QNetworkAccessManager
QtNetwork/QNetworkRequest
QtNetwork/QNetworkReply
QUrl
The thing is that the file is created but there is no data in the file and i am getting an error that i don't understand . I searched through the forum found some similar kind of problems but did not understand as i am a beginner . Please help me its a school project and i am really stuck here.
Here is the httpWindow.h code
#ifndef HTTPWINDOW_H
#define HTTPWINDOW_H
#include <QMainWindow>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QUrl>
#include <QString>
class QFile;
namespace Ui {
class httpWindow;
}
class httpWindow : public QMainWindow
{
Q_OBJECT
public:
explicit httpWindow(QWidget *parent = 0);
~httpWindow();
void request(QUrl url);
private slots:
void downloadFile();
void httpFinished();
void httpReadyRead();
private:
Ui::httpWindow *ui;
QUrl url;
QNetworkAccessManager *manager;
QNetworkRequest requete;
QNetworkReply *reply;
QFile *file;
int httpGetId;
bool httpRequestAborted;
};
#endif // HTTPWINDOW_H
Here is the httpwindow.cpp
#include <QtWidgets>
#include <qnetwork.h>
#include <QString>
#include "httpwindow.h"
#include "ui_httpwindow.h"
httpWindow::httpWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::httpWindow)
{
ui->setupUi(this);
downloadFile();
}
httpWindow::~httpWindow()
{
delete ui;
}
void httpWindow::request(QUrl url)
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished()),
this, SLOT(httpFinished()));
//requete.setUrl(QUrl("http://fxrates.fr.forexprostools.com/index.php?force_lang=5&pairs_ids=1;3;2;4;7;5;8;6;&header-text-color=%23FFFFFF&curr-name-color=%230059b0&inner-text-color=%23000000&green-text-color=%232A8215&green-background=%23B7F4C2&red-text-color=%23DC0001&red-background=%23FFE2E2&inner-border-color=%23CBCBCB&border-color=%23cbcbcb&bg1=%23F6F6F6&bg2=%23ffffff&bid=show&ask=show&last=show&change=hide&last_update=hide"));
requete.setUrl(url);
reply = manager->get(requete);
connect(reply, SIGNAL(&reply::readyRead()), this, SLOT(httpReadyRead()));
}
void httpWindow::downloadFile()
{
QMessageBox msg ;
QUrl url("http://fxrates.fr.forexprostools.com/index.php?force_lang=5&pairs_ids=1;3;2;4;7;5;8;6;&header-text-color=%23FFFFFF&curr-name-color=%230059b0&inner-text-color=%23000000&green-text-color=%232A8215&green-background=%23B7F4C2&red-text-color=%23DC0001&red-background=%23FFE2E2&inner-border-color=%23CBCBCB&border-color=%23cbcbcb&bg1=%23F6F6F6&bg2=%23ffffff&bid=show&ask=show&last=show&change=hide&last_update=hide") ;
qDebug() << url.toString();
QFileInfo fileInfo(url.path());
//msg.setText("fileInfo = " + fileInfo);
QString fileName = "C:\\testQt\\" + fileInfo.fileName();
msg.setText("fileName = " + fileName);
if (fileName.isEmpty()){
fileName = "C:\testQt\fichier.html";
msg.setText(" création d'un nouveau fichier fichier.html ");
}
if (QFile::exists(fileName)) {
QFile::remove(fileName);
return;
}
file = new QFile(fileName);
msg.setText(" QFile::exists(fileName) == true , file : ");
if (!file->open(QIODevice::WriteOnly)) {
delete file;
file = 0;
return;
}
// schedule the request
httpRequestAborted = false;
request(url);
}
void httpWindow::httpFinished()
{
if (httpRequestAborted) {
if (file) {
file->close();
file->remove();
delete file;
file = 0;
}
reply->deleteLater();
return;
}
file->flush();
file->close();
QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (reply->error()) {
file->remove();
// QMessageBox::information(this, tr("HTTP"),
// tr("Download failed: %1.")
// .arg(reply->errorString()));
// downloadButton->setEnabled(true);
} else if (!redirectionTarget.isNull()) {
QUrl newUrl = url.resolved(redirectionTarget.toUrl());
// if (QMessageBox::question(this, tr("HTTP"),
// tr("Redirect to %1 ?").arg(newUrl.toString()),
// QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
url = newUrl;
reply->deleteLater();
file->open(QIODevice::WriteOnly);
file->resize(0);
request(url);
return;
}
reply->deleteLater();
reply = 0;
delete file;
file = 0;
}
void httpWindow::httpReadyRead()
{
// this slot gets called every time the QNetworkReply has new data.
// We read all of its new data and write it into the file.
// That way we use less RAM than when reading it at the finished()
// signal of the QNetworkReply
if (file)
file->write(reply->readAll());
}
Here is the main.cpp code
#include "httpwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
httpWindow w;
w.show();
return a.exec();
}
The errors :
can't find linker symbol for virtual table for `QMessageBox' value
found `RGB_MASK' instead
can't find linker symbol for virtual table for `QMessageBox' value
found `RGB_MASK' instead
"http://fxrates.fr.forexprostools.com/index.php?force_lang=5&pairs_ids=1;3;2;4;7;5;8;6;&header-text-color=%23FFFFFF&curr-name-color=%230059b0&inner-text-color=%23000000&green-text-color=%232A8215&green-background=%23B7F4C2&red-text-color=%23DC0001&red-background=%23FFE2E2&inner-border-color=%23CBCBCB&border-color=%23cbcbcb&bg1=%23F6F6F6&bg2=%23ffffff&bid=show&ask=show&last=show&change=hide&last_update=hide"
QObject::connect: No such signal QNetworkAccessManager::finished() in ..\ppe3_trading_test\httpwindow.cpp:24
QObject::connect: (receiver name: 'httpWindow')
QObject::connect: No such signal QNetworkReplyHttpImpl::&reply::readyRead() in ..\ppe3_trading_test\httpwindow.cpp:31
QObject::connect: (receiver name: 'httpWindow')
Please do help me its really important for my schooling .

connect(reply, SIGNAL(&reply::readyRead()), this, SLOT(httpReadyRead()));
You're mixing up old syntax and new syntax, it should be
connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));
or better yet using new syntax(Qt5 only):
connect(reply, &QNetworkReply::readyRead, this, &httpWindow::httpReadyRead);
QNetworkAccessManager doesn't have a finished() signal it has a finished(QNetworkReply*) signal, read the docs.

Related

Web request with progress bar

This is my code (C++: Qt) for getting webpage source:
QString htmlString;
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QNetworkRequest req( QUrl( QString( "http://stackoverflow.com" ) ) );
QNetworkReply *reply = mgr.get(req);
eventLoop.exec();
htmlString = reply->readAll();
Is there any way to get webpage source with progress bar ?!
Write special class for this:
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDebug>
#include <QProgressBar>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = 0);
void doDownload();
public slots:
void replyFinished (QNetworkReply *reply);
void updateDownloadProgress(qint64, qint64);
private:
QNetworkAccessManager *manager;
QProgressBar *bar;
};
#endif
Cpp:
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
}
void Downloader::doDownload()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
QNetworkReply * rep = manager->get(QNetworkRequest(QUrl("http://qt-project.org/")));
connect(rep, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateDownloadProgress(qint64, qint64)));
bar = new QProgressBar;
bar->show();
}
void Downloader::replyFinished (QNetworkReply *reply)
{
if(reply->error())
{
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << reply->readAll();
}
reply->deleteLater();
}
void Downloader::updateDownloadProgress(qint64 read, qint64 total)
{
qDebug() << read << total;
bar->setMaximum(total);
bar->setValue(read);
}
Usage:
Downloader down;
down.doDownload();
Main idea here is to use void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) [signal] to get progress and show this progress in QProgressBar.
And you can do this with your current code without class:
QString htmlString;
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QProgressBar *bar = new QProgressBar;
bar->show();
QNetworkRequest req( QUrl( QString( "http://stackoverflow.com" ) ) );
QNetworkReply *reply = mgr.get(req);
QObject::connect(reply,&QNetworkReply::downloadProgress,[=](qint64 bytesReceived, qint64 bytesTotal) {//with lambda
bar->setMaximum(bytesTotal);
bar->setValue(bytesReceived);
});
eventLoop.exec();
htmlString = reply->readAll();
qDebug() << htmlString;
I used here C++11 (CONFIG += c++11 to .pro file) and new syntax of signals and slots.

Delete QNetworkReply *reply cause SIGSEGV outside of the code?

I wrote a simple program to automate the process setting the router. After a check, I find a pointer need to be delete (QNetworkReply *reply in replyFinish())and do the job, but after that the program crash and Qt show it stopped in some assembly code :(
So my questions are:
Are there any common practices to handle situation like that (Qt
show the program stopped in some assembly code)
What did I do wrong when delete a pointer which isn't used anymore?
(pretty sure about that)
Here is the code:
#ifndef HTTPGETTER_H
#define HTTPGETTER_H
class QNetworkAccessManager;
class QNetworkReply;
class QNetworkRequest;
class QAuthenticator;
#include <QObject>
class httpGetter : public QObject
{
Q_OBJECT
private:
QNetworkAccessManager *nam;
public:
explicit httpGetter(QObject *parent=0);
~httpGetter();
public slots:
void replyFinish(QNetworkReply* reply);
void onAuthen(QNetworkReply*,QAuthenticator*);
};
implements
#include "httpgetter.h"
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkAccessManager>
#include <QAuthenticator>
#include <QDebug>
httpGetter::httpGetter(QObject *parent) : QObject(parent)
{
nam = new QNetworkAccessManager(this);
QObject::connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinish(QNetworkReply*)));
QObject::connect(nam,SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),this,SLOT(onAuthen(QNetworkReply*,QAuthenticator*)));
QUrl url("http://192.168.1.1");
QNetworkReply *reply= nam->get(QNetworkRequest(url));
}
httpGetter::~httpGetter(){
delete nam;
}
void httpGetter::replyFinish(QNetworkReply *reply)
{
if (reply==NULL) {
qDebug() << "NULL reply";
return;
}
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
qDebug() << statusCode.toString();
if (reply->error()==QNetworkReply::NoError) {
qDebug() << "NICE reply";
QByteArray bytes = reply->readAll();
QString answer = QString(bytes);
qDebug()<< answer;
}
else {
qDebug() << "reply error";
}
//delete reply; ==> delele cause sigsegv, if don't the program run like a while(true)
//reply == NULL;
}
void httpGetter::onAuthen(QNetworkReply* rep,QAuthenticator* auth)
{
if ( rep==NULL || auth == NULL) {
qDebug()<< "reply or authentication pointer is null";
return;
}
qDebug()<< rep->readAll();
auth->setUser("rolan");
auth->setPassword("123456");
}
main
#include <QtCore/QCoreApplication>
#include "httpgetter.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
httpGetter abc;
return a.exec();
}
According to the documentation:
Note: After the request has finished, it is the responsibility of the
user to delete the QNetworkReply object at an appropriate time. Do not
directly delete it inside the slot connected to finished(). You can
use the deleteLater() function.
Also, since
nam = new QNetworkAccessManager(this);
creates a new QNetworkAccessManager with this as its parent, and QObject's destructor will automatically delete all of its children, your delete nam; in httpGetter's destructor is unnecessary and will end up causing a double delete.

Qt NetworkAccessManager finished signal

I have a code that will download a package from the web. I want such code to run a html5viewer (or a window, it will be the same) after the download has finished, meaning I have to handle the finished() signal, here is my code:
main.cpp
#include <QApplication>
#include "html5applicationviewer.h"
#include "networkmanager.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
NetworkManager manager;
//manager.setFile("http://listadomedicamentos.aemps.gob.es/prescripcion.zip");
manager.setFile("http://listadomedicamentos.aemps.gob.es/prescripcion.zip");
/*
Html5ApplicationViewer viewer;
viewer.setOrientation(Html5ApplicationViewer::ScreenOrientationAuto);
viewer.showMaximized();
viewer.loadFile(QLatin1String("html/index.html"));*/
return app.exec();
}
networkmanager.h
#include <QObject>
#include "html5applicationviewer.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <QStringList>
class NetworkManager : public QObject
{
Q_OBJECT
public:
explicit NetworkManager(QObject *parent = 0);
virtual ~NetworkManager();
void setFile(QString fileURL);
private:
QNetworkAccessManager *manager;
QNetworkReply *reply;
QFile *file;
private slots:
void onDownloadProgress(qint64, qint64);
void onFinished(QNetworkReply *reply);
void onReadyRead();
void onReplyFinished();
};
networkmanager.cpp
#include "networkmanager.h"
#include "html5applicationviewer.h"
#include <QDir>
#include <QStandardPaths>
#include <QDebug>
NetworkManager::NetworkManager(QObject *parent) :
QObject(parent)
{
manager = new QNetworkAccessManager;
}
NetworkManager::~NetworkManager()
{
manager->deleteLater();
}
void NetworkManager::setFile(QString fileURL)
{
QString filePath = fileURL;
QString saveFilePath;
QString savePath;
QStringList filePathList = filePath.split('/');
QString fileName = filePathList.at(filePathList.count() - 1);
savePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
if (QDir(savePath).exists())
{
qDebug() << "Archivos locales para almacenar la base de datos existentes.";
}
else
{
qDebug() << "Creando los archivos locales para almacenar la base de datos...";
QDir().mkdir(savePath);
}
saveFilePath = QString(savePath + "/" + fileName );
QNetworkRequest request;
request.setUrl(QUrl(fileURL));
reply = manager->get(request);
file = new QFile;
file->setFileName(saveFilePath);
file->open(QIODevice::WriteOnly);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this,
SLOT(onDownloadProgress(qint64,qint64)));
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(onFinished(QNetworkReply*)));
connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
}
void NetworkManager::onDownloadProgress(qint64 bytesRead, qint64 bytesTotal)
{
qDebug() << QString::number(bytesRead).toLatin1() + " bytes descargados de " +
QString::number(bytesTotal).toLatin1() + " bytes totales";
}
void NetworkManager::onFinished(QNetworkReply *reply)
{
switch (reply->error())
{
case QNetworkReply::NoError:
{
qDebug() << "El archivo se ha descargado con éxito.";
}
break;
default:
qDebug() << reply->errorString().toLatin1();
}
if (file->isOpen())
{
file->close();
file->deleteLater();
}
}
void NetworkManager::onReadyRead()
{
file->write(reply->readAll());
}
void NetworkManager::onReplyFinished()
{
if (file->isOpen())
{
file->close();
file->deleteLater();
}
}
I have tried doing
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished(Html5ApplicationViewer&)));
void NetworkManager::onReplyFinished(Html5ApplicationViewer &viewer)
{
viewer.show();
if (file->isOpen())
{
file->close();
file->deleteLater();
}
}
But it will tell me that:
QObject::connect: Incompatible sender/receiver arguments
QNetworkReplyHttpImpl::finished() --> NetworkManager::startViewer(Html5ApplicationViewer&)
How could I make this viewer or window start with that finished() signal?
You are facing issue because, QNetworkAccessManager's finished signal does not have any parameter while you are connecting it with slot which takes Html5ApplicationViewer as parameter.
which is not compatible and thus you are getting warning.
If you want to have access to Html5ApplicationViewer pointer then you will need to assign or create pointer inside your NetworkManager class.

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.
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"

How can i download file from the internet in Qt?

I don't know what the problem is...The compiler (Qt) runs program without errors, but the file is not downloaded...
Can you tell me please tell what is wrong?
I made by example "download", which is located in the qt folder. The only difference is that they have is a console, and I have windows application.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtNetwork>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
class DownloadManager: public QObject
{
Q_OBJECT
QNetworkAccessManager manager;
QList<QNetworkReply *> currentDownloads;
public:
DownloadManager();
void doDownload(const QUrl &url);
QString saveFileName(const QUrl &url);
bool saveToDisk(const QString &filename, QIODevice *data);
public slots:
void execute();
void downloadFinished(QNetworkReply *reply);
};
#endif // MAINWINDOW_H
main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QtNetwork>
#include <QNetworkAccessManager>
#include <QStringList>
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QStringList>
#include <QTimer>
#include <QUrl>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
#if defined(Q_WS_S60)
w.showMaximized();
#else
w.show();
#endif
return a.exec();
}
DownloadManager::DownloadManager()
{
connect(&manager, SIGNAL(finished(QNetworkReply*)),
SLOT(downloadFinished(QNetworkReply*)));
}
void DownloadManager::doDownload(const QUrl &url)
{
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
currentDownloads.append(reply);
}
QString DownloadManager::saveFileName(const QUrl &url)
{
QString path = url.path();
QString basename = QFileInfo(path).fileName();
if (basename.isEmpty())
basename = "download";
if (QFile::exists(basename)) {
// already exists, don't overwrite
int i = 0;
basename += '.';
while (QFile::exists(basename + QString::number(i)))
++i;
basename += QString::number(i);
}
return basename;
}
bool DownloadManager::saveToDisk(const QString &filename, QIODevice *data)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
fprintf(stderr, "Could not open %s for writing: %s\n",
qPrintable(filename),
qPrintable(file.errorString()));
return false;
}
file.write(data->readAll());
file.close();
return true;
}
void DownloadManager::execute()
{
QStringList args = QCoreApplication::instance()->arguments();
args[0]="http://www.google.ru/images/srpr/logo3w.png";
QString arg=args[0];
QUrl url = QUrl::fromEncoded(arg.toLocal8Bit());
doDownload(url);
}
void DownloadManager::downloadFinished(QNetworkReply *reply)
{
QUrl url = reply->url();
if (reply->error()) {
fprintf(stderr, "Download of %s failed: %s\n",
url.toEncoded().constData(),
qPrintable(reply->errorString()));
} else {
QString filename = saveFileName(url);
if (saveToDisk(filename, reply))
printf("Download of %s succeded (saved to %s)\n",
url.toEncoded().constData(), qPrintable(filename));
}
currentDownloads.removeAll(reply);
reply->deleteLater();
if (currentDownloads.isEmpty())
// all downloads finished
QCoreApplication::instance()->quit();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
DownloadManager manager;
manager.execute();
QTimer::singleShot(0, &manager, SLOT(execute()));
}
The problem is at that point of your code:
void MainWindow::on_pushButton_clicked()
{
DownloadManager manager;
manager.execute();
}
QNetworkAccessManager is asynchronous, so it needs an event loop to do any downloading. But when the function on_pushButton_clicked() returns and gives the control back to the event loop, the QNetworkAccessManager is already destroyed, and didn't have the time to do anything.
When you add a QMessageBox in DownloadManager::execute, you are in fact running another event loop withing the slot on_pushButton_clicked(), and it gives the opportunity to the QNetworkAccessManager to do its work.
The correct solution would be to allocate DownloadManager dynamically, and eventually to make it destroy itself when it has finished all downloads.
void MainWindow::on_pushButton_clicked()
{
DownloadManager *manager = new DownloadManager(this);
manager->execute();
}
void DownloadManager::downloadFinished(QNetworkReply *reply)
{
...
if (currentDownloads.isEmpty())
this->deleteLater();
}