项目中使用lambda表达式绑定槽非常方便,但是在断开槽的时候遇到了问题,通过查遍资料没有解决最后找到原因,在此记录。
复现问题
lambda绑定槽
QObjectDemo有一个sigNum信号, 通过lambda绑定:
signals: void sigNum();
MainWindow.cpp:
通过connect绑定sigNum信号,槽为lambda表达式,在发送信号前调用disconnect()函数断开MainWindow实例相关所有信号槽:
QObjectDemo *demo = new QObjectDemo; QObject::connect(demo, &QObjectDemo::sigNum, []() { qDebug() << "abc"; }); this.disconnect(demo, nullptr, this, nullptr);//断开MainWindow示例和*demo实例关联的所有信号槽 emit demo->sigNum();;//发送信号
正常情况下, 不会输入abc, 但执行后发现, 在发送信号后, 仍然输出了 abc ,也就是说this.disconnect()并没有断开成功!
问题解决
在使用lambda当做槽时,如果考虑后期需要断开槽, 需要提供接受者, 如果不考虑后期断开槽,可以不提供接受者。
把例子中connect参数中,添加接受者,信号槽正常断开:
QObjectDemo *demo = new QObjectDemo; QObject::connect(demo, &QObjectDemo::sigNum, this, []() { qDebug() << "abc"; }); disconnect(demo, nullptr, this, nullptr);//断开MainWindow示例和*demo实例关联的所有信号槽 emit demo->sigNum();;//发送信号
注意在调用disconnect断开的时候,接受者是那个引用, disconnect参数中接受者也需要传那个引用,例如此处connect中接受者是this,所以在断开的时候接受者也是this:
disconnect(demo, nullptr, this, nullptr);
此处接受者不一定是this(MainWindow引用),也可以是任何集成QObject的引用,例如接受者为 *demo2 :
QObjectDemo *demo2 = new QObjectDemo; QObjectDemo *demo = new QObjectDemo; connect(demo, &QObjectDemo::sigNum, demo2, [](){ qDebug() <<"hello ..."; }); disconnect(demo, nullptr, demo2, nullptr); emit demo->sigNum();;//发送信号
发现不会输出"hello...", 信号槽也能正常断开!
在Qt 官方文档中也提到了没有接收者引用的connect信号槽实例,是没有办法断开的。
connect 没有receiver实例: https://doc.qt.io/qt-5.15/qobject.html#connect-4
对于没有接受者的信号槽, 文档也作了说明,没有receiver(接收者),是没法断开槽的...: