jueves, 7 de junio de 2012

Eventos en Qt - Signals & Slots

Buenas. Para hoy, el caso que nos ocupa es poder crear eventos en una aplicación hecha en Qt. Entiéndase por evento un proceso a realizar como respuesta a una acción realizada por el usuario, como por ejemplo: pulsar un botón.

Bien, Qt introdujo como bandera el sistema Signals & Slots, en español: señales y…pues, slots xD (no sé qué concepto se apegue más en español, pero aquí decimos slots también para denotar una ranura o lugar donde encajar algo). En fin, este sistema es original de Qt y resulta muy fácil de usar para manejar los eventos en nuestras aplicaciones.

Signals son señales que emiten los objetos en Qt para comunicar a otro objeto que algún evento X ha ocurrido. Cada objeto en qt tiene sus propias señales y sus propios slots, aunque a través de la herencia, podemos agregar nuestros propios slots y señales. Para conectar una señal con un slot se sigue esta sintaxis:



connect (objetoEmisor, SIGNAL(señalDelEmisor()), objetoReceptor, SLOT(slotDelReceptor())); 

Para emitir una señal, la sintaxis es:

emit(funcionSeñal()); // esta función forma parte de una clase

Y para desconectar una señal de un slot:

disconnect(objetoEmisor, SIGNAL(señalDelEmisor()),objetoReceptor, SLOT(slotDelReceptor()));

Así, por ejemplo, se puede conectar la señal clicked() de un botón (de la clase QPushButton) al slot de una clase propia que crea un dialogo de usuario o una ventana o al slot de algún otro widget. Y un slot termina siendo una función común y corriente perteneciente a una clase que realizara alguna acción y que solo se ejecutara cuando las señales conectadas a él, se emitan. Y las señales igualmente, son funciones que pertenecen a una clase. Estas funciones pueden ser públicas, protegidas o privadas. Hay que destacar que estas conexiones se pueden realizar en tiempo de ejecución y también se pueden deshacer en tiempo de ejecución. No puede hacerse conexiones sin haber declarado el macro Q_OBJECT.

Para hoy, vamos a crear un proyecto donde exista un botón en la ventana principal de nuestra app, y que, al presionarlo, nos muestre otra ventana. Yo usare el mismo hola mundo creado anteriormente.

Creamos un nuevo proyecto del tipo “Qt Gui Application” (váyanse al post de hola mundo…allí se explica cómo crear un proyecto). En el modo de diseño, en el form principal, es decir en mainwindow.ui que está en la carpeta Forms del árbol del proyecto, arrastramos un botón y le escribimos cualquier texto adentro.



Ya tenemos el botón, así que ahora vamos a crear el slot. Para eso nos dirigimos al archivo mainwindow.h en la carpeta headers en el árbol del proyecto. Ahora crearemos una nueva sección en la clase: “private slots:” y declararemos un slot o función q retorne un entero llamada abrirVentana(). Así:

private slots: int abrirVentana(); 

Quedando algo así:

Ahora nos dirigimos al archivo mainwindow.cpp en la carpeta Sources del árbol del proyecto. Ahí vamos a definir el slot que hemos recién declarado en la clase MainWindow:

int MainWindow::abrirVentana() {
   QDialog *dialogo; dialogo = new QDialog(this);
   dialogo->show();


Ok, ahora debemos hacer la conexión. Podemos hacerla de dos maneras, vía código (la más rápida) o vía diseñador (más…”amigable”).

Para hacerla con código nos dirigimos al constructor de la clase MainWindow, en el archivo mainwindow.cpp. Y agregamos esta línea después de la inicialización de la interfaz gráfica:

connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(abrirVentana())); 

Como ven, colocamos ui->pushButton como objeto emisor de la señal, ese es el botón que hemos creado en la ventana principal y accedemos a él con el puntero ui de la clase MainWindow. Luego colocamos como señal la función clicked(), y como objeto receptor la misma clase MainWindow, por eso usamos el puntero this, y por último, como slot ponemos la función abrirVentana(). Les quedara algo así:


Ya podemos ejecutar nuestra aplicación y este será el resultado:

Ahora vamos a ver como conectar señales de un widget con un slot de otro widget a través del diseñador. Para ello abrimos el archivo mainwindow.ui que está en la carpeta Forms del árbol de proyecto. Allí haremos click al botón “Edit Signals/Slots” que está en la parte superior:

Luego hacemos click al botón que creamos y arrastramos hacia afuera del mismo y soltamos. Nos saldrá esto:

En esa ventana se muestran las señales del botón y los slots del main window o ventana principal. No hay slots mostrados porque debemos agregarlos, aunque podemos ver los slots heredados haciendo click a la casilla en la parte inferior que dice: “Show signals and slots inherited from QWidget”. Sin embargo, debemos agregar el slot que ya hemos creado a la lista de slots de MainWindow. Para eso le damos al botón Edit que está marcado en rojo en la imagen. Nos saldrá otra ventana:


Luego volveremos a la ventana anterior, pero esta vez, el slot que agregamos saldrá en la lista de slots de main window. Ahora solo seleccionamos la señal clicked() y el slot abrirVentana() y presionamos OK.


Y ya podemos ejecutar nuestra aplicación, siendo el resultado el mismo que el anterior.

A estas alturas ya se habrán dado cuenta que el IDE de Qt los ayudara mucho a la hora de codificar ya que tiene un ayudante de escritura de código que te ayuda a ver con facilidad las funciones miembros de alguna clase que estés usando, a resaltar variables en un bloque de código, entre otras cosas muy buenas como identar tu código. Además, Qt posee en su SDK a Qt Assistant, donde tendrás a tu disposición la documentación entera de Qt y podrás investigar sobre el uso de clases y funciones en específico en cualquier momento.

Si tienen alguna duda, no duden en peguntar.

2 comentarios:

  1. Pues me gustaría me explicaras para que sirve crear las señales en general porque en este ejemplo con el puro slot funciona. Eso es lo que me perturba simplemente por no sé cual es la diferencia de crear la señal.

    ResponderEliminar
  2. Hola muchas gracias por los tutoriales; quisiera q me ayudes con un proyecto q tengo: necesito q cuando la laptop se desconecte de la corriente envie una señal a un puerto USB para q accione un octoacoplador. en el mercado existen algunos octoacopladores a travez de usb........ https://www.youtube.com/watch?v=1qisW-SmbAA

    ResponderEliminar