Hi, I got the error in the title running a class derived from QNetworkAccessManager to download and save files. It works fine except when requesting a large number of file (600~). Here the implementation (quite common):
FileDownloader
::FileDownloader(QObject *parent
) : QNetworkAccessManager(parent)
{
}
FileDownloader::~FileDownloader()
{
deleteLater();
}
void FileDownloader
::setPath(const QString &path
) {
mPath = path;
}
void FileDownloader
::setFileName(const QString &fileName
) {
mFileName = fileName;
}
void FileDownloader
::setUrl(const QString &url
) {
mUrl = url;
}
void FileDownloader::download()
{
file
->setFileName
(mPath
+ QDir::separator() + mFileName
);
if(file->exists())
if(!file->remove()) {
qDebug() << file->errorString();
return;
}
QNetworkRequest request;
request.
setUrl(QUrl(mUrl
));
reply = get(request);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64,qint64)));
connect(this, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
}
void FileDownloader::onFinished(QNetworkReply *reply)
{
switch(reply->error()) {
case QNetworkReply::NoError:
qDebug() << "Downloaded:" << file->fileName();
break;
default:
qDebug(reply->errorString().toLatin1());
}
if(file->isOpen()) {
file->close();
file->deleteLater();
}
}
void FileDownloader::onReadyRead()
{
file->write(reply->readAll());
}
void FileDownloader::onReplyFinished()
{
if(file->isOpen()) {
file->close();
file->deleteLater();
}
}
void FileDownloader::onDownloadProgress(qint64, qint64)
{
qDebug
(QString::number(bytesRead
).
toLatin1() + " - " + QString::number(bytesTotal
).
toLatin1());
}
FileDownloader::FileDownloader(QObject *parent) :
QNetworkAccessManager(parent)
{
}
FileDownloader::~FileDownloader()
{
deleteLater();
}
void FileDownloader::setPath(const QString &path)
{
mPath = path;
}
void FileDownloader::setFileName(const QString &fileName)
{
mFileName = fileName;
}
void FileDownloader::setUrl(const QString &url)
{
mUrl = url;
}
void FileDownloader::download()
{
file = new QFile;
file->setFileName(mPath + QDir::separator() + mFileName);
if(file->exists())
if(!file->remove()) {
qDebug() << file->errorString();
return;
}
file->open(QIODevice::WriteOnly);
QNetworkRequest request;
request.setUrl(QUrl(mUrl));
reply = get(request);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64,qint64)));
connect(this, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
}
void FileDownloader::onFinished(QNetworkReply *reply)
{
switch(reply->error()) {
case QNetworkReply::NoError:
qDebug() << "Downloaded:" << file->fileName();
break;
default:
qDebug(reply->errorString().toLatin1());
}
if(file->isOpen()) {
file->close();
file->deleteLater();
}
}
void FileDownloader::onReadyRead()
{
file->write(reply->readAll());
}
void FileDownloader::onReplyFinished()
{
if(file->isOpen()) {
file->close();
file->deleteLater();
}
}
void FileDownloader::onDownloadProgress(qint64, qint64)
{
qDebug(QString::number(bytesRead).toLatin1() + " - " + QString::number(bytesTotal).toLatin1());
}
To copy to clipboard, switch view to plain text mode
I'm calling it this way:
FileDownloader * downloader = new FileDownloader(this);
downloader->setUrl(/*...*/);
downloader->setPath(/*...*/);
downloader->setFileName(/*...*/);
downloader->download();
}
foreach(QString file, files) {
FileDownloader * downloader = new FileDownloader(this);
downloader->setUrl(/*...*/);
downloader->setPath(/*...*/);
downloader->setFileName(/*...*/);
downloader->download();
}
To copy to clipboard, switch view to plain text mode
Searching the web I read that a solution should be QRunnable, but I'm using it in the wrong way:
* had subclassed QRunnable:
class FileDownloader : public QNetworkAccessManager, public QRunnable
class FileDownloader : public QNetworkAccessManager, public QRunnable
To copy to clipboard, switch view to plain text mode
* renamed FileDownloader::download() in FileDownloader::run()
* modified calling routine:
FileDownloader * downloader = new FileDownloader(this);
downloader->setUrl(/*...*/);
downloader->setPath(/*...*/);
downloader->setFileName(/*...*/);
QThreadPool::globalInstance()->start(downloader); // <- new version
foreach(QString file, files) {
FileDownloader * downloader = new FileDownloader(this);
downloader->setUrl(/*...*/);
downloader->setPath(/*...*/);
downloader->setFileName(/*...*/);
QThreadPool::globalInstance()->start(downloader); // <- new version
To copy to clipboard, switch view to plain text mode
In console I got repetition of the following error:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is FileDownloader(0x13297e0), parent's thread is QThread(0x118c420), current thread is QThread(0x13525d0)
Any help will be very appreciated. Thanks.
Bookmarks