Мое соединение сигнал / слот не работает
Я неоднократно вижу, что у людей возникают проблемы с не вызываемыми слотами. Я хотел бы собрать некоторые из наиболее распространенных причин. Так что, возможно, я смогу помочь людям и избежать множества лишних вопросов.
каковы причины того, что соединения сигнала / слота не работают? Как можно избежать таких проблем?
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.