3 回答
TA贡献1801条经验 获得超8个赞
有一些规则可以简化信号和插槽的使用寿命,并涵盖连接缺陷的最常见原因。如果我忘记了什么请告诉我。
1)检查调试控制台输出:
发生执行错误时,调试输出可以显示原因。
2)使用信号和插槽的完整签名:
代替
connect(that, SIGNAL(mySignal), this, SLOT(mySlot));
写
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
并检查你的拼写和大小写。
3)使用现有的重载:
仔细检查您是否正在使用所需的信号和插槽过载以及您使用的过载是否确实存在。
4)您的信号和插槽必须兼容:
这尤其意味着参数必须是相同类型(可以容忍引用)并且具有相同的顺序。
编译时语法也需要相同数量的参数。旧运行时语法允许将信号连接到具有较少参数的插槽。
5)经常检查连接方法的返回值(程序员应该永远不会忽略返回值):
代替
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 typesqRegisterMetaType<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.7connect(that, qOverload<int>::of(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++11connect(that, qOverload<int>(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++14
也不要为该语法混合const / non-const信号/槽(通常信号和槽将是非const)。
9)你的类需要一个Q_OBJECT宏:
在使用“信号”和“插槽”规范的类中,您需要添加一个Q_OBJECT宏,如下所示:
class SomeClass{ Q_OBJECT signals: void MySignal(int x);};class SomeMoreClass{ Q_OBJECTpublic 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上询问。
添加回答
举报