license gui gratis descargar creator c++ qt

c++ - gui - Qt eventos y señal/ranuras



qt license (9)

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?


En Qt, las señales y los eventos son ambas implementaciones del patrón Observer . 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 " manejar ". De hecho, aquí hay una diferencia básica entre la intención de las señales y los eventos:

  • Usted " maneja " eventos
  • Usted " recibe notificaciones de " emisiones de señal

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 siempre se espera que heredes al escribir un widget con un comportamiento personalizado (por una buena razón: 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 la 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 abismo del éxito al hacer que sea fácil hacer lo correcto y es difícil hacer lo incorrecto (haciendo del evento KeyPressEvent un evento).

Por otro lado, considere el uso más simple de QPushButton, simplemente ejemplíelo y reciba notificaciones cuando se haga clic en él :

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 hacer clicked() - o conectar varias señales para 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 en los que QPushButton emite clicked clicked() está en su implementación mousePressEvent() . Eso no significa que mousePressEvent() 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).


En mi opinión, los eventos son completamente redundantes y podrían descartarse. No hay ninguna razón por la cual las señales no puedan ser reemplazadas por eventos o eventos por señales, excepto que Qt ya está configurado tal como está. Las señales en cola están envueltas por eventos y los eventos podrían estar envueltos por señales, por ejemplo:

connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});

Reemplazaría la función mouseMoveEvent () que se encuentra en QWidget (pero ya no en QQuickItem) y manejaría las señales mouseMove que un administrador de escena 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 muy a menudo en el mundo de los componentes de Qt, aunque se supone que no debe permitirse. Pero Qt es un conglomerado de muchas decisiones de diseño diferentes y casi hecho en piedra por temor a romper el código anterior (lo que sucede con bastante frecuencia de todos modos).


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 que se usan para lograr lo mismo. Como una diferencia general, las señales son útiles cuando se utiliza un widget, mientras que los eventos son útiles cuando se implementa el widget. Por ejemplo, cuando estamos usando un widget como QPushButton, estamos más interesados ​​en su señal clicked () que en la pulsación de un mouse de nivel bajo o eventos de pulsación de teclas que causaron la emisión de la señal. Pero si estamos implementando la clase QPushButton, estamos más interesados ​​en la implementación del código para mouse y eventos clave. Además, generalmente manejamos eventos pero recibimos 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.


La documentación de Qt probablemente lo explica mejor:

En Qt, los eventos son objetos, derivados de la clase QEvent 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 una subclase QObject, pero son especialmente relevantes para widgets. Este documento describe cómo se entregan y manejan 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 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.


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 una barra de progreso durante un proceso largo no implica un QEvent hasta ese punto.


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, el mecanismo de señales y ranuras es totalmente independiente de cualquier bucle de eventos 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. Verifique todos los tipos de conexión en la documentación de Qt .


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 una 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 que escuchamos entró, etc. - Eso no es ni una señal Qt, ni un evento Qt, y el Qt main loop se decide a 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.


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.)


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 receptor, el método QObject::event 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, podríamos pensar en los eventos como una forma de invocar el método de event del objeto objetivo. 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.