8

我正在使用 Qt4 编写应用程序。

我需要从给定的 http 地址下载一个非常短的文本文件。

该文件很短,我的应用程序需要它才能继续,所以我想确保下载被阻止(或者如果文件未找到/不可用,几秒钟后将超时)。

我想使用 QHttp::get(),但这是一种非阻塞方法。

我想我可以使用一个线程:我的应用程序会启动它,然后等待它完成。当文件下载或超时后,线程将处理下载并退出。

但我不能让它工作:

class JSHttpGetterThread : public QThread
{
  Q_OBJECT

public:
  JSHttpGetterThread(QObject* pParent = NULL);
  ~JSHttpGetterThread();

  virtual void run()
  {
    m_pHttp = new QHttp(this);
    connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));

    m_pHttp->setHost("127.0.0.1");
    m_pHttp->get("Foo.txt", &m_GetBuffer);
    exec();
  }

  const QString& getDownloadedFileContent() const
  {
    return m_DownloadedFileContent;
  }

private:
  QHttp* m_pHttp;

  QBuffer m_GetBuffer;
  QString m_DownloadedFileContent;

private slots:
  void onRequestFinished(int Id, bool Error)
  {
    m_DownloadedFileContent = "";
    m_DownloadedFileContent.append(m_GetBuffer.buffer());
  }
};

在创建线程以启动下载的方法中,这是我正在做的事情:

JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait();

但这不起作用,我的应用程序一直在等待。它看起来点亮了插槽“onRequestFinished”从未被调用过。

任何的想法 ?

有没有更好的方法来做我想做的事情?

4

6 回答 6

5

有点晚了,但是:不要使用这些等待循环,正确的方法是使用来自 QHttp 的 done() 信号。

我所看到的 requestFinished 信号仅适用于您的应用程序完成请求时,数据可能仍在下降中。

您不需要新线程,只需设置 qhttp:

httpGetFile= new QHttp();
connect(httpGetFile, SIGNAL(done(bool)), this, SLOT(processHttpGetFile(bool)));

也不要忘记在 processHttpGetFile 中刷新文件,因为它可能并不都在磁盘上。

于 2008-11-05T15:39:47.283 回答
4

您可以直接进入一个调用的循环,而不是使用线程processEvents

while (notFinished) {
   qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}

notFinished可以从onRequestFinished插槽设置的标志在哪里。

ExcludeUserInput将确保在等待时忽略与 GUI 相关的事件。

于 2008-10-31T07:44:03.367 回答
3

你必须打电话QThread::quit()或者exit()如果你完成了 - 否则你的线程将永远运行......

于 2008-10-30T17:04:21.333 回答
1

我选择实施大卫的解决方案,这似乎是最简单的。

但是,我处理了更多的事情:

  • 我不得不为 Qt4.3.3(我正在使用的版本)调整 QEventLoop 枚举值;
  • 我必须跟踪请求 ID,以确保在下载请求完成时退出 while 循环,而不是在另一个请求完成时退出;
  • 我添加了一个超时,以确保在出现任何问题时退出 while 循环。

这是(或多或少)伪代码的结果:

class BlockingDownloader : public QObject
{
  Q_OBJECT
public:
    BlockingDownloaderBlockingDownloader()
    {
      m_pHttp = new QHttp(this);
      connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
    }

    ~BlockingDownloader()
    {
      delete m_pHttp;
    }

    QString getFileContent()
    {
      m_pHttp->setHost("www.xxx.com");
      m_DownloadId = m_pHttp->get("/myfile.txt", &m_GetBuffer);

      QTimer::singleShot(m_TimeOutTime, this, SLOT(onTimeOut()));
      while (!m_FileIsDownloaded)
      {
        qApp->processEvents(QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents);
      }
      return m_DownloadedFileContent;
    }

private slots:
    void BlockingDownloader::onRequestFinished(int Id, bool Error)
    {
      if (Id == m_DownloadId)
      {
        m_DownloadedFileContent = "";
        m_DownloadedFileContent.append(m_GetBuffer.buffer());
        m_FileIsDownloaded = true;
      }
    }

  void BlockingDownloader::onTimeOut()
  {
    m_FileIsDownloaded = true;
  }

private:
  QHttp* m_pHttp;
  bool m_FileIsDownloaded;
  QBuffer m_GetBuffer;
  QString m_DownloadedFileContent;
  int m_DownloadId;
};
于 2008-11-03T12:34:51.200 回答
0

我出于同样的需要使用了 QNetworkAccsessManager。因为这个类管理连接 RFC 基础(6 个进程同时)和非阻塞。

http://qt-project.org/doc/qt-4.8/qnetworkaccessmanager.html

于 2014-10-15T08:15:53.700 回答
-1

给 GUI 一些时间来等待线程然后放弃怎么样。

就像是:

JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait(10000);  //give the thread 10 seconds to download

或者...

为什么 GUI 线程必须等待“下载器线程”?当应用程序启动时,创建下载线程,将 finished() 信号连接到其他对象,启动下载线程,然后返回。当线程完成后,它将向另一个可以恢复您的进程的对象发出信号。

于 2008-10-30T20:24:05.330 回答