Signals & Slots en Qt

En todos los framework diseñados para desarrollar GUIs debemos tener un mecanismo para responder a los eventos producidos por los componente de la interface de usuario y también para emitir dichos eventos, en Qt 5.x contamos con los Signals & Slots para tal propósito, por ejemplo, al presionar el botón Salir se genera un signal, si deseamos que dicho botón cierre la ventana entonces debemos establecer la función close() de la ventana como slot.

Signal: es emitido por un objeto cuando el mismo detecte un cambio de estado en alguna de sus propiedades, en el caso de un QPushButton al hacer clic sobre el mismo se emite QPushButton::clicked puedes ver la documentación para conocer los distintos signals que son emitidos por esta clase.

Slot: es una función C++ que es invocada en respuesta a un signal, para que esto sea posible debemos conectarlos, para esto usaremos la función QObject::connect(...) más adelante explicamos su uso.

Nuestra primer ejemplo usando Qt Creator, primero creamos el proyecto:

Crear proyecto Qt Creator

Agregamos las siguientes clases:

Agregar clases a proyecto Qt

Agregamos el siguiente código al archivo mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    this->setWindowTitle("Signls & Slots");
    this->resize(600, 250);

    QPushButton* btn = new QPushButton("Salir", this);
    btn->setGeometry(10, 10, 120, 30);

    QObject::connect(btn, &QPushButton::clicked, this, &QMainWindow::close);
}

Podemos ver que tenemos un botón llamado Salir, la idea es que, al hacer clic sobre él, se cierre la ventana, para que esto sea posible debemos conectar el signal QPushButton::clicked con el slot QMainWindow::close esto se hace de esta manera:

QObject::connect(btn, &QPushButton::clicked, this, &QMainWindow::close);

Los primeros dos parámetros indican el objeto que produce el signal y cuál es el mismo, todos los componentes de UI que contiene Qt producen uno o más signals, los últimos dos establecen el objeto y la función del mismo que responderán al emitirse el signal indicado previamente.

Ejemplo Signals & Slot en Qt

Al presionar Salir se cierra la ventana.

Definir nuestro propio slot

En el ejemplo que acabamos de presentar hemos usado el slot QMainWindow::close definido por el framework Qt, ahora mostramos el proceso para definir nuestro propio slot.

class MainWindow : public QMainWindow
{
    Q_OBJECT

public slots:
    void OnClickSalir();

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
};

Debemos tener presente lo siguiente, para que una clase puede utilizar este mecanismo debe ser un objeto Qt, es decir debe heredar de QObject, además debemos agregar el macro Q_OBJECT quién añadirá todo lo necesario para el correcto funcionamiento de mecanismo, el slot se define de esta manera:

public slots:
    void OnClickSalir();

La implementación solo muestra un mensaje, veamos:

void MainWindow::OnClickSalir()
{
    QString text = "Click en QPushButton\nUsando el mecanismo Signal & Slot de Qt";
    QMessageBox::information(this, "QMessageBox", text, QMessageBox::Ok);
}

Ahora debemos conectar el clic del botón a nuestro slot que acabamos de definir:

QObject::connect(btn, &QPushButton::clicked, this, &MainWindow::OnClickSalir);

Con esto tenemos:

Definir un Slot propio

Emitir un signal personalizado

De igual moda que lo anterior también podemos preparar nuestra clase para que emita un signal, para este ejemplo haremos los siguiente: crearemos un signal que se dispara cuando un contador sobrepasa el valor definido, para nuestro caso 5, creamos además un slot que estará encargado de incrementar el contador, lo que buscamos es que, al presionar más de 5 veces el botón este cierre la ventana.

Modificamos la clase de la siguiente manera:

class MainWindow : public QMainWindow
{
    Q_OBJECT

public slots:
    void OnClickSalir();

signals:
    void MaxClickCount();

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QPushButton *btn = 0;
    int clickCount = 0;
};

La definición de los respectivos Signals y Slots es la siguiente, estos realizan las tareas previamente mencionadas:

public slots:
    void OnClickSalir();

signals:
    void MaxClickCount();

La implementación de la clase:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    this->setWindowTitle("Signls & Slots");
    this->resize(600, 250);

    btn = new QPushButton("Salir (0)", this);
    btn->setGeometry(10, 10, 120, 30);

    QObject::connect(btn, &QPushButton::clicked, this, &MainWindow::OnClickSalir);
    QObject::connect(this, &MainWindow::MaxClickCount, this, &MainWindow::close);
}

void MainWindow::OnClickSalir()
{
    if(this->clickCount++ >= 5) {
        emit MaxClickCount();
    }

    this->btn->setText(QString::asprintf("Salir (%d)", this->clickCount));
}

El siguiente slot incrementa el respectivo contador, cuando este sea mayor que el valor establecido se emite el signal MaxClickCount() para ello usamos el código emit MaxClickCount().

void MainWindow::OnClickSalir()
{
    if(this->clickCount++ >= 5) {
        emit MaxClickCount();
    }
}

La primera línea de código conecta el clic del botón con la función que acabamos de mostrar, esto nos permite incrementar el contador cada vez que se presione el botón, luego conectamos el signal MainWindow::MaxClickCount con la función que cierra la ventana, recordemos que este signal es emitido cuando el contador supera el valor definido, por lo que al hacer más de 5 clic la ventana se cerrará.

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    // ...
    QObject::connect(btn, &QPushButton::clicked, this, &MainWindow::OnClickSalir);
    QObject::connect(this, &MainWindow::MaxClickCount, this, &MainWindow::close);
}

Tenemos este resultado:

Crear un Signal propio

Requerimos presionar el botón mas de 5 veces para salir.

Terminamos por ahora, espero haber explicado lo mejor posible los Signals & Slot del Framework Qt ya que son parte importante del mismo, los espere en la próxima.

Descargar demo: signal-slot-demo.zip

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

Controles y Contenedores JavaFX 8 - I

tkinter Canvas

Histogramas OpenCV Python