I have a C++ Qt program that uses QThreadPool to process files in no more than MAX_THREAD_COUNT threads. And I'm having troubles with Qt::QueuedConnection. It looks like signals got lost. But with Qt::DirectConnection it works pretty perfect.
I'd be thankful if someone will explain what's going on.
UPDATE: This code works well in Qt, but not in Visual Studio 2005. In VS it stops after the first thread finished (but works with Qt::DirectConnection)
That's how it looks:
Manager.h:
#ifndef MANAGER_H
#define MANAGER_H
#include <QObject>
#include <QThreadPool>
#include <QDebug>
#include "threadbody.h"
class Manager : public QObject
{
Q_OBJECT
private:
QList<QString> processedfiles;
QList<QString> resultfiles;
bool ok;
QString lasterror;
public slots:
void addToProcessedFiles(const QString& filename);
void addToResultFiles(const QString& filename);
void setErrorMessage(const QString& message);
void startNewThread();
public:
bool startManager(const QString& firstfile);
explicit Manager(QObject *parent = 0);
~Manager();
};
#endif // MANAGER_H
ThreadBody.h:
#ifndef THREADBODY_H
#define THREADBODY_H
#include <QTemporaryFile>
#include <QRunnable>
#include <QTextStream>
#define MAX_THREAD_COUNT 4
class ThreadBody : public QObject, public QRunnable
{
Q_OBJECT
private:
QString filename;
public:
ThreadBody(const QString& filename);
~ThreadBody();
void run();
signals:
void sendResult(const QString& filename);
void sendFileName(const QString& filename);
void taskDone();
void threadError(const QString& message);
};
#endif // THREADBODY_H
Manager.cpp:
Manager::Manager(QObject *parent) :
QObject(parent)
{
ok=true;
QThreadPool::globalInstance()->setMaxThreadCount(MAX_THREAD_COUNT);
}
void Manager::addToProcessedFiles(const QString& filename)
{
processedfiles.push_back(filename);
if(QThreadPool::globalInstance()->activeThreadCount()<MAX_THREAD_COUNT)
startNewThread();
}
void Manager::addToResultFiles(const QString& filename)
{
resultfiles.push_back(filename);
}
void Manager::setErrorMessage(const QString& message)
{
ok=false;
lasterror=message;
}
void Manager::startNewThread()
{
if(processedfiles.isEmpty())
return;
if(!ok)
return;
QString filename=processedfiles.takeFirst();
ThreadBody* task=new ThreadBody(filename);
connect(task,SIGNAL(taskDone()),this,SLOT(startNewThread()),Qt::QueuedConnection);
connect(task,SIGNAL(sendResult(const QString&)),this,SLOT(addToResultFiles(const QString&)),Qt::QueuedConnection);
connect(task,SIGNAL(sendFileName(const QString&)),this,SLOT(addToProcessedFiles(const QString&)),Qt::QueuedConnection);
connect(task,SIGNAL(threadError(const QString&)),this,SLOT(setErrorMessage(const QString&)),Qt::QueuedConnection);
qDebug()<<"thread starts";
QThreadPool::globalInstance()->start(task);
}
bool Manager::startManager(const QString& firstfile)
{
processedfiles.push_back(firstfile);
startNewThread();
QThreadPool::globalInstance()->waitForDone();
return ok;
}
Manager::~Manager(){}
ThreadBody.cpp:
#include "threadbody.h"
#include <QThreadPool>
ThreadBody::ThreadBody(const QString& filename)
{
this->filename=filename;
}
ThreadBody::~ThreadBody(){}
void ThreadBody::run()
{
QFile file(filename);
if(!file.open(QIODevice::ReadOnly))
{
QString message=QString("Thread can't open file=%1: %2").arg(filename).arg(file.errorString());
emit threadError(message);
emit taskDone();
return;
}
QTextStream in(&file);
QTemporaryFile newProcessedFile;
newProcessedFile.setAutoRemove(false);
if(!newProcessedFile.open())
{
QString message="Thread can't open temporary file";
emit threadError(message);
emit taskDone();
return;
}
QTextStream out(&newProcessedFile);
QTemporaryFile resultFile;
resultFile.setAutoRemove(false);
if(!resultFile.open())
{
QString message="Thread can't open temporary file";
emit threadError(message);
emit taskDone();
return;
}
QTextStream resultOut(&resultFile);
while(!in.atEnd())
{
//!---time consuming task---!//
//example//
QString currentLine=in.readLine();
out<<currentLine;
resultOut<<currentLine;
}
resultFile.close();
newProcessedFile.close();
file.remove();
emit sendResult(resultFile.fileName());
emit sendFileName(newProcessedFile.fileName());
emit taskDone();
}
main.cpp:
#include <QCoreApplication>
#include "manager.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Manager manager;
QString filename="C:/airtest/ask.cpp";
manager.startManager(filename);
return a.exec();
}
Related
I've been having this problem for few weeks, still didn't found a solution anywhere. I did everything I could to find the problem, everything looks good but for some reason it doesn't work.
I tested the connection, between the loginFailed() signal, and handleLoginFailed() slot, it returned True, printed the object info, it shows the connections. Tried different Qt::connectionTypes, nothing works.
The two objects are defined bellow.
LoginService.h
#ifndef LOGINSERVICE_H
#define LOGINSERVICE_H
#include <QObject>
#include <QVariant>
#include "libs/qubeapi/QubeAPI.h"
#include "libs/qubeapi/LoginCommand.h"
#include "libs/qubeapi/APIBridge.h"
#include "libs/mge-users/User.h"
#include "libs/mge-users/permissionfactory.h"
#include "Utils/serverstate.h"
#include "Utils/singleton.h"
#include "Utils/baseservice.h"
class LoginService : public QObject
{
Q_OBJECT
QubeAPI* api;
APIBridge* bridge;
LoginCommand* loginCmd;
QString m_userType;
QString m_firstName;
QString m_lastName;
User *m_user;
public:
explicit LoginService(QObject *parent = nullptr);
Q_PROPERTY(QString userType READ userType WRITE setUserType NOTIFY userTypeChanged)
Q_PROPERTY(QString firstName READ firstName WRITE setFirstName NOTIFY firstNameChanged)
Q_PROPERTY(QString lastName READ lastName WRITE setLastName NOTIFY lastNameChanged)
Q_PROPERTY(User* user READ user WRITE setUser NOTIFY userChanged)
const QString &userType() const;
void setUserType(const QString &newUserType);
const QString &firstName() const;
void setFirstName(const QString &newFirstName);
const QString &lastName() const;
void setLastName(const QString &newLastName);
User *user() const;
void setUser(User *newUser);
signals:
void success(QString token);
void loginFailed();
void userTypeChanged();
void firstNameChanged();
void lastNameChanged();
void staffLogout();
void userTypeRecived();
void userChanged();
public slots:
void requestLogin(QString userName, QString password);
void loginResponse(QString jsonData);
void doClose();
void prepareGetUserType();
void loadUserType(QString jsonData);
};
#endif // LOGINCONTROLLER_H
The function that emits the signal:
void LoginService::loginResponse(QString jsonData)
{
QSignalSpy spy(this,SIGNAL(loginFailed()));
if(jsonData == "") {
emit Singleton<ServerState>::GetInstance().offlineServer();
return;
}
QJsonDocument doc = QJsonDocument::fromJson(jsonData.toUtf8());
QString token = doc["data"]["tokenAuth"]["token"].toString();
if(!token.isEmpty()) {
UserSession::getInstance()->setAuthToken(token);
emit success(token);
prepareGetUserType();
} else {
qDebug() << "Urmeaza eroare";
QString errorMsg = doc["errors"][0]["message"].toString();
emit loginFailed();
qDebug() << spy.count();
}
}
The controller class that has the slot:
#ifndef LOGINCONTROLLER_H
#define LOGINCONTROLLER_H
#include <Utils/basecontroller.h>
#include <Utils/enginefactory.h>
#include <Utils/singleton.h>
#include <QQuickWindow>
#include <QQuickItem>
#include <QThread>
#include <QProperty>
#include <QQmlProperty>
#include "loginservice.h"
#include "draggableviewhelper.h"
#include <QMouseEvent>
class LoginController : public BaseController
{
Q_OBJECT
private:
QQuickWindow* window;
QQuickItem* login;
QQuickItem* userTextField;
QQuickItem* passwordTextField;
DraggableViewHelper* draggableViewHelper;
QQuickItem* mouseArea;
LoginService* service;
QPointF lastMousePosition;
public:
explicit LoginController(QObject *parent = nullptr);
// BaseController interface
void initialize();
// void setService(BaseService* s);
void setService(LoginService* s);
void setLastMousePosition(QPointF lastMousePosition);
public slots:
void handleLoginResponseSuccess(QString loginResponse);
void handleLoginResponseFailed();
void handlePositionChanged();
void handleLogout();
};
#endif // LOGINCONTROLLER_H
The initializer methods
void LoginController::initialize()
{
this->engine = Singleton<EngineFactory*>::GetInstance()->createEngine("qrc:/qml/LoginWindow.qml");
this->window = qobject_cast<QQuickWindow*>(this->engine->rootObjects().first());
// Create a draggable view helper, use window as input
// Get the view from the engine
this->draggableViewHelper = new DraggableViewHelper(this->window);
this->window->setFlags(Qt::Window | Qt::FramelessWindowHint);
this->login = window->findChild<QQuickItem*>("login");
this->userTextField = QQmlProperty::read(this->login,"user").value<QQuickItem*>();
this->passwordTextField = QQmlProperty::read(this->login,"password").value<QQuickItem*>();
// Set the mouseArea with the mainMouseArea item of the window
this->mouseArea = window->findChild<QQuickItem*>("mainMouseArea");
// Connect onClicked from mouse area, to handleMove of this
QObject::connect(this->mouseArea,SIGNAL(positionMoved()),this,SLOT(handlePositionChanged()));
}
void LoginController::setService(LoginService *s)
{
this->service = s;//new LoginService;
connect(this->service,SIGNAL(loginFailed()),this,SLOT(handleLoginResponseFailed()));
connect(this->service,SIGNAL(success(QString)),this,SLOT(handleLoginResponseSuccess(QString)));
connect(login,SIGNAL(doLogin(QString,QString)),this->service,SLOT(requestLogin(QString,QString)));
this->dumpObjectInfo();
this->service->dumpObjectInfo();
}
The slot
void LoginController::handleLoginResponseFailed()
{
qDebug() << "Failed";
QQmlProperty::write(this->userTextField,"state",QVariant::fromValue(QString{"default-error"}));
QQmlProperty::write(this->passwordTextField,"state",QVariant::fromValue(QString{"password-error"}));
}
This is the main.cpp file, where the objects are created
QApplication app1(argc, argv);
LoginController* loginCtrl = new LoginController;
LoginService* loginService = new LoginService;
QObject::connect(loginService, &LoginService::userTypeRecived,[&](){
qDebug() << "Failed to login";
});
qDebug() << loginService;
loginCtrl->initialize();
loginCtrl->setService(loginService);
//This will trigger the signal
// loginService->loginResponse("{\"errors\":[{\"message\":\"Please enter valid credentials\",\"locations\":[{\"line\":1,\"column\":12}],\"path\":[\"tokenAuth\"]}],\"data\":{\"tokenAuth\":null}}");
return app1.exec();
I don't know what the issue with this code, the syntax I have used for connecting the signals and sort looks correct but for some reason I keep getting this error
error: static assertion failed: Signal and slot arguments are not compatible.
# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
^
this is the code for the header file
include <QString>
#include <QStringList>
#include <QTextStream>
class filereader : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString filename READ getFileName WRITE setFileName NOTIFY fileNameChanged)
Q_PROPERTY(QString output READ getOutput)
Q_PROPERTY(QString error READ getErrorString)
explicit filereader(QObject *parent = 0);
QString getFileName();
QString getOutput();
QString getErrorString();
void setFileName(const QString &fileName);
Q_INVOKABLE void readFile(); // this allows us to use this is as a function so we could do something like onClicked{ <text_id>.text = <file_reader_id>.readFile() }
signals:
void fileNameChanged();
void outputChanged(QString &Output);
void gotError(QString &&err);
void errorSignal();
protected slots:
void handleOut(QString &output);
void handleError(QString &err);
private:
QString fileName;
QString output;
QString error;
};
#endif // FILEREADER_H
this is the code for the source file
#include "filereader.h"
filereader::filereader(QObject *parent):
QObject(parent)
{
connect(this,&filereader::gotError,this,&filereader::handleError);
connect(this,&filereader::outputChanged,this,&filereader::handleOut);
}
QString filereader::getFileName()
{
return this->fileName;
}
QString filereader::getOutput()
{
return this->output;
}
QString filereader::getErrorString()
{
return this->error;
}
void filereader::setFileName(const QString &fileName)
{
if(this->fileName == fileName)
return;
this->fileName = fileName;
emit fileNameChanged();
}
void filereader::readFile()
{
QFile file(this->fileName);
if (file.open(QIODevice::ReadOnly))
{
QTextStream in(&file);
while (!in.atEnd())
{
QString line = in.readAll();
outputChanged(line);
qDebug() << line;
}
file.close();
file.flush(); // this flushes the file stream
}else{
gotError("Could not open the file!");
}
}
void filereader::handleOut(QString &output)
{
if(this->output == output)
return;
this->output = output;
}
void filereader::handleError(QString &err)
{
if(this->error == err)
return;
this->error = err;
emit errorSignal();
}
I'm new to Qt and Qml so please help me understand the issue. Thanks :)
How to catch incorrect link errors? For example:
ftp://cddis.gsfc.nasa.gov/pub/slr/data/npt_crd/gracea/2010/gracea_20100101.npt.Z
-- this is incorrect link
Why doesn't any error signal work? Or How to determine the correct links? Please, write an example of correct work with errors.
#ifndef WIDGET_H
#define WIDGET_H
#include "Downloader.h"
#include <QWidget>
#include <QNetworkReply>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void onDownloadButtonClicked();
void onSelectTargetFolderButtonClicked();
void onCancelButtonClicked();
void onUpdateProgress(qint64 bytesReceived, qint64 bytesTotal);
void onResult(QNetworkReply *reply);
private:
Ui::Widget *ui;
Downloader m_downloader;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include "ui_Widget.h"
#include <QFileDialog>
#include <QStandardPaths>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->downloadPushButton, &QPushButton::clicked, this, &Widget::onDownloadButtonClicked);
connect(ui->selectTargetFolderPushButton, &QPushButton::clicked, this, &Widget::onSelectTargetFolderButtonClicked);
connect(ui->cancelPushButton, &QPushButton::clicked, this, &Widget::onCancelButtonClicked);
connect(&m_downloader, &Downloader::updateDownloadProgress, this, &Widget::onUpdateProgress);
connect(&m_downloader.manager, &QNetworkAccessManager::finished, this, &Widget::onResult);
}
Widget::~Widget()
{
delete ui;
}
void Widget::onDownloadButtonClicked()
{
m_downloader.get(ui->targetFolderLineEdit->text(), ui->urlLineEdit->text());
}
void Widget::onSelectTargetFolderButtonClicked()
{
QString targetFolder = QFileDialog::getExistingDirectory(this,
tr("Select folder"),
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
ui->targetFolderLineEdit->setText(targetFolder);
}
void Widget::onCancelButtonClicked()
{
m_downloader.cancelDownload();
ui->downloadProgressBar->setMaximum(100);
ui->downloadProgressBar->setValue(0);
}
void Widget::onUpdateProgress(qint64 bytesReceived, qint64 bytesTotal)
{
ui->downloadProgressBar->setMaximum(bytesTotal);
ui->downloadProgressBar->setValue(bytesReceived);
}
void Widget::onResult(QNetworkReply *reply)
{
if (reply->error()) {
qDebug() << "Error";
qDebug() << reply->error();
} else {
qDebug() << "Done";
}
}
Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QNetworkAccessManager>
#include <QNetworkReply>
//class QNetworkReply;
class QFile;
class Downloader : public QObject
{
Q_OBJECT
using BaseClass = QObject;
public:
explicit Downloader(QObject* parent = nullptr);
bool get(const QString& targetFolder, const QUrl& url);
QNetworkReply* currentReply {nullptr};
QNetworkAccessManager manager;
QString fullName;
public slots:
void cancelDownload();
signals:
void updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
private slots:
void onReadyRead();
void onReply(QNetworkReply* reply);
void errorSlot(QNetworkReply::NetworkError er);
private:
QFile* m_file {nullptr};
};
#endif // DOWNLOADER_H
Downloader.cpp
#include "Downloader.h"
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QFile>
#include <QDir>
Downloader::Downloader(QObject* parent) :
BaseClass(parent)
{
connect(&manager, &QNetworkAccessManager::finished, this, &Downloader::onReply);
}
bool Downloader::get(const QString& targetFolder, const QUrl& url)
{
qDebug() << "get";
if (targetFolder.isEmpty() || url.isEmpty())
{
return false;
}
fullName = targetFolder + QDir::separator() + url.fileName();
m_file = new QFile(fullName);
if (!m_file->open(QIODevice::WriteOnly))
{
delete m_file;
m_file = nullptr;
return false;
}
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
currentReply = manager.get(request);
connect(currentReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
this, &Downloader::errorSlot);
connect(currentReply, &QNetworkReply::readyRead, this, &Downloader::onReadyRead);
connect(currentReply, &QNetworkReply::downloadProgress, this, &Downloader::updateDownloadProgress);
return true;
}
void Downloader::onReadyRead()
{
qDebug() << "onReadyRead";
if (m_file)
{
m_file->write(currentReply->readAll());
}
}
void Downloader::cancelDownload()
{
qDebug() << "cancelDownload";
if (currentReply)
{
currentReply->abort();
}
}
void Downloader::onReply(QNetworkReply* reply)
{
qDebug() << "onReply";
if (reply->error() == QNetworkReply::NoError)
{
m_file->flush();
m_file->close();
}
else
{
m_file->remove();
}
delete m_file;
m_file = nullptr;
reply->deleteLater();
}
void Downloader::errorSlot(QNetworkReply::NetworkError er)
{
qDebug() << er;
}
I am trying to implement http://developer.nokia.com/community/wiki/Creating_an_HTTP_network_request_in_Qt and my code compiles without error but does not function. I have a warning that reply in "QNetworkReply* reply = nam->get(QNetworkRequest(url));" is not being used. I am sure this is my error and I am not setting up my HTTP GET correctly, but I am unsure of how to correct it.
//coreEng.h
#ifndef COREENG_H
#define COREENG_H
#include <QObject>
#include <QNetworkAccessManager>
class coreEng : public QObject
{
Q_OBJECT
public:
//coreEng(QObject);
coreEng(QObject *parent = 0) :
QObject(parent)
{
nam = new QNetworkAccessManager();
}
private slots:
public slots:
void connect();
void url(QNetworkReply *reply);
void finishedSlot(QNetworkReply* reply);
private:
QNetworkAccessManager* nam;
};
#endif // COREENG_H
//coreEng.cpp
"coreeng.h"
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QImageReader>
void coreEng::connect(){
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(finishedSlot(QNetworkReply*)));
}
void coreEng::url(QNetworkReply*){
QUrl url("http://www.nyctelecomm.com");
QNetworkReply* reply = nam->get(QNetworkRequest(url));
}
void coreEng::finishedSlot(QNetworkReply* reply){
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (reply->error() == QNetworkReply::NoError)
{
QImageReader imageReader(reply);
QImage pic = imageReader.read();
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
}
else
{
}
//delete reply();
}
//main.cpp
#include <QCoreApplication>
#include "coreeng.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
coreEng mConnect;
mConnect.connect();
return a.exec();
}
changed void coreEng::url(QNetworkReply*) to void coreEng::url()
changed void url(QNetworkReply *reply); to void url();
added mConnect.url(); to main.cpp and I could see the http packet with wireshark exit the NIC and begin the session.
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();
}