Doğukan Tunç
Doğukan Tunç

Reputation: 347

How to connect signals to the slots of all instances of a class

I have a simple class, and I will create let's say, 100 instances of that class.

Is there a way to connect a slot in all and any of this his class' objects' to a single signal (or vice versa) before creating the instances (since connecting every object one by one is tiresome work, obviously).

Thanks for any ideas in advance and I gladly welcome any different approaches.

Upvotes: 1

Views: 1900

Answers (2)

S.M.Mousavi
S.M.Mousavi

Reputation: 5246

you can store pointers of all instances in an static list within constructor and remove it within destructor:

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);
    void myMethod1();
    ~MyClass();

signals:
    void globalSignal();

public slots:

private:
    static QList<MyClass *> m_allInstances;
    void emitSignal4All();
};

#endif // MYCLASS_H

myclass.cpp

#include <QDebug>
#include "myclass.h"

QList<MyClass *> MyClass::m_allInstances;

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    m_allInstances.append(this);
}

void MyClass::myMethod1()
{
    //... sample usage of `emitSignal4All()`
    emitSignal4All();
}

MyClass::~MyClass()
{
    m_allInstances.removeOne(this);
}

void MyClass::emitSignal4All()
{
    for(int i = 0; i<m_allInstances.count(); i++) {
        emit m_allInstances.at(i)->globalSignal();
    }
}

sample usage

    MyClass instance1;
    MyClass *instance2 = new MyClass();
    connect(&instance1, &MyClass::globalSignal, this, [&instance1, this]() {
        qDebug() << "signal of instance1 is fired!";
    });
    connect(instance2, &MyClass::globalSignal, this, [instance2, this]() {
        qDebug() << "signal of instance2 is fired!";
    });

    MyClass instance3;
    instance3.myMethod1();

Upvotes: 2

Damien
Damien

Reputation: 1552

There is a simple way to do it by using a singleton class to which the instantiated class will connect by their own:


Singleton class which will provide a single entry point:

class Linker : public QObject
{
    Q_OBJECT

public:
        static Linker * getInstance(QObject *parent = 0)
        {
           static Linker * instance = new Linker(parent);
           return instance;
        }

        sendSignal()
        {
            emit mySignal();
        }

 signals:
        void mySignal();
};

Class to be instantiated:

class ClassToBeInstencied  : public QObject
{
    Q_OBJECT

private slots:
    void mySlot() {}

public:

    ClassToBeInstencied() // constructor
    {
        connect(this, &ClassToBeInstencied::mySlot, Linker::getInstance(), &Linker::mySignal);
    }
};

This has the advantage to keep your code clean and simple as you don't have to handle the connection to the signal / slot outside of the class, so it is well encapsulated.

You just need to create a new instance:

ClassToBeInstencied  * a = new ClassToBeInstencied();
ClassToBeInstencied  * b = new ClassToBeInstencied();
ClassToBeInstencied  * c = new ClassToBeInstencied();

and the connection will be automatically done.

You can send a signal to all directly with:

Linker::getInstance()->sendSignal();

Advantage: No list, no loop nothing necessary to manage outside the class and no need of manually connecting each instance.

Upvotes: 3

Related Questions