Hemos investigando por todo el mundo online y así traerte la solución a tu duda, si tienes inquietudes déjanos la pregunta y te contestaremos con gusto, porque estamos para ayudarte.
Solución:
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.
Fíjate cómo usé la palabra “resolver“. De hecho, aquí hay una diferencia básica entre la intención de las señales y los eventos:
- Usted “resolver” eventos
- Usted “ser notificado de“emisiones de señales
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 el teclado “arriba” y “abajo” keys. De lo contrario, el botón debería funcionar como un QPushButton
(se puede hacer clic en él, etc.). En Qt, esto se hace creando su propio “componente” reutilizable (subclase de QPushButton
), que reimplementa 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 extra. Agregamos esta funcionalidad de manera muy conveniente:
- Dado que reimplementamos un virtual, nuestra implementación se encapsuló automáticamente en nuestra clase. Si los diseñadores de Qt hubieran hecho
keyPressEvent
una señal, tendríamos que decidir si heredarQPushButton
o simplemente conéctese externamente a la señal. Pero eso sería una estupidez, ya que en Qt estás siempre Se espera que herede al escribir un widget con un comportamiento personalizado (por una buena razón: reutilización / modularidad). Entonces al hacerkeyPressEvent
un evento, transmiten su intención de 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. - 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 (arriba y abajo keys) y dejando el resto a la clase base. Puede ver que esto sería casi imposible si
keyPressEvent
eran 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 (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 hace clic en él:
button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())
Esto está claramente destinado a ser realizado por el usuario de la clase:
- si tuviéramos que subclasificar
QPushButton
cada vez que queremos 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 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. - es posible que deseemos conectar varias ranuras a
clicked()
– o conecte varias señales asayHello()
. 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 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 en el sentido de que ambos le permiten “suscribirse” a una notificación de algo que está sucediendo).
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 suscita un 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, ingresó un paquete a un puerto UDP que escuchamos, etc. Ese material no es una señal Qt ni un evento Qt, y el bucle 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 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 se llamará o no a 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 parecen 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 key golpes 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.
La documentación de Qt probablemente lo explica mejor:
En Qt, los eventos son objetos, derivados de lo abstracto.
QEvent
class, 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 unQObject
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 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 eventos en QApplication
. En general, a menos que configure el código, no generará eventos. Podrías filtrarlos a través de QObject::installEventFilter()
o manejar eventos en un objeto subclasificado anulando las funciones apropiadas.
Las señales y las ranuras son mucho más fáciles de generar y recibir y puede conectar dos QObject
subclases. 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.
Si conservas alguna vacilación o disposición de innovar nuestro tutorial eres capaz de añadir un informe y con deseo lo observaremos.