Можно ли отключить все соединения QObject, не удаляя его

У меня есть QObject A, это связано с другим QObject B. Теперь я хочу, чтобы A соединился с C, третьим QObject и полностью отключился от B.

Легкий peasy! Проблема в том, что у меня есть много A, каждый со своим набором сигналов и слотов (B/C более общие). До сих пор я вручную создавал метод подключения и отключения для каждого типа класса. Эти методы в основном являются копиями друг друга, обменивая вызов 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?
}

Я ткнул в QMetaObject, QObject и Документация и слоты без ведома (хотя это часто не является гарантией...).

Ответы

Ответ 1

Существует не менее двух способов. Сначала отключите все.

disconnect(obj,0,0,0);
//or
obj->disconnect();

Во-вторых. Каждый connect() возвращает QMetaObject::Connection, который можно скопировать или переместить, чтобы вы могли сохранить некоторые соединения в списке и через некоторое время просто перебрать через список и вызовите disconnect() для каждого объекта. Пример с одним соединением:

QMetaObject::Connection m_connection;
//…
m_connection = QObject::connect(…);
//…
QObject::disconnect(m_connection);

Бонус: нет, Qt не поддерживает такую ​​глубокую интроспекцию, вы не можете получить список всех подключенных слотов или что-то другое, но в большинстве случаев вам это совсем не нужно. Одна полезная информация, которую Qt дает вам, - это sender(), указатель на объект, который отправил сигнал.

Edit

Как doc сказал:

Отключить все, что связано с сигналами объекта

Итак, в следующем примере будут показаны оба окна:

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");

Но uncomment 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");