tutorial signal custom and qt signals-slots qt-signals qt-slot qt-connection

custom - qt signals and slots tutorial



Mi conexión de señal/ranura no funciona (3)

Respuesta corta

Usted (casi) ya no tiene que preocuparse por eso. Utilice siempre QMetaMethod / Pointer para crear un prototipo de connect , ya que fallará en el momento de la compilación si la señal y la ranura no son compatibles.

connect(sourceObject, &SourceClass::signal, destObject, &DestClass::slot);

Este prototipo solo fallará en tiempo de ejecución si sourceObject o destObject es nulo (lo cual es de esperar). Pero la incompatibilidad de argumentos aparecerá durante la compilación

Solo las situaciones raras requieren la sintaxis más antigua basada en SIGNAL / SLOT , por lo que este debería ser su último recurso.

Compatibilidad

Las firmas son compatibles si se cumplen las siguientes condiciones:

  • Estás conectando una señal a una ranura o una señal
  • La señal / ranura de destino tiene el mismo número o menos argumentos que la señal fuente
  • Los argumentos de la señal de origen se pueden convertir implícitamente al argumento correspondiente (emparejado en orden) en la señal / ranura de destino, si se usa
Ejemplos
  • OK - signalA(int, std::string) => signalC(int, std::string)
    • Tenga en cuenta que nos estamos conectando a una señal
  • OK - signalA(int, std::string) => slotB(int, std::string)
  • OK - signalA(int, std::string) => slotB(int)
    • Parámetro de cadena ignorado
  • OK - signalA(int, std::string) => slotB()
    • Todos los parámetros ignorados
  • OK - signalA(int, const char*) => slotB(int, QString)
    • Convertido implícitamente con QString(const char*)
  • Falla - signalA(int, std::string) => slotB(std::string)
    • int no es implícitamente convertible a std::string
  • Falla - signalA(int, std::string) => slotB(std::string, int)
    • Orden incorrecta
  • Falla - signalA(int, std::string) => slotB(int, std::string, int)
    • Demasiados argumentos en el lado derecho

Veo repetidamente personas que tienen problemas con las máquinas tragamonedas que no se llaman. Me gustaría recopilar algunas de las razones más comunes. Entonces, tal vez pueda ayudar a las personas y evitar muchas preguntas redundantes.

¿Cuáles son las razones por las cuales las conexiones de señal / ranura no funcionan? ¿Cómo se pueden evitar estos problemas?


En mi práctica, he encontrado casos de anulación incorrecta de eventFilter en el objeto que recibe la señal. Algunos programadores novatos se olvidan de devolver "falso" al final de la función. Y, por lo tanto, no permita que el evento MetaCall pase al objeto receptor. En este caso, la señal no se procesa en el objeto receptor.


Hay algunas reglas que facilitan la vida con señales y ranuras y cubren la razón más común de conexiones defectuosas. Si olvidé algo por favor dime.

1) Verifique la salida de la consola de depuración:

Cuando se producen errores de ejecución, la salida de depuración puede mostrarle el motivo.

2) Use la firma completa de señal y ranura:

En lugar de

connect(that, SIGNAL(mySignal), this, SLOT(mySlot));

escribir

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));

y revisa tu ortografía y mayúsculas.

3) Use sobrecargas existentes:

Verifique cuidadosamente si está utilizando las sobrecargas deseadas de señal y ranura y si las sobrecargas que usó realmente existen.

4) Su señal y ranura deben ser compatibles:

Esto significa especialmente que los parámetros deben ser del mismo tipo (se toleran las referencias) y tener el mismo orden.

La sintaxis en tiempo de compilación también necesita el mismo número de parámetros. La antigua sintaxis de tiempo de ejecución permite conectar señales a ranuras con menos parámetros.

5) Verifique siempre el valor de retorno del método de conexión (los programadores nunca deben ignorar los valores de retorno):

En lugar de

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));

siempre usa algo como

bool success = connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); Q_ASSERT(success);

O si desea lanzar una excepción o implementar un manejo completo de errores. También puede usar una macro como esa:

#ifndef QT_NO_DEBUG #define CHECK_TRUE(instruction) Q_ASSERT(instruction) #else #define CHECK_TRUE(instruction) (instruction) #endif CHECK_TRUE(connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))));

6) Necesita un bucle de eventos para conexiones en cola:

Es decir, cuando conecte señales / ranuras de dos objetos propiedad de diferentes hilos (llamadas conexiones en cola) debe llamar a exec(); en el hilo de la ranura!

El bucle de eventos también debe servirse realmente. Siempre que el hilo de la ranura está atascado en algún tipo de bucle ocupado, las conexiones en cola NO se ejecutan.

7) Necesita registrar tipos personalizados para conexiones en cola:

Por lo tanto, cuando use tipos personalizados en conexiones en cola, debe registrarlos para este propósito.

Primero declare el tipo usando la siguiente macro:

Q_DECLARE_METATYPE(MyType)

Luego use una de las siguientes llamadas:

qRegisterMetaType<MyTypedefType>("MyTypedefType"); // For typedef defined types qRegisterMetaType<MyType>(); // For other types

8) Prefiera la nueva sintaxis de tiempo de compilación sobre la sintaxis comprobada en tiempo de ejecución anterior:

En lugar de

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));

usa esta sintaxis

connect(that, &ThatObject::mySignal, this, &ThisObject::mySlot));

que comprueba la señal y la ranura durante el tiempo de compilación e incluso no necesita que el destino sea una ranura real.

Si su señal está sobrecargada, use la siguiente sintaxis:

connect(that, static_cast<void (ThatObject::*)(int)> &ThatObject::mySignal), this, &ThisObject::mySlot); // <Qt5.7 connect(that, qOverload<int>::of(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++11 connect(that, qOverload<int>(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++14

Tampoco mezcle señales / ranuras const / non-const para esa sintaxis (normalmente las señales y las ranuras serán no const).

9) Tus clases necesitan una macro Q_OBJECT:

En las clases donde usa especificaciones de "señales" y "ranuras", necesita agregar una macro Q_OBJECT como esta:

class SomeClass { Q_OBJECT signals: void MySignal(int x); }; class SomeMoreClass { Q_OBJECT public slots: void MySlot(int x); };

Esta macro agrega metainformación necesaria a la clase.

10) Tus objetos deben estar vivos:

Tan pronto como se destruye el objeto emisor o el objeto receptor, Qt descarta automáticamente la conexión.

Si no se emite la señal: ¿Sigue existiendo el objeto emisor? Si no se llama a la ranura: ¿Sigue existiendo el objeto receptor?

Para verificar la vida útil de ambos objetos, utilice un punto de interrupción del depurador o alguna salida qDebug () en los constructores / destructores.

11) Todavía no funciona:

Para hacer una comprobación muy rápida y sucia de su conexión, emita la señal usted mismo utilizando algunos argumentos ficticios y vea si se llama:

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); emit that->mySignal(0); // Ugly, don''t forget to remove it immediately

Finalmente, por supuesto, es posible que la señal simplemente no se emita. Si siguió las reglas anteriores, probablemente algo esté mal en la lógica de su programa. Lee la documentación. Usa el depurador. Y si ahora hay otra forma, pregunte en .