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.5k 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.
  • 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