c++ - gui - qt license
Usar emitir vs llamar a una señal como si fuera una función regular en Qt (3)
Digamos que tengo esta señal:
signals:
void progressNotification(int progress);
Recién aprendí recientemente sobre la palabra clave emitir en Qt. Hasta ahora, solía ejecutar señales simplemente llamándolas como una función normal. Entonces, en lugar de:
emit progressNotification(1000 * seconds);
Yo escribiría:
progressNotification(1000 * seconds);
Llamarlos así parecía funcionar, y todas las máquinas tragamonedas conectadas se ejecutarían, entonces ¿usar la palabra clave emitir causa un comportamiento diferente, o es solo azúcar sintáctica?
Después de 18 meses ... comencé con comentarios bajo la respuesta de @ Mat, y me estaba quedando sin espacio rápidamente. Por lo tanto, la respuesta.
IMO emit
no es azúcar sintáctico ni una palabra clave simple en el sentido de que
- Genera código (como se explica por @Mat arriba),
- Ayuda al mecanismo de
connect
reconocer que de hecho es unasignal
, y - Hace que su señal sea parte de un sistema "más grande", donde las señales y respuestas (ranuras) se pueden ejecutar de forma síncrona o asíncrona, o en cola, dependiendo de dónde y cómo se emitió la señal. Esta es una característica extremadamente útil del sistema de señal / ranura.
Todo el sistema de señal / ranura es una expresión diferente de una simple llamada de función. Yo creo que se deriva del patrón del observador. También hay una gran diferencia entre una signal
y una slot
: ¡ no es necesario implementar una señal, mientras que una ranura debe serlo !
Estás caminando por la calle y ves una casa en llamas (una señal). Marca el 911 ( conecta la señal de fuego con la ranura de respuesta 911 ). La señal solo se emitió , mientras que la ranura fue implementada por el departamento de bomberos. Puede ser impreciso, pero entiendes la idea. Miremos el ejemplo de OP.
Algunos objetos de back-end saben cuánto progreso se ha logrado. Por lo tanto, podría simplemente emit progressNotification(...)
señal emit progressNotification(...)
. Depende de la clase que muestre la barra de progreso real, recoger esta señal y ejecutarla. Pero, ¿cómo se conecta la vista a esta señal? Bienvenido al sistema de señal / ranura de Qt. Ahora se puede concebir una clase de administrador (generalmente un tipo de artilugio), que consiste en un objeto de vista y un objeto de cálculo de datos (ambos son QObjects
), pueden realizar la connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress)
No profundicemos en los aspectos de diseño de la clase de administrador, pero baste decir que aquí es donde brilla el sistema de señal / ranura. Puedo centrarme en diseñar una arquitectura muy limpia para mi aplicación. No siempre, pero muchas veces, me parece que simplemente emito señales pero implemento espacios .
Si es posible utilizar / invocar un método de señal sin siquiera emitirlo , necesariamente implica que nunca necesitó esa función como señal en primer lugar.
La segunda opción implicaría que usted siempre sabe cuál es el nombre de la función y los parámetros de la función y que el objeto al que lo está enviando es conocido por esa función en particular. Esos dos casos no siempre son ciertos, así que esas son las dos principales razones por las cuales se han hecho ranuras y señales. "debajo del capó" el mecanismo de señal y ranura es solo una tabla con punteros para cada función que está conectada.
Además, mira este pdf que explica muy claramente la naturaleza del mecanismo de señales y ranuras: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf
emit
es solo azúcar sintáctico. Si miras la salida preprocesada de la función que emite una señal, verás que se acaba de emit
.
La "magia" ocurre en el código generado para la función de emisión de señal, que se puede ver inspeccionando el código C ++ generado por moc.
Por ejemplo, una señal foo
sin parámetros genera esta función miembro:
void W::foo()
{
QMetaObject::activate(this, &staticMetaObject, 0, 0);
}
Y el código emit foo();
está preprocesado para simplemente foo();
Qt/qobjectdefs.h
se define en Qt/qobjectdefs.h
(en el sabor de fuente abierta de la fuente de todos modos), así:
#ifndef QT_NO_EMIT
# define emit
#endif
(El protector de definición es para permitirle usar Qt con otros marcos que tienen nombres colisionantes a través de la opción de configuración no_keywords
no_keywords).