Qt从基于Qt示例的QThread下载文件不起作用
Posted
技术标签:
【中文标题】Qt从基于Qt示例的QThread下载文件不起作用【英文标题】:Qt Download Files from QThread Based On Qt Example Doesn't work 【发布时间】:2011-04-13 05:52:55 【问题描述】:您好,我构建了一个简单的示例,删除了所有不相关的代码,只剩下有问题的代码 一般来说,我有执行线程的应用程序,并且在这个线程工作者内部,我放置了应该下载超过 30 个文件的下载代码,这基于 Qt 给出的下载示例,问题是 QNetworkAccessManager 插槽从不调用。 你能告诉我我在这里做错了什么吗?
class MainWindowContainer : public QMainWindow
Q_OBJECT
public:
MainWindowContainer(QWidget *parent = 0);
public slots:
void InvokeDownloadThread();
private:
QPushButton *pushButtonInvokeThread;
PhotosDownloadWorker* pm_hotosDownloadWorker;
;
#include <QtGui>
#include "MainWindowContainer.h"
MainWindowContainer::MainWindowContainer(QWidget* parent) :
QMainWindow(parent)
pushButtonInvokeThread = new QPushButton(this);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(pushButtonInvokeThread);
setLayout(layout);
QObject::connect(pushButtonInvokeThread,SIGNAL(clicked()),this, SLOT(InvokeDownloadThread()));
void MainWindowContainer::InvokeDownloadThread()
pm_hotosDownloadWorker = new PhotosDownloadWorker(this);
pm_hotosDownloadWorker->Execute();
class PhotosDownloadWorker : public QThread
Q_OBJECT
public :
PhotosDownloadWorker(QObject *parent);
~PhotosDownloadWorker();
void Execute();
void append(const QStringList &urlList);
bool saveToDisk(const QString &filename, QIODevice *data);
QString saveFileName(const QUrl &url);
protected:
void run();
private:
bool m_abort;
QList<QNetworkReply *> currentDownloads;
QFile output;
QNetworkAccessManager* networkMgr ;
public slots:
void downloadFinished(QNetworkReply *reply);
void startNextDownload(const QUrl &url);
;
#include "PhotosDownloadWorker.h"
PhotosDownloadWorker::PhotosDownloadWorker(QObject *parent)
: QThread(parent)
m_abort = false;
networkMgr = new QNetworkAccessManager(this);
connect(networkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
PhotosDownloadWorker::~PhotosDownloadWorker()
m_abort = true;
wait();
void PhotosDownloadWorker::Execute()
m_abort = false;
start();
void PhotosDownloadWorker::run()
QStringList m_urlList;
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
// x 30
append(m_urlList);
void PhotosDownloadWorker::append(const QStringList &urlList)
foreach (QString url, urlList)
startNextDownload(QUrl::fromEncoded(url.toLocal8Bit()));
void PhotosDownloadWorker::startNextDownload(const QUrl &url)
QNetworkRequest request(url);
QNetworkReply *reply = networkMgr->get(request);
currentDownloads.append(reply);
bool PhotosDownloadWorker::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 PhotosDownloadWorker::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 succeeded (saved to %s)\n",
url.toEncoded().constData(), qPrintable(filename));
reply->deleteLater();
currentDownloads.removeAll(reply);
if (currentDownloads.isEmpty())
this->exit();
QString PhotosDownloadWorker::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;
//main
#include "MainWindowContainer.h"
int main(int argc, char *argv[])
QApplication app(argc, argv);
MainWindowContainer mainWindowContainer;
mainWindowContainer.show();
return app.exec();
【问题讨论】:
你用了什么例子?您能给我们指出一个在线链接吗? 【参考方案1】:尽管您在代码中调用了“networkMgr->get(request)”,但您的线程可能会在实际下载开始之前退出。尝试将“exec()”调用放在“QThread::run()”方法的最底部,以进入 QNetworkAccessManager 需要能够工作的线程中的事件循环。这也将防止线程过早完成其执行。您的代码如下所示:
void PhotosDownloadWorker::run()
QStringList m_urlList;
m_urlList.append("http://....xxxx......jpg");
m_urlList.append("http://....xxxx......jpg");
// x 30
append(m_urlList);
exec();
【讨论】:
是的答案,谢谢最后一个问题.. exec() 调用后如何终止线程最好的方法是什么? 您可以使用 QThread::quit() 或 QThread::exit()。使用最后一个,您可以传递结果代码以从 QThread::exec() 调用返回。通常我使用 QThread::quit()。因此,您甚至可以将最终下载完成()信号连接到 QThread::quit() 插槽。 你能举个我没看懂的例子吗 当我把这个->退出 currentDownloads.isEmpty() 它永远不会到达那里。 不确定你的意思。你能解释一下吗?【参考方案2】:我认为如果参数列表不匹配,它甚至不会将信号连接到插槽。请参阅调试器输出以获取有关运行时的警告(应用程序输出选项卡)。
所以,而不是
connect(networkMgr, SIGNAL(readyRead()), this, SLOT(downloadFinished(QNetworkReply*)));
做
connect(networkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
通过 QNetworkReply 的 error
signal 处理错误。在你get
之后,你就可以连接到信号了。
【讨论】:
以上是关于Qt从基于Qt示例的QThread下载文件不起作用的主要内容,如果未能解决你的问题,请参考以下文章