在下载短文件期间阻止Qt应用程序

时间:2008-10-30 16:06:01

标签: qt

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

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

文件很短,我的应用程序需要能够继续,所以我想确保下载是阻止的(如果文件未找到/不可用,则会在几秒钟后超时)。< / p>

我想使用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'。

有什么想法吗?

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

6 个答案:

答案 0 :(得分:5)

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

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

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

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

另外不要忘记刷新processHttpGetFile中的文件,因为它可能不在磁盘上。

答案 1 :(得分:4)

您可以直接进入调用processEvents

的循环,而不是使用线程
while (notFinished) {
   qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}

其中notFinished是可以从onRequestFinished广告位设置的标志。

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

答案 2 :(得分:3)

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

答案 3 :(得分:1)

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

但是,我还处理了一些事情:

  • 我必须调整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;
};

答案 4 :(得分:0)

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

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

答案 5 :(得分:-1)

给GUI一些时间等待线程然后放弃。

类似的东西:

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

或者...

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