Основная идея заключается в создании обертки, специального «соединения», который автоматически отключает сигнал. Это полезно, если вы используете много соединений «назовите меня один раз»; иначе я бы посоветовал Qobject :: disconnect в начале слота.
Эта реализация работает, создавая 2 соединения: «обычный», и один, который отключает &.
Реализация (с использованием C++ 11/Qt 5,):
template <typename Func1, typename Func2>
static inline QMetaObject::Connection weakConnect(
typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
{
QMetaObject::Connection conn_normal = QObject::connect(sender, signal, receiver, slot);
QMetaObject::Connection* conn_delete = new QMetaObject::Connection();
*conn_delete = QObject::connect(sender, signal, [conn_normal, conn_delete](){
QObject::disconnect(conn_normal);
QObject::disconnect(*conn_delete);
delete conn_delete;
});
return conn_normal;
}
Предостережения/Вещи для улучшения:
- зачистка происходит после вызова регулярное слот. Если обычный слот заставляет сигнал снова излучаться, обычный слот будет выполнен снова (потенциально вызывающий бесконечную рекурсию).
- нет надлежащего способа отключения, кроме как путем испускания сигнала. (вы можете использовать
QObject::disconnect
, но это может вызвать небольшую утечку памяти)
- опирается на порядок выполнения слотов. Кажется, сейчас хорошо.
- именования
Испытано с помощью:
class A : public QObject
{
Q_OBJECT
signals:
void sig(int a);
};
class B : public QObject
{
Q_OBJECT
public:
B(int b) : QObject(), b_(b) {}
int b() const { return b_; }
public slots:
void slo(int a) { qDebug() << "\tB :" << b_ << "a:" << a; }
private:
int b_;
};
и
A a1;
A a2;
B b10(10);
B b20(20);
weakConnect(&a1, &A::sig, &b10, &B::slo);
weakConnect(&a1, &A::sig, &b20, &B::slo);
weakConnect(&a2, &A::sig, &b20, &B::slo);
qDebug() << "a1 :"; emit a1.sig(1);// Should trigger b10 and b20 slo
qDebug() << "a2 :"; emit a2.sig(2);// Should trigger b20 slo
qDebug() << "a1 :"; emit a1.sig(3);// Should do nothing
qDebug() << "a2 :"; emit a2.sig(4);// Should do nothing
Тестовый выход код:
a1 :
B : 10 a: 1
B : 20 a: 1
a2 :
B : 20 a: 2
a1 :
a2 :
Избавление от C++ 11/Qt5 (у меня нет Qt 4.8/GCC4.4.7, поэтому не тестировался с ними) Согласно документу Qt 4.-Не имеет подключения функционировать, поэтому я использую обертку:
class ConnectJanitor : public QObject
{
Q_OBJECT
public slots:
void cleanup()
{
QObject::disconnect(conn_normal_);
QObject::disconnect(*conn_delete_);
delete conn_delete_;
delete this;
}
public:
static ConnectJanitor* make(QMetaObject::Connection conn_normal,
QMetaObject::Connection* conn_delete)
{
return new ConnectJanitor(conn_normal, conn_delete);
}
private:
ConnectJanitor(QMetaObject::Connection conn_normal,
QMetaObject::Connection* conn_delete) :
QObject(0) , conn_normal_(conn_normal), conn_delete_(conn_delete) {}
ConnectJanitor(const ConnectJanitor&); // not implemented
ConnectJanitor& operator=(ConnectJanitor const&);
QMetaObject::Connection conn_normal_;
QMetaObject::Connection* conn_delete_;
};
(я Заставить ConnectJanitor
«конструктору приватный, так как экземпляр самоликвидируется (delete this
))
и weakConnect
:
static inline QMetaObject::Connection weakConnect(const QObject * sender, const char * signal, const QObject * receiver, const char * slot)
{
QMetaObject::Connection conn_normal = QObject::connect(sender, signal, receiver, slot);
QMetaObject::Connection* conn_delete = new QMetaObject::Connection();
*conn_delete = QObject::connect(sender, signal, ConnectJanitor::make(conn_normal, conn_delete), SLOT(cleanup()));
return conn_normal;
}
Если вам нужно вручную разорвать связи, я предлагаю, чтобы иметь weakConnect(), возвращающую указатель на ConnectJanitor в.
В чем проблема с использованием функции 'disconnect()'? – vahancho
Почему вы не хотите использовать 'disconnect'? Есть ли конкретная причина? – Robert
Просто знать, есть ли другой способ. Для некоторых разработчиков вызовите disonnect после первого вызова раздражает, и я хотел бы знать, есть ли способ сделать это. –