Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Qt 我的信号/插槽连接不工作_Qt_Signals Slots_Qt Signals_Qt Slot_Qt Connection - Fatal编程技术网

Qt 我的信号/插槽连接不工作

Qt 我的信号/插槽连接不工作,qt,signals-slots,qt-signals,qt-slot,qt-connection,Qt,Signals Slots,Qt Signals,Qt Slot,Qt Connection,我反复看到人们在插槽未被调用时遇到问题。我想收集一些最常见的原因。所以也许我可以帮助人们,避免很多多余的问题 信号/插槽连接不工作的原因是什么?如何避免此类问题?有一些规则可以简化信号和插槽的使用,并涵盖连接故障的最常见原因。如果我忘了什么,请告诉我 1)检查调试控制台输出: 当发生执行错误时,调试输出可以向您显示原因 2)使用信号和插槽的完整签名: 而不是 connect(that, SIGNAL(mySignal), this, SLOT(mySlot)); connect(that, S

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


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

有一些规则可以简化信号和插槽的使用,并涵盖连接故障的最常见原因。如果我忘了什么,请告诉我

1)检查调试控制台输出:

当发生执行错误时,调试输出可以向您显示原因

2)使用信号和插槽的完整签名:

而不是

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

检查你的拼写和大写字母

3)使用现有重载:

仔细检查您是否正在使用所需的信号和插槽重载,以及您使用的重载是否确实存在

4)您的信号和插槽必须兼容:

这尤其意味着参数必须是相同的类型(允许引用)并具有相同的顺序

编译时语法也需要相同数量的参数。旧的运行时语法允许使用较少的参数将信号连接到插槽

5)始终检查connect方法的返回值(程序员不应忽略返回值):

而不是

connect(that, SIGNAL(mySignal), this, SLOT(mySlot));
connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
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
使用此语法

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
此宏向类添加必要的元信息

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。

简短回答 你(几乎)不必再担心了。始终使用QMetaMethod/指针指向原型的成员,因为如果信号和插槽不兼容,它将在编译时失败

connect(sourceObject, &SourceClass::signal, destObject, &DestClass::slot);
只有当
sourceObject
destObject
为空时(这是预期的),此原型才会在运行时失败。但编译过程中会出现参数不兼容

只有极少数情况需要较旧的
信号
/
插槽
基于文字的语法,因此这应该是您最后的选择

兼容性 如果满足以下条件,则签名是兼容的:

  • 您正在将信号连接到插槽或信号
  • 目标信号/插槽与源信号具有相同数量或更少的参数
  • 如果使用,源信号的参数可以隐式转换为目标信号/插槽中的相应参数(按顺序匹配)
例子
  • OK-
    signalA(int,std::string)
    =>
    signalC(int,std::string)
    • 请注意,我们正在连接到一个信号
  • 正常-
    signalA(int,std::string)
    =>
    slotB(int,std::string)
  • 正常-
    signalA(int,std::string)
    =>
    slotB(int)
    • 忽略字符串参数
  • 正常-
    信号A(int,std::string)
    =>
    slotB()
    • 忽略所有参数
  • 正常-
    signalA(int,const char*)
    =>
    slotB(int,QString)
    • 使用
      QString(const char*)隐式转换
  • 失败-
    signalA(int,std::string)
    =>
    slotB(std::string)
    • int
      不能隐式转换为
      std::string
  • 失败-
    signalA(int,std::string)
    =>
    slotB(std::string,int)
    • 错误的顺序
  • 失败-
    signalA(int,std::string)
    =>
    slotB(int,std::string,int)
    • 右边的论点太多了

在我的实践中,我遇到过在接收信号的对象中错误重写eventFilter的情况。一些新手程序员忘记在函数末尾返回“false”。因此不允许MetaCall事件传递给接收对象。在本例中,si