2008-10-30 60 views
8

我正在使用Qt4编写应用程序。在下载短文件时阻止Qt应用程序

我需要从给定的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

而不是使用一个线程你可以进入一个循环调用processEvents

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

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

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

3

你必须调用QThread::quit()exit()如果你做 - 否则你的线程将永远运行下去......

-1

如何给GUI一定的时间等待的线程上,然后放弃。

喜欢的东西:

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

或者......

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

1

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

然而,我不得不处理一些事情:

  • 我不得不为Qt4.3适应QEventLoop枚举值。3(我正在使用的版本);
  • 我不得不跟踪请求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; 
}; 
+0

谢谢,这有帮助 – aehlke 2010-06-13 08:08:32

5

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

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

你并不需要一个新的线程,只设置了QHTTP:

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

而且不要忘了刷新文件中processHttpGetFile,因为它可能不是所有会在磁盘上。

相关问题