Cómo aprender cuda en un mes…

…y otros cuentos

Crear una ventana de carga en un hilo y comunicarla con un Widget de QT

con un comentario

Desde hace tiempo tengo un botón que lanza un proceso externo (concretamente ANSYS) y normalmente tarda varios minutos. Esto provoca que la interfaz se congele hasta que el proceso termina, con la consiguiente falta de información, bloqueo de ventanas…

Crear un hilo con QT

Como parece que ahora la aplicación tiene que servir para otras personas, era hora de hacer eso bien y tener una pantallita típica de “Running…” con su botón de Abort y todo esto sin bloquear la interfaz, claro. Para eso tenemos que usar hilos y QT tiene sus propios hilos: QThread.

La creación de una clase que sea hilo simplemente debe heredar de QThread, aquí hay una muestra básica:

class MiHilo: public QThread{
  private:
  //mis variables
  public:
  void run(){ //método que se ejecutará al hacer start
    //hacer cosas
  }
};

int main(){
  MiHilo th;
  th.start(); //lanza el hilo
  th.wait(); //espera a que el hilo termine
}

Aunque lo mejor es leerse la documentación de QThread para ver todos los métodos.

Mostrar una ventana de carga

Ahora lo interesante es tener una ventanita que indique que el hilo está haciendo cosas y que bloquee la ejecución del programa principal hasta que se cierre esa ventana, ya sea por acción del usuario o porque el proceso lanzado ha terminado. Para sacar una ventana modal (bloqueante) lo más sencillo es lo siguiente:

th.start();

loadingBox.setText("Process is running...");
loadingBox.setWindowTitle("Please wait");
loadingBox.setWindowModality(Qt::ApplicationModal);
loadingBox.setStandardButtons(QMessageBox::Abort);
loadingBox.setIcon(QMessageBox::Warning);

int r=loadingBox.exec();

th.wait();

Esta ventana tiene además un botón de Abort con el que podemos hacer lo que queramos al mirar el valor de la variable r. La ventana, al ser modal, no permite que el programa principal ejecute el wait() hasta que se haya cerrado, en caso contrario, el programa principal seguiría su ejecución de forma independiente.

Cerrar la ventana con un evento

Siguiente paso: que la ventana se cierre cuando el proceso termine. Aunque pueda parecer sencillo, es más complicado de lo que parece puesto que QT impide enviar eventos directamente entre hilos distintos. Por lo tanto, la clase MiHilo no podrá mandar un close() directamente a loadingBox. Según parece se puede montar un sistema con signals y slots que permitan mandar una señal de cierre, pero no lo he conseguido…

Lo que sí he conseguido es enviar un evento desde un hilo distinto al de la aplicación principal mediante postEvent. Esta función permite mandar un evento a la cola de eventos del objeto receptor definido, entonces, al finalizar la ejecución del programa que está lanzandose en el hilo, se pasa lo siguiente:

QApplication::postEvent(&padre->loadingBox,new QCloseEvent()); //padre es la clase que contiene el objeto loadingBox y que el hilo debe conocer

Y, aunque hay un new, el evento se borra automáticamente al procesarse, si lo borramos después con un delete tendremos errores difíciles de entender.

Todo esto nos ha permitido lanzar un proceso en un hilo, mostrar una ventana modal que interrumpa el programa principal pero sin bloquear la interfaz y cerrarla al terminar la ejecución del proceso.

Advertisement

Escrito por cudagpu

28 febrero 2011 a 10:38

Escrito en Qt

Una respuesta

Suscríbete a los comentarios mediante RSS.

  1. Excelente y muy oportuno post, realmente me has ahorrado el periodo mas difícil de algo nuevo: Empezar…
    Espero en pocos días (bueno o noches) implementarlo en mi aplicación, en la cual realizo el entrenamiento de una red neuronal, pero se ve como el ANSYS que comentas, parece bloqueado.. jeje
    Gracias.

    Thanatos

    3 marzo 2011 a 04:48


Deja un comentario

Fill in your details below or click an icon to log in:

Logo de WordPress.com

You are commenting using your WordPress.com account. Log Out / Cambiar )

Twitter picture

You are commenting using your Twitter account. Log Out / Cambiar )

Facebook photo

You are commenting using your Facebook account. Log Out / Cambiar )

Connecting to %s

Seguir

Get every new post delivered to your Inbox.