Die Kernidee besteht darin, einen Wrapper zu erstellen, einen speziellen "connect", der das Signal automatisch trennt. Dies ist nützlich, wenn Sie viele "Call Me Once" Verbindungen verwenden; sonst würde ich einen Qobject :: disconnect am Anfang des Slots empfehlen.
Diese Implementierung funktioniert durch Erstellen von 2 Verbindungen: eine "normale", und eine, die & entfernen Sie alles nur danach trennen.
Eine Implementierung (C++ 11/Qt 5, verwendet wird):
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;
}
Caveats/Aktivitäten zu verbessern:
- die Bereinigung erfolgt nach den regulären Aufruf Slot. Wenn der reguläre Slot dazu führt, dass das Signal erneut ausgegeben wird, wird der reguläre Slot erneut ausgeführt (was möglicherweise zu einer unendlichen Rekursion führt).
- keine ordnungsgemäße Art zu trennen, außer durch das Ausstrahlen des Signals. (Sie können
QObject::disconnect
verwenden, aber das würde einen kleinen Speicherverlust verursachen)
- hängt von der Reihenfolge der Ausführung von Steckplätzen ab. Scheint gut für den Moment.
- die Benennung
Getestet mit:
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_;
};
und
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
Prüfregeln Ausgabe:
a1 :
B : 10 a: 1
B : 20 a: 1
a2 :
B : 20 a: 2
a1 :
a2 :
Loswerden von C++ 11/Qt5 (Ich habe nicht Qt 4.8/GCC4.4.7, also nicht mit diesen getestet) Nach dem Dokument, Qt 4.8 hat keinen connect funktioniert, also verwende ich einen Wrapper:
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_;
};
(Ich bin der Konstruktor privat‘ConnectJanitor
machen, weil die Instanz selbst zerstört (delete this
))
und für 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;
}
Wenn Sie manuell die Verbindungen zu brechen, schlage ich weakConnect() Rückkehr der ConnectJanitor des Zeigers zu haben.
Was ist das Problem mit der Funktion 'disconnect()'? – vahancho
Warum willst du nicht 'disconnect' verwenden? Gibt es einen bestimmten Grund? – Robert
Nur zu wissen, ob es einen anderen Weg gibt. Für einige Entwickler, rufen Sie die Disonnect nach dem ersten Aufruf ist ärgerlich, und ich würde gerne wissen, ob es einen Weg gibt, es zu tun. –