Pregunta Qt eventos y señal / ranuras


En el mundo de Qt, ¿cuál es la diferencia de eventos y señal / ranuras?

¿Uno reemplaza al otro? ¿Son los eventos una abstracción de señal / slots?


74
2017-09-25 17:01


origen


Respuestas:


los Qt documentación probablemente lo explique mejor:

En Qt, los eventos son objetos, derivados   de la clase QEvent abstracta, eso   representar cosas que han sucedido   ya sea dentro de una aplicación o como   resultado de la actividad exterior que el   la aplicación necesita saber.   Los eventos pueden ser recibidos y manejados por   cualquier instancia de una subclase QObject,   pero son especialmente relevantes para   widgets. Este documento describe cómo   los eventos se entregan y manejan en una   aplicación tipica.

Entonces los eventos y la señal / ranuras son dos mecanismos paralelos que logran las mismas cosas. En general, un evento será generado por una entidad externa (por ejemplo, el teclado o la rueda del mouse) y se entregará a través del bucle de evento en QApplication. En general, a menos que configure el código, no generará eventos. Puede filtrarlos a través de QObject::installEventFilter() o manejar eventos en objetos subclasificados anulando las funciones apropiadas.

Las señales y las ranuras son mucho más fáciles de generar y recibir, y puede conectar dos subclases de QObject. Se manejan a través de la Metaclass (eche un vistazo a su archivo moc_classname.cpp para obtener más información), pero la mayoría de las comunicaciones entre clases que usted producirá probablemente usarán señales y ranuras. Las señales se pueden entregar de inmediato o diferir a través de una cola (si está utilizando subprocesos).

Una señal puede ser generada.


25
2017-09-25 18:00



En Qt, las señales y eventos son ambas implementaciones del Patrón de observador. Se utilizan en diferentes situaciones porque tienen diferentes puntos fuertes y débiles.

Antes que nada, definamos exactamente lo que queremos decir con 'evento Qt': una función virtual en una clase Qt, que se espera que reimplemente en una clase base suya si quiere manejar el evento. Está relacionado con el Patrón de método de plantilla.

Tenga en cuenta cómo usé la palabra "encargarse de". De hecho, aquí hay una diferencia básica entre la intención de las señales y los eventos:

  • Usted "encargarse de" eventos
  • Usted "ser notificado de"emisiones de señales

La diferencia es que cuando "manejas" el evento, asumes la responsabilidad de "responder" con un comportamiento que es útil fuera de la clase. Por ejemplo, considere una aplicación que tiene un botón con un número. La aplicación debe permitir que el usuario enfoque el botón y cambie el número presionando las teclas del teclado "arriba" y "abajo". De lo contrario, el botón debería funcionar como un QPushButton normal (se puede hacer clic, etc.). En Qt, esto se hace creando su propio pequeño "componente" reutilizable (subclase de QPushButton), que vuelve a implementar QWidget :: keyPressEvent. Pseudocódigo:

class NumericButton extends QPushButton
    private void addToNumber(int value):
        // ...

    reimplement base.keyPressEvent(QKeyEvent event):
        if(event.key == up)
            this.addToNumber(1)
        else if(event.key == down)
            this.addToNumber(-1)
        else
            base.keyPressEvent(event)

¿Ver? Este código presenta una nueva abstracción: un widget que actúa como un botón, pero con alguna funcionalidad adicional. Agregamos esta funcionalidad muy convenientemente:

  • Como hemos vuelto a implementar un virtual, nuestra implementación se convirtió automáticamente en encapsulada en nuestra clase. Si los diseñadores de Qt hubieran hecho una señal a keyPressEvent, tendremos que decidir si heredaremos QPushButton o simplemente conectaremos externamente a la señal. Pero eso sería estúpido, ya que en Qt estás siempre se espera que herede cuando se escribe un widget con un comportamiento personalizado (por buenas razones: reutilización / modularidad). Así que al convertir KeyPressEvent en un evento, transmiten su intención de que keyPressEvent sea solo un bloque básico de funcionalidad. Si fuera una señal, se vería como algo que mira al usuario, cuando no está destinado a serlo.
  • Dado que la implementación de clase base de la función está disponible, implementamos fácilmente el Patrón de cadena de responsabilidad manejando nuestros casos especiales (teclas arriba y abajo) y dejando el resto a la clase base. Puedes ver que esto sería casi imposible si keyPressEvent fuera una señal.

El diseño de Qt está bien pensado: nos hicieron caer en el pozo del éxito haciendo que sea fácil hacer lo correcto y difícil hacer lo incorrecto (haciendo de keyPressEvent un evento).

