Alfabetización Qt: una descripción general del sistema de eventos Qt

I. Resumen

En Qt, un evento es un objeto derivado de la clase abstracta QEvent, que representa el resultado de una actividad externa que ocurre dentro de la aplicación o que la aplicación necesita conocer .

El evento puede ser recibido y procesado por cualquier instancia de la subclase QObject.Generalmente, este evento se usa con mucha frecuencia en los programas de ventana.

¿Cómo se entrega y procesa el evento?

Cuando ocurre un evento, Qt crea un objeto de evento para representar el evento construyendo una instancia de la subclase QEvent adecuada y entrega el evento a la instancia específica de QObject (o una de sus subclases ) llamando a su función event().

La función event() no maneja el evento en sí; dependiendo del tipo de evento entregado, invoca el controlador de eventos para ese tipo de evento en particular y envía una respuesta dependiendo de si el evento fue aceptado o ignorado.

Algunos eventos, como QMouseEvent y QKeyEvent, provienen del sistema de ventanas, algunos eventos (como QTimerEvent) provienen de otras fuentes y algunos provienen de la propia aplicación.

inserte la descripción de la imagen aquí

2. Tipo de evento - Tipos de eventos

Existen clases especiales para la mayoría de los tipos de eventos, en particular QResizeEvent, QPaintEvent, QMouseEvent, QKeyEvent y QCloseEvent. Cada clase es una subclase de QEvent con funciones específicas de eventos añadidas. Por ejemplo, QResizeEvent agrega size() y oldSize() para permitir que los widgets descubran cómo ha cambiado su tamaño.

Algunas clases admiten varios tipos de eventos reales. Al igual que QMouseEvent admite el botón del mouse, hacer doble clic, mover y otras operaciones relacionadas.

Cada evento tiene un tipo de evento asociado, definido en QEvent::type, que se puede usar como una fuente conveniente de información de tipo de tiempo de ejecución para determinar rápidamente a partir de qué subclase se construyó un objeto de evento determinado.

Debido a que los programas necesitan reaccionar de varias formas complejas, el mecanismo de entrega de eventos de Qt es flexible. La documentación de QCoreApplication::notify() explica todo el proceso de forma sucinta; el artículo trimestral de Qt "Another Look at Events" es menos conciso. Aquí, explicaremos el 95% de la aplicación.

3. Controladores de eventos - Controladores de eventos

La forma normal de pasar eventos es llamar a funciones virtuales. Por ejemplo, QPaintEvent se entrega llamando a QWidget::paintEvent(). Esta función virtual se encarga de reaccionar adecuadamente, normalmente redibujando el widget. Si no realiza todo el trabajo necesario al implementar una función virtual, es posible que deba llamar a la implementación de la clase base .

Es decir, debe reescribir esta función virtual usted mismo para realizar la función.

Por ejemplo, el siguiente código maneja los clics del botón izquierdo del mouse en un widget de casilla de verificación personalizado mientras pasa todos los demás clics de botón a la clase base QCheckBox
MyCheckBox es la clase que hereda de QCheckBox y anula la función mousePressEvent.
:

  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 funciones de la clase base, debe implementar todo usted mismo. Sin embargo, si solo desea ampliar la funcionalidad de la clase base, puede implementar lo que desee y llamar a la clase base para obtener el comportamiento predeterminado para cualquier caso que no desee manejar.

A veces no hay funciones específicas de eventos, o simplemente usar funciones específicas de eventos no es suficiente. El ejemplo más común es presionar la tecla Tabulador. Normalmente, los QWidgets interceptan estas teclas para mover el foco del teclado, pero algunos widgets requieren la tecla Tabulador.

Estos objetos pueden volver a implementar el controlador de eventos genérico QObject::event() y realizar el manejo de eventos antes o después del procesamiento habitual, o reemplazar la función por completo. ( Si ya lo procesó, devolverá verdadero. Si no lo procesa, la función de la clase base también se llamará más tarde y es posible que sobrescriba la función que escribió).

La siguiente es una función de evento () que implementa la función de presionar la pestaña para recorrer las pestañas:

bool EventUse::event(QEvent *event)
{
    
    
    if (event->type() == QEvent::KeyPress)
    {
    
    
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_Tab)
        {
    
    
            qDebug()<<"当前页面:"<<ui->tabWidget->currentIndex();
            ui->tabWidget->setCurrentIndex((ui->tabWidget->currentIndex() + 1) % ui->tabWidget->count());
            return true;
        }
    }

    return QWidget::event(event);
}

Tenga en cuenta que todavía se llama a QWidget::event() para todos los casos no manejados, y el valor de retorno indica si el evento fue manejado: un valor verdadero evita que el evento se envíe a otros objetos .

Cuarto, el filtro de eventos - Filtros de eventos

A veces, un objeto necesita ver e interceptar eventos pasados ​​a otro objeto. Por ejemplo, los diálogos a menudo quieren filtrar las pulsaciones de teclas para ciertos widgets; por ejemplo, modificar el manejo de la tecla de retorno.

La función QObject::installEventFilter() hace esto configurando un filtro de eventos para que el objeto de filtro especificado reciba eventos del objeto de destino en su función QObject::eventFilter().

Los filtros de eventos procesan eventos antes que el objeto de destino, lo que le permite inspeccionar y descartar eventos según sea necesario. Un filtro de eventos existente se puede eliminar usando la función QObject::removeEventFilter().

Al llamar a la implementación eventFilter() del objeto de filtro, puede aceptar o rechazar el evento y permitir o denegar el procesamiento posterior del evento. Si todos los filtros de eventos permiten un mayor procesamiento del evento (devolviendo falso cada vez), el evento se envía al propio objeto de destino. Si uno de ellos deja de procesar (devolviendo true ), ni el objetivo ni los filtros de eventos posteriores verán el evento . Equivalente a un cortocircuito. ¡Esto actúa como un filtro!

Al igual que instalé un controlador de eventos en la ventana principal de un control, lo procesé y devolví falso, e instalé un controlador de eventos en el control.Para el mismo evento, si la ventana principal devuelve falso, el evento se pasará al control Si es verdadero, entonces este control no obtendrá este evento.

  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 eventos de pulsación de pestañas enviados a un widget de destino específico. En este caso, el filtro procesa el evento asociado y devuelve verdadero para detener el procesamiento posterior. Todos los demás eventos se ignoran y el filtro devuelve falso, lo que permite enviarlos al componente de destino a través de otros filtros de eventos instalados en el componente de destino.

También es posible filtrar todos los eventos de toda la aplicación instalando un filtro de eventos en el objeto QApplication o QCoreApplication. Dichos filtros de eventos globales se invocan antes que los filtros específicos de objetos. Esto es muy poderoso, pero también ralentiza la entrega de cada evento a lo largo de la aplicación; este generalmente debería usar las otras técnicas discutidas.

El uso de QObject::installEventFilter(QObject *filterObj) es el siguiente:

Instala un filtro de eventos filterObj en este objeto. Por ejemplo:

monitoredObj - > installEventFilter (filterObj);

Un filtro de eventos es un objeto que recibe todos los eventos enviados a ese objeto. Los filtros pueden detener eventos o reenviar eventos a este objeto. El filtro de eventos filterObj recibe eventos a través de la función eventFilter(). La función eventFilter() debe devolver verdadero si es necesario filtrar el evento (es decir, detenerlo); de lo contrario, debe devolver falso.

Si se instalan varios filtros de eventos en un solo objeto, el último filtro instalado se activará primero. El mecanismo similar a empujar la pila
La siguiente es la clase KeyPressEater, que comerá el comportamiento de pulsación de tecla del objeto supervisado, porque intercepta todas las acciones de pulsación de tecla:

  class KeyPressEater : public QObject
  {
    
    
      Q_OBJECT
      ...

  protected:
      bool eventFilter(QObject *obj, QEvent *event) override;
  };

  bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
  {
    
    
      if (event->type() == QEvent::KeyPress) {
    
    
          QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
          qDebug("Ate key press %d", keyEvent->key());
          return true;
      } else {
    
    
          // standard event processing
          return QObject::eventFilter(obj, event);
      }
  }

He aquí cómo instalarlo en ambas partes:

  KeyPressEater *keyPressEater = new KeyPressEater(this);
  QPushButton *pushButton = new QPushButton(this);
  QListView *listView = new QListView(this);

  pushButton->installEventFilter(keyPressEater);
  listView->installEventFilter(keyPressEater);

Por ejemplo, la clase QShortcut utiliza esta técnica para interceptar las pulsaciones de teclas de método abreviado.

Advertencia: si elimina el objeto receptor en la función eventFilter(), asegúrese de devolver verdadero. Si se devuelve falso, Qt enviará el evento al objeto eliminado y el programa se bloqueará.

Tenga en cuenta que el objeto de filtro debe estar en el mismo subproceso que este objeto. Si filterObj está en un hilo diferente, esta función no hace nada. Si filterObj o este objeto se mueven a un subproceso diferente después de llamar a esta función, el filtro de eventos no se llamará hasta que ambos objetos vuelvan a tener la misma afinidad de subprocesos (no se hayan eliminado).

5. Envío de eventos - Envío de eventos

Muchas aplicaciones desean crear y enviar sus propios eventos. Puede publicar eventos exactamente de la misma manera que el propio bucle de eventos de Qt mediante la construcción de objetos de evento apropiados y el uso de QCoreApplication::sendEvent() y QCoreApplication::postEvent() para publicar eventos.

1. enviarEvento()

sendEvent() maneja el evento inmediatamente. Cuando regresa, el filtro de eventos y/o el objeto en sí mismo ya ha manejado el evento. Para muchas clases de eventos hay una función llamada isAccepted() que le dice si el último controlador llamado aceptó o rechazó el evento.

2. postevento()

postEvent() envía el evento a la cola para que se envíe más tarde La próxima vez que se ejecute el bucle de eventos principal de Qt, enviará todos los eventos publicados, con algunas optimizaciones. Por ejemplo, si hay varios eventos de cambio de tamaño, se comprimen en uno. Lo mismo se aplica a los eventos de pintura: QWidget::update() llama a postEvent(), lo que elimina el parpadeo y mejora la velocidad al evitar múltiples redibujados.

postEvent() también se usa para la inicialización de objetos, ya que los eventos publicados generalmente se envían poco después de que se completa la inicialización del objeto. Al implementar una ventana, es importante darse cuenta de que los eventos se pueden entregar temprano en su ciclo de vida, por lo tanto, en su constructor, asegúrese de inicializar las variables miembro lo antes posible antes de que pueda recibir eventos.

Para crear un tipo de evento personalizado, debe definir un número de evento, que debe ser mayor que QEvent::User, y es posible que deba crear una subclase de QEvent para pasar información específica sobre el evento personalizado. Este es el mismo que el número de mensaje win32

Supongo que te gusta

Origin blog.csdn.net/qq_43680827/article/details/131134903
Recomendado
Clasificación