El Sistema de Eventos
En Qt, los eventos son objetos, derivados de la clase abstracta QEvent, que representan cosas que han sucedido dentro de una aplicación o como resultado de una actividad externa que la aplicación necesita conocer. Los eventos pueden ser recibidos y manejados por cualquier instancia de una subclase de QObject, pero son especialmente relevantes para los widgets. Este documento describe cómo se entregan y gestionan los eventos en una aplicación típica.
Cómo se entregan los eventos
Cuando ocurre un evento, Qt crea un objeto de evento para representarlo construyendo una instancia de la subclase QEvent apropiada, y lo entrega a una instancia particular de QObject (o una de sus subclases) llamando a su función event().
Esta función no maneja el evento en sí; basándose en el tipo de evento entregado, llama a un manejador de eventos para ese tipo específico de evento, y envía una respuesta basada en si el evento fue aceptado o ignorado.
Algunos eventos, como QMouseEvent y QKeyEvent, provienen del sistema de ventanas; otros, como QTimerEvent, provienen de otras fuentes; otros provienen de la propia aplicación.
Tipos de eventos
La mayoría de los tipos de eventos tienen clases especiales, en particular QResizeEvent, QPaintEvent, QMouseEvent, QKeyEvent, y QCloseEvent. Cada clase subclase QEvent y añade funciones específicas del evento. Por ejemplo, QResizeEvent añade size() y oldSize() para permitir a los widgets descubrir cómo han cambiado sus dimensiones.
Algunas clases admiten más de un tipo de evento real. QMouseEvent admite pulsaciones de botones del ratón, dobles clics, movimientos y otras operaciones relacionadas.
Cada evento tiene un tipo asociado, definido en QEvent::Type, y esto se puede utilizar como una fuente conveniente de información de tipo en tiempo de ejecución para determinar rápidamente de qué subclase se construyó un objeto de evento dado.
Dado que los programas necesitan reaccionar de formas variadas y complejas, los mecanismos de entrega de eventos de Qt son flexibles. La documentación de QCoreApplication::notify() cuenta toda la historia de forma concisa; el artículo de Qt Quarterly Another Look at Events lo repasa de forma menos concisa. Aquí explicaremos lo suficiente para el 95% de las aplicaciones.
Manejadores de Eventos
La forma normal de entregar un evento es llamando a una función virtual. Por ejemplo, QPaintEvent se entrega llamando a QWidget::paintEvent(). Esta función virtual se encarga de reaccionar adecuadamente, normalmente repintando el widget. Si no realizas todo el trabajo necesario en tu implementación de la función virtual, puede que necesites llamar a la implementación de la clase base.
Por ejemplo, el siguiente código maneja los clics del botón izquierdo del ratón en un widget de casilla de verificación personalizado mientras que pasa todos los demás clics de botón a la clase base QCheckBox:
void MyCheckBox::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { // handle left mouse button here } else { // pass on other buttons to base class QCheckBox::mousePressEvent(event); } }
Si desea reemplazar la función de la clase base, debe implementar todo usted mismo. Sin embargo, si sólo quieres extender la funcionalidad de la clase base, entonces implementa lo que quieras y llama a la clase base para obtener el comportamiento por defecto para cualquier caso que no quieras manejar.
Ocasionalmente, no existe tal función específica de evento, o la función específica de evento no es suficiente. El ejemplo más común es la pulsación de la tecla Tabulador. Normalmente, QWidget las intercepta para mover el foco del teclado, pero algunos widgets necesitan la tecla Tab para sí mismos.
Estos objetos pueden reimplementar QObject::event(), el manejador general de eventos, y hacer su manejo de eventos antes o después del manejo usual, o pueden reemplazar la función completamente. Un widget muy inusual que interpreta Tab y tiene un evento personalizado específico de la aplicación podría contener la siguiente función event():
bool MyWidget::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent *>(event); if (ke->key() == Qt::Key_Tab) { // special tab handling here return true; } } else if (event->type() == MyCustomEventType) { MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event); // custom event handling here return true; } return QWidget::event(event); }
Ten en cuenta que QWidget::event() se sigue llamando para todos los casos no gestionados, y que el valor de retorno indica si se ha gestionado un evento; un valor true impide que el evento se envíe a otros objetos.
Filtros de eventos
A veces un objeto necesita mirar, y posiblemente interceptar, los eventos que se envían a otro objeto. Por ejemplo, los diálogos suelen querer filtrar las pulsaciones de teclas para algunos widgets; por ejemplo, para modificar el manejo de la tecla Retorno.
La función QObject::installEventFilter() permite esto estableciendo un filtro de eventos, haciendo que un objeto filtro nominado reciba los eventos de un objeto objetivo en su función QObject::eventFilter(). Un filtro de eventos llega a procesar los eventos antes que el objeto de destino, lo que le permite inspeccionar y descartar los eventos según sea necesario. Un filtro de eventos existente puede ser eliminado utilizando la función QObject::removeEventFilter().
Cuando se llama a la implementación eventFilter() del objeto filtro, éste puede aceptar o rechazar el evento, y permitir o denegar su procesamiento posterior. Si todos los filtros de eventos permiten el procesamiento posterior de un evento (devolviendo cada uno false), el evento se envía al propio objeto de destino. Si uno de ellos detiene el procesamiento (devolviendo true), el objetivo y cualquier otro filtro de eventos posterior no llegan a ver el evento en absoluto.
bool FilterObject::eventFilter(QObject *object, QEvent *event) { if (object == target && event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); if (keyEvent->key() == Qt::Key_Tab) { // Special tab handling return true; } else return false; } return false; }
El código anterior muestra otra forma de interceptar los eventos de pulsación de la tecla Tab enviados a un widget de destino concreto. En este caso, el filtro maneja los eventos relevantes y devuelve true para evitar que se sigan procesando. Todos los demás eventos se ignoran, y el filtro devuelve false para permitir que se envíen al widget de destino, a través de cualquier otro filtro de eventos que esté instalado en él.
También es posible filtrar todos los eventos de toda la aplicación, instalando un filtro de eventos en el objeto QApplication o QCoreApplication. Estos filtros de eventos globales son invocados antes que los filtros específicos del objeto. Esto es muy potente, pero también ralentiza el envío de eventos de cada uno de los eventos de toda la aplicación; por lo general, se deberían utilizar en su lugar las otras técnicas comentadas.
Envío de eventos
Muchas aplicaciones quieren crear y enviar sus propios eventos. Puedes enviar eventos exactamente de la misma forma que el bucle de eventos de Qt, construyendo objetos de evento adecuados y enviándolos con QCoreApplication::sendEvent() y QCoreApplication::postEvent().
sendEvent() procesa el evento inmediatamente. Cuando vuelve, los filtros de eventos y/o el propio objeto ya han procesado el evento. Para muchas clases de eventos existe una función llamada isAccepted() que indica si el evento fue aceptado o rechazado por el último manejador que fue llamado.
postEvent() coloca el evento en una cola para su posterior envío. La próxima vez que se ejecute el bucle principal de eventos de Qt, despachará todos los eventos publicados, con alguna optimización. Por ejemplo, si hay varios eventos de redimensionado, se comprimen en uno. Lo mismo se aplica a los eventos de pintura: QWidget::update() llama a postEvent(), lo que elimina el parpadeo y aumenta la velocidad al evitar múltiples repintados.
postEvent() también se utiliza durante la inicialización del objeto, ya que el evento publicado normalmente se enviará muy poco después de que se complete la inicialización del objeto. Cuando se implementa un widget, es importante darse cuenta de que los eventos pueden ser enviados muy pronto en su vida, así que, en su constructor, asegúrate de inicializar las variables miembro al principio, antes de que haya alguna posibilidad de que pueda recibir un evento.
Para crear eventos de un tipo personalizado, necesitas definir un número de evento, que debe ser mayor que QEvent::User, y puede que necesites subclasificar QEvent para pasar información específica sobre tu evento personalizado. Consulte la documentación de QEvent para más detalles.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.