Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to connect signal slots between many objects
Forum Updated to NodeBB v4.3 + New Features

How to connect signal slots between many objects

Scheduled Pinned Locked Moved Solved General and Desktop
19 Posts 3 Posters 3.0k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SGaistS SGaist

    Hi,

    Since you say they are unrelated, can you explain why they should be connected to each other ?

    tovaxT Offline
    tovaxT Offline
    tovax
    wrote on last edited by
    #4

    @SGaist
    There is a complicated parent-child relationship between objects in the same thread, which makes it difficult to connect child objects of different threads. I don't know how to deal with this architecture, so I defined a global singleton signal transfer station, through this transfer station to realize the object communication of different threads. However, the coupling of this method is still quite large, and the signal needs to be transferred many times, I feel that this is wrong. I want to know how you realize the communication of sub-objects between threads. Thank you!

    1 Reply Last reply
    0
    • tovaxT Offline
      tovaxT Offline
      tovax
      wrote on last edited by tovax
      #5

      This is the code I found on the web, the purpose is to pass messages directly between multi-layer forms.
      I don't know if this code is the correct way to achieve communication between multiple sub-objects in multiple threads.

      Header

      #pragma once
      #include <qobject.h>
      class obesrverApater;
       
      struct relationData
      {
      	QString type;
      	QObject *receiver;
      	obesrverApater *obesrverApater;
      };
       
      class obesrverApater : public QObject
      {
      	Q_OBJECT
      public:
      	explicit obesrverApater(QObject *parent = 0);
      signals:
      	void notify(const QStringList&);
      };
       
      class GlobalObserver : public QObject
      {
      	Q_OBJECT
      public:
      	static GlobalObserver* GetInstance();
      	static GlobalObserver *m_pInstance;
      	void attach(const QString & type, QObject * receiver, const char * method);
      	void detach(const QString &type, const QObject* reciver);
      	void notify(const QString & type, const QStringList & params);
      private:
      	GlobalObserver();
      	~GlobalObserver();
      private:
      	QList<relationData*> m_oRelationList;
      };
      

      Source

      #include "GlobalObserver.h"
       
      GlobalObserver* GlobalObserver::m_pInstance = nullptr;
       
      GlobalObserver::GlobalObserver()
      {
      }
      GlobalObserver::~GlobalObserver()
      {
      }
       
      GlobalObserver* GlobalObserver::GetInstance()
      {
      	if (m_pInstance == nullptr) {
      		m_pInstance = new GlobalObserver();
      	}
      	return m_pInstance;
      }
       
      void GlobalObserver::attach(const QString& type, QObject* receiver, const char *method)
      {
      	obesrverApater* oa = new obesrverApater();
      	connect(oa, SIGNAL(notify(const QStringList&)), receiver, method);
      	relationData *data = new relationData();
      	data->type = type;
      	data->receiver = receiver;
      	data->obesrverApater = oa;
      	m_oRelationList.append(data);
      }
       
      void GlobalObserver::detach(const QString & type, const QObject * receiver)
      {
      	QList<relationData*>::iterator iter = m_oRelationList.begin();
       
      	while (iter != m_oRelationList.end()){
      		if ((*iter)->type.compare(type) == 0 && (*iter)->receiver == receiver){
      			relationData *data = *iter;
      			m_oRelationList.removeOne((*iter));
      			delete data->obesrverApater;
      			delete data;
      			return;
      		}
      		iter++;
      	}
      }
       
      void GlobalObserver::notify(const QString & type, const QStringList& params)
      {
      	QList<relationData*>::iterator iter = m_oRelationList.begin();
      	while (iter != m_oRelationList.end()){
      		if ((*iter)->type.compare(type) == 0){
      			emit(*iter)->obesrverApater->notify(params);
      		}
      		iter++;
      	}
      }
      

      Test code

      // Attach
      GlobalObserver::GetInstance()->attach("export", this, SLOT(sltAddExportItem(const QStringList&)));
      // Detach
      GlobalObserver::GetInstance()->detach("export", this);
      // Emit signal
      QStringList params;
      GlobalObserver::GetInstance()->notify("export", params);
      
      1 Reply Last reply
      0
      • A Offline
        A Offline
        Asperamanca
        wrote on last edited by
        #6

        I had a similar problem once. My solution was to write a central data model class, which had all the data that needed to be shared between multiple objects on multiple layers.
        The result was that instead of passing data between multiple objects, I would always pass data to the data model first, and the data model offered centralized notification for anyone interested in a specific data point. The web of inter-dependencies became a much more manageable hub, with the side benefit of centralized logging.

        I can't really say whether my solution would really fit your use case, but I hope it helps.

        tovaxT 1 Reply Last reply
        5
        • tovaxT Offline
          tovaxT Offline
          tovax
          wrote on last edited by
          #7

          I want to achieve communication between multiple layers of sub-objects in a low-coupling way.

          class Grandchild1 : public QObject
          {
              Q_OBJECT
          public:
              explicit Grandchild1(QObject *parent = nullptr);
          signals:
              some signals
          public slots:
              some slots
          };
          
          class Grandchild2 : public QObject
          {
              Q_OBJECT
          public:
              explicit Grandchild2(QObject *parent = nullptr);
          signals:
              some signals
          public slots:
              some slots
          };
          
          class Grandchild3 : public QObject
          {
              Q_OBJECT
          public:
              explicit Grandchild3(QObject *parent = nullptr);
          signals:
              some signals
          public slots:
              some slots
          };
          
          class Child1 : public QObject
          {
              Q_OBJECT
          public:
              explicit Child1(QObject *parent = nullptr);
          private:
              Grandchild1 grandchild1;
              Grandchild2 grandchild2;
              Grandchild3 grandchild3;
          signals:
              some signals
          public slots:
              some slots
          };
          
          Class Child2;
          
          Class Child3;
          
          class Object1 : public QObject
          {
              Q_OBJECT
          public:
              explicit Object1(QObject *parent = nullptr);
          private:
              Child1 child1;
              Child2 child2;
              Child3 child3;
          signals:
              some signals
          public slots:
              some slots
          };
          

          qt2.png

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #8

            What kind of messages are you going to exchange between these various unrelated objects ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            tovaxT 1 Reply Last reply
            2
            • SGaistS SGaist

              What kind of messages are you going to exchange between these various unrelated objects ?

              tovaxT Offline
              tovaxT Offline
              tovax
              wrote on last edited by
              #9

              @SGaist
              I'm very sorry, I don’t quite understand what "What kind of messages" means~
              @Asperamanca’s solution explains my doubts very well. If there is no other solution, I will follow Asperamanca ’s suggestion.
              Best regards!

              SGaistS 1 Reply Last reply
              0
              • A Asperamanca

                I had a similar problem once. My solution was to write a central data model class, which had all the data that needed to be shared between multiple objects on multiple layers.
                The result was that instead of passing data between multiple objects, I would always pass data to the data model first, and the data model offered centralized notification for anyone interested in a specific data point. The web of inter-dependencies became a much more manageable hub, with the side benefit of centralized logging.

                I can't really say whether my solution would really fit your use case, but I hope it helps.

                tovaxT Offline
                tovaxT Offline
                tovax
                wrote on last edited by tovax
                #10

                @Asperamanca Hi, thank you very much!
                Your solution is the answer I want, but my English is too bad, and I can't always explain my problem.
                Take the communication between child1 and child2 as an example, is the code like this?

                CentralModel

                class CentralModel : public QObject, public Singleton
                {
                    Q_OBJECT
                public:
                    explicit CentralModel(QObject *parent = nullptr) : QObject(parent) {}
                    ~CentralModel() {}
                
                private:
                    QVariant m_data; //!< shared data between child1 and child2
                    QReadWriteLock m_dataLock; //!< lock for m_data
                
                public:
                    QVariant data() //!< get data
                    {
                        QReadLocker locker(&m_dataLock);
                        return m_data;
                    }
                    void setData(const QVariant value) //!< set data
                    {
                        QWriteLocker locker(&m_dataLock);
                        if (m_data != value) {
                            m_data = value;
                            emit dataChanged(value);
                        }
                    }
                
                signals:
                    void dataChanged(const QVariant value);
                };
                

                Child1

                class Child1 : public QObject,
                {
                    Q_OBJECT
                public:
                    explicit Child1(QObject *parent = nullptr) : QObject(parent) {}
                    ~Child1() {}
                
                public:
                    QVariant func()
                    {
                        CentralModel::getInstance()->setData(3.14);
                    }
                };
                

                Child2

                class Child2 : public QObject,
                {
                    Q_OBJECT
                public:
                    explicit Child2(QObject *parent = nullptr) : QObject(parent)
                    {
                        QObject::connect(CentralModel::getInstance(), SIGNAL(dataChanged(const QVariant)), SLOT(onDataChanged(const QVariant)));
                    }
                    ~Child2() {}
                
                private slots:
                    void onDataChanged(const QVariant value)
                    {
                        qDebug() << value.toDouble();
                    }
                };
                
                
                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  Asperamanca
                  wrote on last edited by
                  #11

                  I would only design the central model as a singleton if you are sure you'll not need a separate model in the future (e.g. old project state vs current project state).
                  You sample code doesn't tell me what you mean by "QVariant data()". If it was just an example, and in reality you'll have multiple properties that should work fine. What I would not do is put every information you have inside the data() and notify everyone if anything changes.

                  One nice trick (if you need it): If you store the data of the whole data model in a separate, copyable class (just place an instance in the DataModel QObject class and use it there), you can always create snapshots of older states of your project data. Also, you can easily implement transaction logic (multiple changes are only applied together once you are ready to push them).

                  tovaxT 2 Replies Last reply
                  1
                  • A Asperamanca

                    I would only design the central model as a singleton if you are sure you'll not need a separate model in the future (e.g. old project state vs current project state).
                    You sample code doesn't tell me what you mean by "QVariant data()". If it was just an example, and in reality you'll have multiple properties that should work fine. What I would not do is put every information you have inside the data() and notify everyone if anything changes.

                    One nice trick (if you need it): If you store the data of the whole data model in a separate, copyable class (just place an instance in the DataModel QObject class and use it there), you can always create snapshots of older states of your project data. Also, you can easily implement transaction logic (multiple changes are only applied together once you are ready to push them).

                    tovaxT Offline
                    tovaxT Offline
                    tovax
                    wrote on last edited by
                    #12

                    @Asperamanca
                    Yes, "QVariant data()" is just an example, there are many different types of data and signals in actual projects.

                    1 Reply Last reply
                    0
                    • A Asperamanca

                      I would only design the central model as a singleton if you are sure you'll not need a separate model in the future (e.g. old project state vs current project state).
                      You sample code doesn't tell me what you mean by "QVariant data()". If it was just an example, and in reality you'll have multiple properties that should work fine. What I would not do is put every information you have inside the data() and notify everyone if anything changes.

                      One nice trick (if you need it): If you store the data of the whole data model in a separate, copyable class (just place an instance in the DataModel QObject class and use it there), you can always create snapshots of older states of your project data. Also, you can easily implement transaction logic (multiple changes are only applied together once you are ready to push them).

                      tovaxT Offline
                      tovaxT Offline
                      tovax
                      wrote on last edited by tovax
                      #13

                      @Asperamanca said in How to connect signal slots between many objects:

                      One nice trick (if you need it): If you store the data of the whole data model in a separate, copyable class (just place an instance in the DataModel QObject class and use it there), you can always create snapshots of older states of your project data. Also, you can easily implement transaction logic (multiple changes are only applied together once you are ready to push them).

                      Do you mean like this?

                      class ExampleModel1 : public QObject //!< Copyable
                      {
                          Q_OBJECT
                      public:
                          explicit ExampleModel1(QObject *parent = nullptr);
                          ~ExampleModel1();
                      private:
                          QVariant exampleData1;
                      public:
                          QVariant getExampleData1();
                          void setExampleData1(const QVariant value);
                      signals:
                          void exampleData1Changed(const QVariant value);
                      };
                      
                      class ExampleModel2 : public QObject //!< Copyable
                      {
                          Q_OBJECT
                      public:
                          explicit ExampleModel2(QObject *parent = nullptr);
                          ~ExampleModel2();
                      private:
                          QVariant exampleData2;
                      public:
                          QVariant getExampleData2();
                          void setExampleData2(const QVariant value);
                      signals:
                          void exampleData2Changed(const QVariant value);
                      };
                      
                      class CentralModel : public QObject, public Singleton  //!< Singleton, Not copyable
                      {
                          Q_OBJECT
                      public:
                          explicit CentralModel(QObject *parent = nullptr);
                          ~CentralModel();
                      
                      public:
                          ExampleModel1 *model1;
                          QReadWriteLock lock1; // lock for model1
                          
                          ExampleModel2 *model2;
                          QReadWriteLock lock2;  // lock for model2
                      };
                      
                      A 1 Reply Last reply
                      0
                      • tovaxT tovax

                        @Asperamanca said in How to connect signal slots between many objects:

                        One nice trick (if you need it): If you store the data of the whole data model in a separate, copyable class (just place an instance in the DataModel QObject class and use it there), you can always create snapshots of older states of your project data. Also, you can easily implement transaction logic (multiple changes are only applied together once you are ready to push them).

                        Do you mean like this?

                        class ExampleModel1 : public QObject //!< Copyable
                        {
                            Q_OBJECT
                        public:
                            explicit ExampleModel1(QObject *parent = nullptr);
                            ~ExampleModel1();
                        private:
                            QVariant exampleData1;
                        public:
                            QVariant getExampleData1();
                            void setExampleData1(const QVariant value);
                        signals:
                            void exampleData1Changed(const QVariant value);
                        };
                        
                        class ExampleModel2 : public QObject //!< Copyable
                        {
                            Q_OBJECT
                        public:
                            explicit ExampleModel2(QObject *parent = nullptr);
                            ~ExampleModel2();
                        private:
                            QVariant exampleData2;
                        public:
                            QVariant getExampleData2();
                            void setExampleData2(const QVariant value);
                        signals:
                            void exampleData2Changed(const QVariant value);
                        };
                        
                        class CentralModel : public QObject, public Singleton  //!< Singleton, Not copyable
                        {
                            Q_OBJECT
                        public:
                            explicit CentralModel(QObject *parent = nullptr);
                            ~CentralModel();
                        
                        public:
                            ExampleModel1 *model1;
                            QReadWriteLock lock1; // lock for model1
                            
                            ExampleModel2 *model2;
                            QReadWriteLock lock2;  // lock for model2
                        };
                        
                        A Offline
                        A Offline
                        Asperamanca
                        wrote on last edited by
                        #14

                        @tovax
                        QObject is never copyable. So the data has to be in classes not derived from QObject. If your only access to these data classes is via you (QObject-derived) Data model, then you have full control when data is changed, and the data model can reliably fire notification signals.

                        tovaxT 1 Reply Last reply
                        1
                        • tovaxT tovax

                          @SGaist
                          I'm very sorry, I don’t quite understand what "What kind of messages" means~
                          @Asperamanca’s solution explains my doubts very well. If there is no other solution, I will follow Asperamanca ’s suggestion.
                          Best regards!

                          SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #15

                          @tovax said in How to connect signal slots between many objects:

                          @SGaist
                          I'm very sorry, I don’t quite understand what "What kind of messages" means~

                          I meant what kind of data are you going to pass around ? Depending on that you might want to consider a publish/subscribe system like mqtt and the corresponding QtMQTT module.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          tovaxT 1 Reply Last reply
                          1
                          • A Asperamanca

                            @tovax
                            QObject is never copyable. So the data has to be in classes not derived from QObject. If your only access to these data classes is via you (QObject-derived) Data model, then you have full control when data is changed, and the data model can reliably fire notification signals.

                            tovaxT Offline
                            tovaxT Offline
                            tovax
                            wrote on last edited by
                            #16

                            @Asperamanca
                            I will try to implement the central model in the project based on your suggestions. Maybe my understanding is not enough at present, but I think I will have a deeper understanding in the process of doing it.
                            Best regards!

                            class CentralData
                            {
                            public:
                                CentralData();
                                ~CentralData();
                                QVariant exampleData1;
                                QVariant exampleData2;
                                QVariant exampleDataN;
                            };
                            
                            class CentralModel : public QObject
                            {
                            public:
                                CentralModel();
                                ~CentralModel();
                            
                            private:
                                CentralData centralData;
                            
                            public:
                                QVariant getExampleData1();
                                void setExampleData1(const QVariant value);
                                QVariant getExampleData2();
                                void setExampleData2(const QVariant value);
                                QVariant getExampleDataN();
                                void setExampleDataN(const QVariant value);
                            
                            signals:
                                void exampleData1Changed(const QVariant value);
                                void exampleData2Changed(const QVariant value);
                                void exampleDataNChanged(const QVariant value);
                            };
                            
                            A 1 Reply Last reply
                            0
                            • SGaistS SGaist

                              @tovax said in How to connect signal slots between many objects:

                              @SGaist
                              I'm very sorry, I don’t quite understand what "What kind of messages" means~

                              I meant what kind of data are you going to pass around ? Depending on that you might want to consider a publish/subscribe system like mqtt and the corresponding QtMQTT module.

                              tovaxT Offline
                              tovaxT Offline
                              tovax
                              wrote on last edited by
                              #17

                              @SGaist Hi, thank you very much for your patience.
                              Data types supported by QVariant, and some custom structures. I will carefully read the link you gave.

                              1 Reply Last reply
                              0
                              • tovaxT tovax

                                @Asperamanca
                                I will try to implement the central model in the project based on your suggestions. Maybe my understanding is not enough at present, but I think I will have a deeper understanding in the process of doing it.
                                Best regards!

                                class CentralData
                                {
                                public:
                                    CentralData();
                                    ~CentralData();
                                    QVariant exampleData1;
                                    QVariant exampleData2;
                                    QVariant exampleDataN;
                                };
                                
                                class CentralModel : public QObject
                                {
                                public:
                                    CentralModel();
                                    ~CentralModel();
                                
                                private:
                                    CentralData centralData;
                                
                                public:
                                    QVariant getExampleData1();
                                    void setExampleData1(const QVariant value);
                                    QVariant getExampleData2();
                                    void setExampleData2(const QVariant value);
                                    QVariant getExampleDataN();
                                    void setExampleDataN(const QVariant value);
                                
                                signals:
                                    void exampleData1Changed(const QVariant value);
                                    void exampleData2Changed(const QVariant value);
                                    void exampleDataNChanged(const QVariant value);
                                };
                                
                                A Offline
                                A Offline
                                Asperamanca
                                wrote on last edited by Asperamanca
                                #18

                                @tovax said in How to connect signal slots between many objects:

                                @Asperamanca
                                I will try to implement the central model in the project based on your suggestions. [...]

                                Yes, that looks about like what I was suggesting.
                                A few notes:

                                • If you ever set the centralData (e.g. to revert to an old state), you'll need a mechanism to trigger all change signals that apply
                                • If all your data is QVariant, you could store it in a single container, and access it via Enum:
                                QVariant getData(const EDataKey eKey) const;
                                

                                However, signals are tricky in this case. You could have a single signal that passes the changed EDataKey (or a List or Set of changed keys for a sum change notification), but it would mean that everyone who is interested in data change will get all notifications, and needs to discard those that are not relevant. You could still make single signals and only one setData/getData, but this would mean some ugly switches in your code, and an inconsistent interface.

                                But this brings me to another question:

                                • Why make all data QVariant? You lose the benefits of type safety. What do you gain?
                                tovaxT 1 Reply Last reply
                                1
                                • A Asperamanca

                                  @tovax said in How to connect signal slots between many objects:

                                  @Asperamanca
                                  I will try to implement the central model in the project based on your suggestions. [...]

                                  Yes, that looks about like what I was suggesting.
                                  A few notes:

                                  • If you ever set the centralData (e.g. to revert to an old state), you'll need a mechanism to trigger all change signals that apply
                                  • If all your data is QVariant, you could store it in a single container, and access it via Enum:
                                  QVariant getData(const EDataKey eKey) const;
                                  

                                  However, signals are tricky in this case. You could have a single signal that passes the changed EDataKey (or a List or Set of changed keys for a sum change notification), but it would mean that everyone who is interested in data change will get all notifications, and needs to discard those that are not relevant. You could still make single signals and only one setData/getData, but this would mean some ugly switches in your code, and an inconsistent interface.

                                  But this brings me to another question:

                                  • Why make all data QVariant? You lose the benefits of type safety. What do you gain?
                                  tovaxT Offline
                                  tovaxT Offline
                                  tovax
                                  wrote on last edited by
                                  #19

                                  @Asperamanca Hi,
                                  I have two kinds of data, the first is the parameter obtained from the database, and its type is QVariant, which is converted when it is used; the second is my customized structure data.

                                  1 Reply Last reply
                                  0

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved