qué - Bloquear una aplicación Qt durante la descarga de un archivo corto
configurar qué hará firefox cuando descargo archivos (6)
¿Qué le parece darle a la GUI una cantidad de tiempo para esperar el hilo y luego darse por vencido?
Algo como:
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait(10000); //give the thread 10 seconds to download
O...
¿Por qué la secuencia de la interfaz gráfica de usuario tiene que esperar para 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.
Estoy escribiendo una aplicación usando Qt4.
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é el tiempo después de 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 que crea el hilo 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?
Elegí implementar la solución de David, que parecía ser la más fácil.
Sin embargo, tuve que manejar algunas cosas más:
- Tuve que adaptar los valores enum QEventLoop para Qt4.3.3 (la versión que estoy usando);
- Tenía 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;
- Agregué 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) 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;
};
Un poco tarde pero: No use estos bucles de espera, la forma correcta es usar la señal de hecho () de QHttp.
La señal de solicitud finalizada de lo que he visto es solo para cuando su aplicación haya terminado la solicitud, los datos aún pueden estar en camino hacia abajo.
No necesita un hilo nuevo, solo configure el qhttp:
httpGetFile= new QHttp();
connect(httpGetFile, SIGNAL(done(bool)), this, SLOT(processHttpGetFile(bool)));
Además, no se olvide de vaciar el archivo en procesoHttpGetFile ya que es posible que no esté en el disco.
En lugar de utilizar un hilo, puede entrar en un bucle que llama a processEvents
:
while (notFinished) {
qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}
Donde no notFinished
es una bandera que se puede configurar desde la ranura onRequestFinished
.
ExcludeUserInput
garantizará que los eventos relacionados con la GUI se ignoren mientras se espera.
tienes que llamar a QThread::quit()
o exit()
si has terminado; de lo contrario, el hilo se ejecutará para siempre ...
Utilicé QNetworkAccsessManager por la misma necesidad. Debido a que esta clase gestiona las conexiones RFC base (6 procesos de mismo tiempo) y no-bloqueo.