Por otro lado, considere el uso más simple de QPushButton - simplemente crear una instancia y recibir una notificación cuando se hace clic:

button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())

Esto está claramente destinado a ser hecho por el usuario de la clase:

  • si tuviéramos que subclasificar QPushButton cada vez que quisiéramos que un botón nos notificara un clic, eso requeriría muchas subclases sin una buena razón! Un widget que siempre muestra un cuadro de mensaje de "Hola mundo" al hacer clic es útil solo en un solo caso, por lo que no es totalmente reutilizable. Nuevamente, no tenemos más remedio que hacer lo correcto, conectándonos a él externamente.
  • es posible que deseemos conectar varias ranuras para clicked() - o conecta varias señales a sayHello(). Con señales no hay problemas. Con la subclasificación, deberá sentarse y considerar algunos diagramas de clases hasta que decida sobre un diseño apropiado.

Tenga en cuenta que uno de los lugares QPushButton emite clicked() está en su mousePressEvent() implementación. Eso no significa clicked() y mousePressEvent() son intercambiables, solo que están relacionados.

Entonces las señales y los eventos tienen diferentes propósitos (pero están relacionados porque ambos te permiten "suscribir" a una notificación de que algo está sucediendo).


124
2017-09-25 18:14



No me gustan las respuestas hasta ahora. - Déjame concentrarme en esta parte de la pregunta:

¿Son los eventos una abstracción de señal / slots?

Respuesta corta: no. La respuesta larga plantea un Pregunta "mejor": ¿cómo se relacionan las señales y los eventos?

Un bucle principal inactivo (Qt, por ejemplo) generalmente está "atascado" en una llamada de selección () del sistema operativo. Esa llamada hace que la aplicación "duerma", mientras pasa un montón de sockets o archivos o lo que sea que el núcleo solicite: si algo cambia en estos, deje que la llamada select () retorne. - Y el núcleo, como el maestro del mundo, sabe cuándo sucede eso.

El resultado de esa llamada select () podría ser: nuevos datos en el socket se conectan a X11, un paquete a un puerto UDP en el que escuchamos entró, etc. - Eso no es una señal Qt, ni un evento Qt, y el ciclo principal Qt decide por sí mismo si convierte los datos nuevos en uno, el otro o lo ignora.

Qt podría llamar a un método (o varios) como keyPressEvent (), convirtiéndolo efectivamente en un evento Qt. O Qt emite una señal, que en efecto busca todas las funciones registradas para esa señal, y las llama una después de la otra.

Una diferencia de esos dos conceptos es visible aquí: una ranura no tiene voto sobre si se llamarán o no otras ranuras registradas a esa señal. - Los eventos son más como una cadena, y el controlador de eventos decide si interrumpe esa cadena o no. Las señales se ven como una estrella o un árbol a este respecto.

Un evento puede dispararse o convertirse completamente en una señal (simplemente emita uno, y no llame a "super ()"). Una señal puede convertirse en un evento (llamar a un controlador de eventos).

Lo que abstrae lo que depende del caso: la cliqueada () - señaliza los eventos del mouse (un botón baja y vuelve a subir sin demasiado movimiento). Los eventos de teclado son abstracciones de niveles inferiores (cosas como 果 o é son varias pulsaciones de teclas en mi sistema).

Tal vez el focusInEvent () es un ejemplo de lo contrario: podría usar (y así abstraer) la señal clicked (), pero no sé si realmente lo hace.


34
2018-04-29 19:11



Los eventos son enviados por el ciclo de eventos. Cada programa de GUI necesita un bucle de evento, sea lo que sea que lo escriba en Windows o Linux, utilizando Qt, Win32 o cualquier otra biblioteca de GUI. Además, cada hilo tiene su propio ciclo de eventos. En Qt, "GUI Event Loop" (que es el bucle principal de todas las aplicaciones de Qt) está oculto, pero lo inicias llamando:

QApplication a(argc, argv);
return a.exec();

Los mensajes del sistema operativo y otras aplicaciones que se envían a su programa se envían como eventos.

Las señales y las ranuras son mecanismos de Qt. En el proceso de compilaciones que usan moc (compilador de metaobjetos), se cambian a funciones de devolución de llamada.

El evento debe tener un receptor, que debe enviarlo. Nadie más debería tener ese evento.

Todas las ranuras conectadas a la señal emitida se ejecutarán.

No debe pensar en las señales como eventos, porque como puede leer en la documentación de Qt:

