2008-10-30 40 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,因爲它可能不是所有會在磁盤上。

相關問題