2008-10-30 3 views
8

Estoy escribiendo una aplicación usando Qt4.Bloquear una aplicación Qt durante la descarga de un archivo corto

Necesito descargar un archivo de texto muy corto desde una dirección http dada.

El archivo es corto y se necesita para que mi aplicación pueda continuar, por lo que me gustaría asegurarme de que la descarga sea de bloqueo (o agotaré unos segundos si el archivo no se encuentra/no está disponible).

Quería usar QHttp :: get(), pero este es un método que no bloquea.

Pensé que podría usar un hilo: mi aplicación lo iniciaría y esperaría a que termine. El hilo manejaría la descarga y se cerraría cuando se descargue el archivo o después de un tiempo de espera.

Pero no puedo hacer que funcione:

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()); 
    } 
}; 

En el método de la creación de la rosca para iniciar la descarga, esto es lo que estoy haciendo:

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

Pero eso no funciona y mi aplicación sigue esperando. Parece iluminado, nunca se llama a la ranura 'onRequestFinished'.

¿Alguna idea?

¿Hay una mejor manera de hacer lo que estoy tratando de hacer?

Respuesta

4

En lugar de utilizar un hilo sólo puede entrar en un bucle que llama processEvents:

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

Dónde notFinished es una bandera que puede ser ajustado de la ranura onRequestFinished.

El ExcludeUserInput se asegurará de que los eventos relacionados con la GUI se ignoran mientras se espera.

3

usted tiene que llamar o QThread::quit()exit() si ha terminado - de lo contrario el hilo se ejecutará siempre ...

-1

¿Qué hay de dar la interfaz gráfica de una cierta cantidad de tiempo para esperar en la rosca y luego abandonar.

Algo así como:

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

O ...

¿Por qué el hilo de interfaz gráfica de usuario que tenga que esperar a que el "hilo de descarga" en absoluto? Cuando la aplicación se active cree la secuencia de descarga, conecte la señal finished() a algún otro objeto, inicie la secuencia de descarga y vuelva. Cuando el hilo haya terminado, señalará al otro objeto que puede reanudar su proceso.

1

Elegí implementar la solución de David, que parecía ser la más fácil.

Sin embargo, tuve que manejar un par de cosas más:

  • tuve que adaptar los valores de enumeración QEventLoop para Qt4.3.3 (la versión que estoy usando);
  • Tuve que rastrear el Id. De la solicitud, para asegurarme de salir del ciclo while cuando la solicitud de descarga haya finalizado, y no cuando haya terminado otra solicitud;
  • He añadido un tiempo de espera, para asegurarme de salir del ciclo while si hay algún problema.

Aquí está el resultado como (más o menos) de pseudo-código:

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

gracias, esto ayudó – aehlke

5

Un poco tarde pero: no utilizan estos esperan bucles, la forma correcta es utilizar el hecho() señal de QHttp.

La señal de finalización de la solicitud de lo que he visto es solo para cuando su aplicación ha terminado la solicitud, los datos pueden estar en su camino hacia abajo.

que no es necesario un nuevo hilo, acaba de configurar el qhttp:

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

Tampoco se olvide para eliminar el archivo en processHttpGetFile ya que no podría estar todos en el disco.

Cuestiones relacionadas