Cuando se emite una señal, las ranuras conectadas a ella generalmente se ejecutan inmediatamente, al igual que una llamada de función normal. Cuando esto sucede, las señales y   el mecanismo de las ranuras es totalmente independiente   de cualquier bucle de evento GUI.

Cuando envía un evento, debe esperar un tiempo hasta que el bucle de evento distribuya todos los eventos que llegaron antes. Debido a esto, la ejecución del código después de enviar el evento o la señal es diferente. El código que sigue al envío de un evento se ejecutará inmediatamente. Con los mecanismos de señales y ranuras, depende del tipo de conexión. Normalmente se ejecutará después de todas las ranuras. Usando Qt :: QueuedConnection, se ejecutará inmediatamente, al igual que los eventos. Comprobar todos los tipos de conexión en la documentación de Qt.


13
2017-09-25 19:07



Hay un artículo que analiza el procesamiento de eventos con cierto detalle: http://www.packtpub.com/article/events-and-signals

Discute la diferencia entre eventos y señales aquí:

Los eventos y las señales son dos mecanismos paralelos utilizados para lograr el   la misma cosa. Como una diferencia general, las señales son útiles cuando se usa una   widget, mientras que los eventos son útiles al implementar el widget. por   ejemplo, cuando estamos usando un widget como QPushButton, somos más   interesado en su señal clicked () que en la pulsación de mouse de bajo nivel   o eventos de pulsación de teclas que causaron la emisión de la señal. Pero si nosotros   están implementando la clase QPushButton, estamos más interesados ​​en la   implementación de código para mouse y eventos clave. Además, generalmente   manejar eventos pero recibir notificaciones por emisiones de señales.

Esta parece ser una forma común de hablar al respecto, ya que la respuesta aceptada usa algunas de las mismas frases.


Tenga en cuenta que, por favor, consulte los comentarios útiles a continuación sobre esta respuesta de Kuba Ober, que me preguntan si podría ser un poco simplista.


6
2017-07-09 17:42



TL; DR: las señales y las ranuras son llamadas a métodos indirectos. Los eventos son estructuras de datos. Entonces son animales bastante diferentes.

El único momento en que se unen es cuando las llamadas de tragamonedas se realizan a través de los límites de los hilos. Los argumentos de llamadas de intervalos se empaquetan en una estructura de datos y se envían como un evento a la cola de eventos del hilo de recepción. En el hilo de recepción, el QObject::event El método descomprime los argumentos, ejecuta la llamada y posiblemente devuelve el resultado si se trata de una conexión de bloqueo.

Si estamos dispuestos a generalizar al olvido, uno podría pensar en los eventos como una forma de invocar el objetivo del objeto event método. Esta es una llamada a un método indirecto, por así decirlo, pero no creo que sea una forma útil de pensarlo, incluso si es una afirmación verdadera.


4
2018-01-12 20:29



Los eventos (en un sentido general de interacción usuario / red) se manejan típicamente en Qt con señales / ranuras, pero las señales / ranuras pueden hacer muchas otras cosas.

QEvent y sus subclases son básicamente pequeños paquetes de datos estandarizados para que el marco se comunique con su código. Si desea prestar atención al mouse de alguna manera, solo tiene que mirar la API de QMouseEvent, y los diseñadores de la biblioteca no tienen que reinventar la rueda cada vez que necesita averiguar qué hizo el mouse en algún rincón de la API Qt.

Es cierto que si estás esperando eventos (de nuevo en el caso general) de algún tipo, es casi seguro que tu tragamonedas aceptará una subclase QEvent como argumento.

Dicho esto, las señales y las ranuras sin duda se pueden utilizar sin QEvents, aunque encontrará que el ímpetu original para activar una señal a menudo será algún tipo de interacción del usuario u otra actividad asincrónica. A veces, sin embargo, su código simplemente llegará a un punto en el que disparar una determinada señal será lo correcto. Por ejemplo, disparar una señal conectada a un barra de progreso durante un largo proceso no implica un QEvent hasta ese punto.


3
2017-09-25 17:14



Otra consideración pragmática menor: emitir o recibir señales requiere heredar QObject, mientras que un objeto de cualquier herencia puede publicar o enviar un evento (ya que invoca QCoreApplication.sendEvent () o postEvent ()). Por lo general, esto no es un problema sino: usar señales PyQt extrañamente requiere QObject para ser la primera súper clase, y es posible que no desee reorganizar su orden de herencia solo para poder enviar señales.)


1
2017-10-16 12:35