Мое соединение сигнал / слот не работает

Я неоднократно вижу, что у людей возникают проблемы с не вызываемыми слотами. Я хотел бы собрать некоторые из наиболее распространенных причин. Так что, возможно, я смогу помочь людям и избежать множества лишних вопросов.

каковы причины того, что соединения сигнала / слота не работают? Как можно избежать таких проблем?

1 ответов


есть некоторые правила, которые делают жизнь с сигналами и слотами проще и охватывают наиболее распространенную причину неисправных соединений. Если я что-то забыл подскажите пожалуйста.

1) Проверьте вывод консоли отладки:

при возникновении ошибок выполнения вывод отладки может показать вам причину.

2) Используйте полную подпись сигнала и слота:

вместо

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

написать

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

и проверьте орфографию и капитализацию.

3) использовать существующие перегрузок:

тщательно проверьте, используете ли вы желаемые перегрузки сигнала и слота, и если перегрузки, которые вы использовали на самом деле существуют.

4) Ваш сигнал и слот должны быть совместимыми:

особенно это означает, что параметры должны быть одного типа (ссылки терпимо) и имеют такой же порядок.

синтаксис времени компиляции также требует такого же количества параметров. Старый синтаксис выполнения позволяет подключать сигналы к слотам с меньшими параметрами.

5) Всегда проверяйте возвращаемое значение метода connect (программисты должны никогда игнорировать возвращаемые значения):

вместо

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

всегда используйте что-то вроде

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

или если вы хотите бросить исключение или реализовать полную обработку ошибок. Вы также можете использовать такой макрос:

#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) вам нужен цикл событий для соединений в очереди:

т. е. когда вы подключите сигналы/слоты двух объектов, принадлежащих разным потокам (так называемый очереди подключений) вам нужно позвонить exec(); в резьбе слота!

цикл событий также должен быть фактически подан. Всякий раз, когда поток слота застрял в каком-то цикле занятости, соединения в очереди не казнены!

7) вам нужно зарегистрировать пользовательские типы для соединений в очереди:

поэтому при использовании пользовательских типов в подключениях в очереди вы должны зарегистрировать их для этой цели.

сначала объявить тип, используя следующий макрос:

Q_DECLARE_METATYPE(MyType)

затем используйте один из следующих звонков:

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

8) предпочитайте новый синтаксис времени компиляции старому проверенному синтаксису времени выполнения:

вместо из

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

использовать следующий синтаксис

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

, который проверяет сигнал и слот, во время компиляции, и даже не нужно было реальный игровой.

если ваш сигнал перегружен используйте следующий синтаксис:

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

также не смешивайте const / non-const сигналы / слоты для этого синтаксиса (обычно сигналы и слоты будут не-const).

9) классы нужен макрос:

In классы, в которых вы используете спецификации "сигналы" и "слоты", вам нужно добавить макрос Q_OBJECT следующим образом:

class SomeClass
{
   Q_OBJECT

signals:
   void MySignal(int x);
};

class SomeMoreClass
{
   Q_OBJECT

public slots:
   void MySlot(int x);
};

этот макрос добавляет необходимую метаинформацию в класс.

10) ваши объекты должны быть живы:

как только объект-отправитель или объект-получатель уничтожен, Qt автоматически отбрасывает соединение.

если сигнал не испущен: объект отправителя все еще существует? Если слот не вызывается: объект receiver все еще существует?

чтобы проверить время жизни обоих объектов, используйте точку останова отладчика или вывод qDebug() в конструкторах/деструкторах.

11) он все еще не работает:

чтобы сделать очень быструю и грязную проверку вашего соединения, испустите сигнал самостоятельно, используя некоторые фиктивные Аргументы, и посмотрите, вызвано ли это:

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

наконец, конечно, возможно, что сигнал просто не испускается. Если вы следовали вышеуказанным правилам, наверное, что-то не так в логике вашей программы. Читать документацию. Используйте отладчик. И если есть другой способ, спросите у stackoverflow.