Блокировка приложения Qt во время загрузки короткого файла - PullRequest
8 голосов
/ 30 октября 2008

Я пишу приложение, используя Qt4.

Мне нужно загрузить очень короткий текстовый файл с указанного http-адреса.

Файл короткий и необходим для продолжения работы моего приложения, поэтому я хочу убедиться, что загрузка блокируется (или истечет время ожидания через несколько секунд, если файл не найден / недоступен). 1005 *

Я хотел использовать 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 ]

5 голосов
/ 05 ноября 2008

Немного поздно, но: Не используйте эти циклы ожидания, правильный способ - использовать сигнал done () из QHttp.

Сигнал requestFinished, который я видел, предназначен только для того, чтобы, когда ваше приложение завершило запрос, данные все еще находились в процессе.

Вам не нужна новая тема, просто настройте qhttp:

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

Также не забудьте сбросить файл в processHttpGetFile, так как он может находиться не на диске.

4 голосов
/ 31 октября 2008

Вместо использования потока вы можете просто войти в цикл, который вызывает processEvents:

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

Где notFinished - флаг, который можно установить из слота onRequestFinished.

ExcludeUserInput гарантирует, что связанные с GUI события будут игнорироваться во время ожидания.

3 голосов
/ 30 октября 2008

вам нужно позвонить QThread::quit() или exit(), если вы закончили - иначе ваш поток будет работать вечно ...

1 голос
/ 03 ноября 2008

Я решил реализовать решение Дэвида, которое казалось самым простым.

Однако мне пришлось справиться еще с несколькими вещами:

  • Мне пришлось адаптировать значения перечисления QEventLoop для Qt4.3.3 (версия, которую я использую);
  • Мне пришлось отслеживать идентификатор запроса, чтобы убедиться, что выход из цикла 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;
};
0 голосов
/ 15 октября 2014

Я использовал QNetworkAccsessManager для той же необходимости. Потому что этот класс управляет соединениями базы RFC (6 процессов одновременно) и неблокирующими.

http://qt -project.org / док / кварта-4,8 / qnetworkaccessmanager.html

0 голосов
/ 30 октября 2008

Как насчет того, чтобы дать GUI некоторое время для ожидания в потоке, а затем сдаться.

Что-то вроде:

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

Или ...

Почему поток GUI вообще должен ждать "потока загрузчика"? Когда приложение запускается, создайте поток загрузчика, подключите сигнал finish () к другому объекту, запустите поток загрузчика и вернитесь. Когда поток завершится, он подаст сигнал другому объекту, который может возобновить ваш процесс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...