En el mundo Qt, ¿cuál es la diferencia de eventos y señal / ranuras?
¿Reemplaza uno al otro? ¿Son los eventos una abstracción de señales / ranuras?
La documentación de Qt probablemente lo explica mejor:
En Qt, los eventos son objetos, derivados de la
QEvent
clase abstracta , 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 unaQObject
subclase, pero son especialmente relevantes para los widgets. Este documento describe cómo se envían y gestionan los eventos en una aplicación típica.
Entonces, los eventos y las señales / 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 eventos en QApplication
. En general, a menos que configure el código, no generará eventos. Puede filtrarlos QObject::installEventFilter()
o manejar eventos en un objeto subclasificado anulando las funciones apropiadas.
Las señales y ranuras son mucho más fáciles de generar y recibir y puede conectar dos QObject
subclases cualesquiera . Se manejan a través de la Metaclase (eche un vistazo a su archivo moc_classname.cpp para obtener más información), pero la mayor parte de la comunicación entre clases que producirá probablemente utilizará señales y ranuras. Las señales se pueden entregar inmediatamente o diferir a través de una cola (si está utilizando subprocesos).
Se puede generar una señal.
En Qt, las señales y los eventos son implementaciones del patrón Observer . Se utilizan en diferentes situaciones porque tienen diferentes fortalezas y debilidades.
En primer lugar, definamos lo que queremos decir con 'evento Qt' exactamente: una función virtual en una clase Qt, que se espera que vuelva a implementar en una clase base suya si desea manejar el evento. Está relacionado con el patrón del método de plantilla .
Observe cómo usé la palabra " manejar ". De hecho, aquí hay una diferencia básica entre la intención de las señales y los eventos:
La diferencia es que cuando "maneja" el evento, asume 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 "arriba" y "abajo" del teclado. De lo contrario, el botón debería funcionar como normal
QPushButton
(se puede hacer clic en él, etc.). En Qt, esto se hace creando su propio "componente" reutilizable (subclase deQPushButton
), que se vuelve a implementarQWidget::keyPressEvent
. Pseudocódigo:¿Ver? Este código presenta una nueva abstracción: un widget que actúa como un botón, pero con alguna funcionalidad extra. Agregamos esta funcionalidad de manera muy conveniente:
keyPressEvent
una señal, tendríamos que decidir si heredarQPushButton
o simplemente conectarnos externamente a la señal. Pero eso sería estúpido, ya que en Qt siempre se espera que heredes cuando escribes un widget con un comportamiento personalizado (por una buena razón: reutilización / modularidad). Entonces, al hacerkeyPressEvent
un evento, transmiten su intención, quekeyPressEvent
es solo un componente básico de funcionalidad. Si fuera una señal, se vería como algo que enfrenta el usuario, cuando no está destinado a serlo.keyPressEvent
fuera una señal.El diseño de Qt está bien pensado: nos hicieron caer en el pozo del éxito al hacer que sea fácil hacer lo correcto y difícil hacer lo incorrecto (al convertir keyPressEvent en un evento).
Por otro lado, considere el uso más simple de
QPushButton
, simplemente instanciarlo y recibir una notificación cuando se haga clic en él :Esto está claramente destinado a ser realizado por el usuario de la clase:
QPushButton
cada vez que queramos que algún botón nos notifique de un clic, eso requeriría muchas subclases sin una buena razón. Un widget que siempre muestra un "Hola mundo"messagebox
cuando se hace clic en él es útil solo en un caso, por lo que no es totalmente reutilizable. Una vez más, no tenemos más remedio que hacer lo correcto, conectándonos externamente.clicked()
o conectar varias señalessayHello()
. Con las señales no hay problemas. Con la subclasificación, tendría que sentarse y reflexionar sobre algunos diagramas de clases hasta que decida un diseño apropiado.Tenga en cuenta que uno de los lugares que
QPushButton
emiteclicked()
está en sumousePressEvent()
implementación. Eso no significaclicked()
ymousePressEvent()
son intercambiables, solo que están relacionados.Entonces, las señales y los eventos tienen diferentes propósitos (pero están relacionados en el sentido de que ambos le permiten "suscribirse" a una notificación de algo que está sucediendo).
fuente
No me gustan las respuestas hasta ahora. - Permítanme concentrarme en esta parte de la pregunta:
¿Son los eventos una abstracción de señales / ranuras?
Respuesta corta: no. La respuesta larga plantea una pregunta "mejor": ¿Cómo se relacionan las señales y los eventos?
Un bucle principal inactivo (Qt, por ejemplo) suele estar "atascado" en una llamada select () del sistema operativo. Esa llamada hace que la aplicación "duerma", mientras pasa un montón de sockets o archivos o lo que sea al kernel solicitando: si algo cambia en estos, deje que la llamada select () regrese. - Y el núcleo, como amo 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 que escuchamos ingresó, etc. - Eso no es una señal Qt, ni un evento Qt, y el El bucle principal de 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 de hecho busca todas las funciones registradas para esa señal y las llama una tras otra.
Una diferencia de esos dos conceptos es visible aquí: una ranura no tiene voto sobre si otras ranuras registradas en esa señal serán llamadas o no. - Los eventos son más como una cadena, y el controlador de eventos decide si interrumpe esa cadena o no. Las señales se parecen a una estrella o un árbol a este respecto.
Un evento puede dispararse o convertirse por completo en una señal (solo emita una y no llame a "super ()"). Una señal se puede convertir en un evento (llamar a un controlador de eventos).
Lo que abstrae lo que depende del caso: la señal clicked () - abstrae los eventos del mouse (un botón sube y baja sin moverse demasiado). Los eventos de teclado son abstracciones de niveles inferiores (cosas como 果 o é son varias pulsaciones de teclas en mi sistema).
Quizás el focusInEvent () es un ejemplo de lo contrario: podría usar (y por lo tanto abstraer) la señal clicked (), pero no sé si realmente lo hace.
fuente
Los eventos son enviados por el bucle de eventos. Cada programa de GUI necesita un bucle de eventos, independientemente de lo que escriba en Windows o Linux, utilizando Qt, Win32 o cualquier otra biblioteca de GUI. Además, cada hilo tiene su propio bucle de eventos. En Qt, "GUI Event Loop" (que es el bucle principal de todas las aplicaciones de Qt) está oculto, pero lo inicias llamando:
Los mensajes que el sistema operativo y otras aplicaciones envían a su programa se envían como eventos.
Las señales y las ranuras son mecanismos 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 recibir ese evento.
Se ejecutarán todas las ranuras conectadas a la señal emitida.
No debe pensar en las señales como eventos, porque como puede leer en la documentación de Qt:
Cuando envía un evento, debe esperar un tiempo hasta que el bucle de eventos distribuya todos los eventos anteriores. Debido a esto, la ejecución del código después de enviar el evento o la señal es diferente. El código siguiente al envío de un evento se ejecutará inmediatamente. Con los mecanismos de señales y slots 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. Verifique todos los tipos de conexión en la documentación de Qt .
fuente
When you send an event, it must wait for time when event loop dispatch all events that came earlier. Because of this, execution of the cod after sending event or signal is different
Hay un artículo que analiza el procesamiento de eventos con cierto detalle: http://www.packtpub.com/article/events-and-signals
Aquí se analiza la diferencia entre eventos y señales:
Esta parece ser una forma común de hablar de ello, ya que la respuesta aceptada utiliza algunas de las mismas frases.
Tenga en cuenta que consulte los comentarios útiles a continuación sobre esta respuesta de Kuba Ober, que me hacen preguntarme si podría ser un poco simplista.
fuente
event
. Las señales y ranuras son, concretamente , métodos, mientras que el mecanismo de conexión es una estructura de datos que permite que la señal invoque una o más ranuras listadas como conectadas a ella. Espero que vean que hablar de señales / ranuras como algún "subconjunto" o "variante" de eventos es una tontería, y viceversa. Que en realidad son cosas diferentes que pasan a utilizarse para fines similares en el contexto de algunos widgets. Eso es. Cuanto más generalizas, menos útil te vuelves en mi humilde opinión.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 se realizan llamadas de tragamonedas a través de los límites del hilo. Los argumentos de la llamada de ranura se empaquetan en una estructura de datos y se envían como un evento a la cola de eventos del hilo receptor. En el hilo de recepción, el
QObject::event
método descomprime los argumentos, ejecuta la llamada y posiblemente devuelve el resultado si era una conexión de bloqueo.Si estamos dispuestos a generalizar hasta el olvido, se podría pensar en los eventos como una forma de invocar el
event
método del objeto objetivo . Esta es una llamada a un método indirecto, en cierto modo, pero no creo que sea una forma útil de pensar en ello, incluso si es una afirmación verdadera.fuente
Los eventos (en un sentido general de interacción usuario / red) generalmente se manejan 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 QMouseEvent, y los diseñadores de la biblioteca no tienen que reinventar la rueda cada vez que necesite averiguar qué hizo el mouse en algún rincón de la API de Qt.
Es cierto que si está esperando eventos (nuevamente en el caso general) de algún tipo, es casi seguro que su ranura aceptará una subclase QEvent como argumento.
Dicho esto, las señales y las ranuras ciertamente se pueden usar 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 una barra de progreso durante un proceso largo no implica un QEvent hasta ese momento.
fuente
Encontré esta pregunta mientras leía 'Procesamiento de eventos' de Leow Wee Kheng. También dice:
Jasmine Blanchette dice:
fuente
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 invocasQCoreApplication.sendEvent()
opostEvent()
) Esto generalmente no es un problema, pero: para usar señales, PyQt extrañamente requiereQObject
ser la primera superclase, y es posible que no desee reorganizar su orden de herencia solo para poder enviar señales).fuente
En mi opinión, los eventos son completamente redundantes y podrían descartarse. No hay ninguna razón por la que las señales no puedan ser reemplazadas por eventos o eventos por señales, excepto que Qt ya está configurado como está. Las señales en cola están envueltas por eventos y los eventos posiblemente podrían estar envueltos por señales, por ejemplo:
Reemplazaría la
mouseMoveEvent()
función de conveniencia que se encuentra enQWidget
(pero ya no enQQuickItem
) y manejaría lasmouseMove
señales que un administrador de escenas emitiría para el elemento. El hecho de que la señal sea emitida en nombre del elemento por alguna entidad externa no es importante y ocurre con bastante frecuencia en el mundo de los componentes Qt, aunque supuestamente no está permitido (los componentes Qt a menudo eluden esta regla). Pero Qt es un conglomerado de muchas decisiones de diseño diferentes y prácticamente grabado en piedra por temor a romper el código antiguo (lo que sucede con bastante frecuencia de todos modos).fuente
QObject
jerarquía de padres e hijos, cuando es necesario. Las conexiones de señal / ranura son solo una promesa de llamar a una función, directa o indirectamente, cuando se cumple una determinada condición. No hay una jerarquía de manejo asociada con señales y ranuras.accepted
parámetro de referencia a una señal y las ranuras que la manejan o puede tener una estructura como parámetro de referencia con unaccepted
campo. Pero Qt tomó las decisiones de diseño que tomó y ahora están grabadas en piedra.