是否可以断开所有QObject的连接而不删除它

Tro*_*eph 22 c++ qt qobject qmetaobject

我有一个QObject A,它连接到另一个QObject B.现在我希望A连接到C,第三个QObject并完全断开与B.

十分简单!麻烦的是我有很多A都有自己的信号和插槽(B/C更通用).到目前为止,我已经为每个不同的类类型手动创建了connect和disconnect方法.该方法基本上交换彼此的副本connect进行disconnect通话,逆着不要重复自己).

所以我的问题是:以下功能是否可行?

void deleteAllConnections(QObject* someObject) {
    // TODO disconnect all connections owned by someObject
    // For bonus points: Is there a way of accessing the QMetaObject connected to?
}
Run Code Online (Sandbox Code Playgroud)

我在QMetaObject,QObject以及Signals and Slots文档中捅了一下没有运气(虽然这通常不是保证......).

Che*_*byl 46

至少有两种方式.首先,断开一切.

disconnect(obj,0,0,0);
//or
obj->disconnect();
Run Code Online (Sandbox Code Playgroud)

第二.每个可以复制或移动的connect()返回QMetaObject::Connection,因此您可以在列表中保存一些连接,并在一段时间后,只需遍历列表并调用disconnect()每个对象.一个连接的示例:

QMetaObject::Connection m_connection;
//…
m_connection = QObject::connect(…);
//…
QObject::disconnect(m_connection);
Run Code Online (Sandbox Code Playgroud)

奖励:不,Qt不支持这种深度内省,你不能得到所有连接的插槽列表或其他东西,但在大多数情况下,你根本不需要这个.Qt给你的一个有用信息是sender()指向发送信号的对象的指针.

编辑

正如医生所说:

断开连接到对象信号的所有内容

因此,在下一个示例中,将显示两个窗口:

QWidget *a = new QWidget;
QWidget *b = new QWidget;

a->setWindowTitle("A");
b->setWindowTitle("B");

QObject::connect(a,SIGNAL(objectNameChanged(QString)),b,SLOT(show()));
QObject::connect(b,SIGNAL(objectNameChanged(QString)),a,SLOT(show()));

//a->disconnect();

a->setObjectName("A");
b->setObjectName("B");
Run Code Online (Sandbox Code Playgroud)

但是取消注释a->disconnect();并且仅显示A窗口.这意味着QObject::connect(b,SIGNAL(objectNameChanged(QString)),a,SLOT(show()));没有按照文档中的说明断开连接.如果你想解决这个难题你可以做a->disconnect(b);b->disconnect(a);,但这当然是非常糟糕的方法.所以你可以使用我的回答中的第二个建议:

QList<QMetaObject::Connection> connections;

QWidget *a = new QWidget;
QWidget *b = new QWidget;

a->setWindowTitle("A");
b->setWindowTitle("B");

connections << QObject::connect(a,SIGNAL(objectNameChanged(QString)),b,SLOT(show()));
connections << QObject::connect(b,SIGNAL(objectNameChanged(QString)),a,SLOT(show()));

foreach (auto var, connections) {
    QObject::disconnect(var);
}

a->setObjectName("A");
b->setObjectName("B");
Run Code Online (Sandbox Code Playgroud)