Ответ 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
Также не смешивайте постоянные/неконстантные сигналы/слоты для этого синтаксиса (обычно сигналы и слоты будут неконстантными).
9) Вашим классам нужен макрос Q_OBJECT:
В классах, где вы используете спецификации "сигналов" и "слотов", вам нужно добавить макрос Q_OBJECT следующим образом:
class SomeClass
{
Q_OBJECT
signals:
void MySignal(int x);
};
class SomeMoreClass
{
Q_OBJECT
public slots:
void MySlot(int x);
};
Этот макрос добавляет необходимую метаинформацию в класс.
10) Ваши объекты должны быть живы:
Как только объект отправителя или объект получателя уничтожен, Qt автоматически сбрасывает соединение.
Если сигнал не излучается: объект-отправитель все еще существует? Если слот не вызывается: объект-получатель все еще существует?
Чтобы проверить время жизни обоих объектов, используйте точку останова отладчика или какой-нибудь вывод qDebug() в конструкторах/деструкторах.
11) Всё равно не работает
Чтобы сделать очень быструю и грязную проверку вашего соединения, подайте сигнал самостоятельно, используя несколько фиктивных аргументов, и посмотрите, вызывается ли он:
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
emit that->mySignal(0); // Ugly, don't forget to remove it immediately
Наконец, конечно, возможно, что сигнал просто не излучается. Если вы следовали приведенным выше правилам, возможно, что-то не так в логике вашей программы. Прочитайте документацию. Используйте отладчик. А если есть сейчас другой способ, спросите у stackoverflow.