qt - 我的信号/插槽连接不起作用

标签 qt signals-slots qt-signals qt-slot qt-connection

我反复看到人们遇到插槽未被调用的问题。我想收集一些最常见的原因。所以也许我可以帮助人们并避免很多多余的问题。

信号/插槽连接不起作用的原因是什么?如何避免此类问题?

最佳答案

有一些规则可以让信号和插槽的生活变得更轻松,并涵盖了连接缺陷的最常见原因。如果我忘记了什么,请告诉我。
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) 您需要一个用于排队连接的事件循环:
IE。当您连接不同线程拥有的两个对象的信号/插槽(所谓的排队连接)时,您需要调用 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
从 Qt5.14 开始,不推荐使用重载信号。禁用已弃用的 Qt 功能以摆脱上述恶作剧。
也不要为该语法混合常量/非常量信号/槽(通常信号和槽将是非常量)。
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 上询问。

关于qt - 我的信号/插槽连接不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26422154/

相关文章:

c++ - 如何处理列宽调整事件

c++ - 将QCheckBox的状态保存在文件中,程序重启时加载状态

qt - Qt 的 Facebook 连接

c++ - 从 QGroupBox 中删除标题

visual-studio - 如何在具有默认参数的插槽上使用 Qt5 connect()

c++ - QObject::connect() 错误

python - 从字典创建 pyqtSignals

qt - PyQt(或简称 QT)。如何让 QComboBox 在设置值(即使未更改)时触发信号

qt - pyqt:返回旋转框的按下信号?

Python PyQt4 发送和接收自定义信号