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. Proper way to remove connections from a QGraphicsScene
QtWS25 Last Chance

Proper way to remove connections from a QGraphicsScene

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 4 Posters 363 Views
  • 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.
  • J Offline
    J Offline
    james b-s
    wrote on 3 Apr 2025, 16:52 last edited by
    #1

    Problems removing connections to QGraphicsScene.

    I have a a class indirectly based on QGraphicsModel and another based on QGraphicsScene. In between is QtNodes.

    QtNodes::BasicGraphicsScene contains a bunch of connect statements, like this one:

    connect(&_graphModel,
                &AbstractGraphModel::nodeUpdated,
                this,
                &BasicGraphicsScene::onNodeUpdated);
    

    There is no corresponding disconnect.

    At some point, I am deleting the old scene and replacing it with a new one. The next time that nodeUpdated is emitted, OnNodeUpdated is called for the DELETED old scene. I'm trying to force a disconnect. I unfortunately am not free to modify the QtNodes code. I added code in my scene class that looks like this:

    cSI_QTN_GRAPHICS_SCENE::~cSI_QTN_GRAPHICS_SCENE()
    {
      auto qItems = items();
      for (QGraphicsItem* pItem : qItems) {
        removeItem(pItem);
        delete pItem;
      }
      disconnect(this, 0, 0, 0);
      disconnect(dynamic_cast<QtNodes::DataFlowGraphicsScene*>(this), 0, 0, 0);
    
      auto theGraphModel = dynamic_cast<cSI_QTN_MODEL*>(&graphModel());
      disconnect(theGraphModel, &QtNodes::AbstractGraphModel::nodeUpdated, this, 
                                &QtNodes::BasicGraphicsScene::onNodeUpdated);
    }
    

    I found comments on line that said that one had to delete the items. Didn't think so, but I tried it.
    The first disconnect was to try and disconnect everything.
    The second was another attempt at that. Again, didn't think it would work, but I tried it anyways.
    And the last one is a direct disconnect of the connection.

    Still, whenever nodeUpdated is emitted, onNodeUpdated is called for the old, deleted scene.

    This destructor, emit, and onNodeUpdated are all happening in the same thread.

    What is the proper way to disconnect that connection?

    Thanks

    1 Reply Last reply
    0
    • J Offline
      J Offline
      jeremy_k
      wrote on 3 Apr 2025, 18:03 last edited by
      #2

      https://doc.qt.io/qt-6/qobject.html#disconnect-2

      A signal-slot connection is removed when either of the objects involved are destroyed.

      Explicitly disconnecting a slot for a destroyed object should not be necessary. Is the code using a lambda connection without a context object?

      Asking a question about code? http://eel.is/iso-c++/testcase/

      1 Reply Last reply
      1
      • J Offline
        J Offline
        james b-s
        wrote on 3 Apr 2025, 18:24 last edited by james b-s 4 Mar 2025, 18:31
        #3

        I read that the automatic destruction doesn't work for QGraphicsScene because it doesn't derive from QOBject, but I just checked and it does. derive from QObject.

        So what could cause the behavior that I am seeing? I'm definitely getting a signal to a deleted scene.

        J 1 Reply Last reply 3 Apr 2025, 18:38
        1
        • J james b-s
          3 Apr 2025, 18:24

          I read that the automatic destruction doesn't work for QGraphicsScene because it doesn't derive from QOBject, but I just checked and it does. derive from QObject.

          So what could cause the behavior that I am seeing? I'm definitely getting a signal to a deleted scene.

          J Offline
          J Offline
          JonB
          wrote on 3 Apr 2025, 18:38 last edited by JonB 4 Mar 2025, 18:46
          #4

          @james-b-s
          As @jeremy_k says, so long as your BasicGraphicsScene really is derived from QGraphicsScene/QObject you should not have to do any of the stuff you have in your ~cSI_QTN_GRAPHICS_SCENE() code. Nor should you be seeing the old call. Why don't you set just this up in a standalone test of your own, doing a scene replacement on perhaps a timer, and verify behaviour?

          Also suggest search code for nodeUpdated, as he says if there is a lambda connection on that for slot with no context object (like this) that would still exist and cause this behaviour.

          1 Reply Last reply
          0
          • J Offline
            J Offline
            james b-s
            wrote on 4 Apr 2025, 13:27 last edited by
            #5

            The code that does the connect looks like this:

            connect(&_graphModel,
            &AbstractGraphModel::nodeUpdated,
            this,
            &BasicGraphicsScene::onNodeUpdated);

            I don't see any lambda involved

            J 1 Reply Last reply 4 Apr 2025, 13:58
            0
            • J james b-s
              4 Apr 2025, 13:27

              The code that does the connect looks like this:

              connect(&_graphModel,
              &AbstractGraphModel::nodeUpdated,
              this,
              &BasicGraphicsScene::onNodeUpdated);

              I don't see any lambda involved

              J Offline
              J Offline
              JonB
              wrote on 4 Apr 2025, 13:58 last edited by JonB 4 Apr 2025, 13:58
              #6

              @james-b-s
              Indeed there is not in there. The question is whether they might be elsewhere in code, hence the suggestion to search.

              Btw, attach a slot to the scene's destroyed() signal and confirm you receive that, before your signal.

              1 Reply Last reply
              0
              • J Offline
                J Offline
                james b-s
                wrote on 7 Apr 2025, 16:49 last edited by
                #7

                It appears that at least one of the connections that is having problems does involve a lambda. I found this in the code for the scene (derived from QGraphicsScene)

                connect(&_graphModel,
                        &DataFlowGraphModel::inPortDataWasSet,
                        [this](NodeId const nodeId, PortType const, PortIndex const) { onNodeUpdated(nodeId); });
                

                This is in QtNodes. I am not able to modify this code.

                The sequence of events is

                1. I create a new scene
                2. I replace the scene held by the view with the new scene
                3. I verify that the view has the new scene
                4. I delete the old scene
                5. I start doing stuff, trigging the signal posted above, the signal is received by the old deleted scene.

                I overrode disconnectNotify and verified that the connection is not getting deleted.

                This is Qt 5.15. Without modifying the code in QtNodes, is there anyway for me to force the signal to be disconnected? According to the documentation, the signal should be disconnected when the destruction is complete, but that is not happening. I did find some information online that the signal won't be disconnected because the receiver has been destroyed and is now invalid. So the question remains, is there any way for me to disconnect that connection?

                J 1 Reply Last reply 7 Apr 2025, 16:56
                0
                • J james b-s
                  7 Apr 2025, 16:49

                  It appears that at least one of the connections that is having problems does involve a lambda. I found this in the code for the scene (derived from QGraphicsScene)

                  connect(&_graphModel,
                          &DataFlowGraphModel::inPortDataWasSet,
                          [this](NodeId const nodeId, PortType const, PortIndex const) { onNodeUpdated(nodeId); });
                  

                  This is in QtNodes. I am not able to modify this code.

                  The sequence of events is

                  1. I create a new scene
                  2. I replace the scene held by the view with the new scene
                  3. I verify that the view has the new scene
                  4. I delete the old scene
                  5. I start doing stuff, trigging the signal posted above, the signal is received by the old deleted scene.

                  I overrode disconnectNotify and verified that the connection is not getting deleted.

                  This is Qt 5.15. Without modifying the code in QtNodes, is there anyway for me to force the signal to be disconnected? According to the documentation, the signal should be disconnected when the destruction is complete, but that is not happening. I did find some information online that the signal won't be disconnected because the receiver has been destroyed and is now invalid. So the question remains, is there any way for me to disconnect that connection?

                  J Offline
                  J Offline
                  JonB
                  wrote on 7 Apr 2025, 16:56 last edited by JonB 4 Jul 2025, 17:00
                  #8

                  @james-b-s
                  As we suspected :) That connect() has only 3 parameters, right? Even though it uses [this] for the context I don't think that makes the compiled code treat as destroy on this destruction? (At a guess your connection persists till _graphModel is destroyed?)

                  Change it to take this as 3rd parameter for slot object in standard 4 parameter connect():

                  connect(&_graphModel,
                          &DataFlowGraphModel::inPortDataWasSet,
                          this,    // slot object, destroy connection when `this` object destroyed
                          [this](NodeId const nodeId, PortType const, PortIndex const) { onNodeUpdated(nodeId); });
                  

                  Does that indeed resolve your case?

                  1 Reply Last reply
                  1
                  • Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on 7 Apr 2025, 17:07 last edited by
                    #9

                    For Qt6.7 and up: https://doc.qt.io/qt-6/qobject.html#QT_NO_CONTEXTLESS_CONNECT

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    1 Reply Last reply
                    2
                    • J Offline
                      J Offline
                      james b-s
                      wrote on 8 Apr 2025, 19:42 last edited by
                      #10

                      Unfortunately, that connect is third party code. I cannot change it.

                      J 1 Reply Last reply 8 Apr 2025, 20:51
                      0
                      • J james b-s
                        8 Apr 2025, 19:42

                        Unfortunately, that connect is third party code. I cannot change it.

                        J Offline
                        J Offline
                        JonB
                        wrote on 8 Apr 2025, 20:51 last edited by JonB 4 Aug 2025, 20:59
                        #11

                        @james-b-s
                        Then I think you have a problem! I believe to disconnect a lambda explicitly (if you cannot introduce a slot object) you need to store the result of the connect() and pass that to disconnect(). But presumably you cannot do that either if the code you show is untouchable third-party?

                        P.S.
                        If you're interested in a discussion on this slot-lambda-functor-without-slot-object destruction problem read through https://interest.qt-project.narkive.com/AiSB9wkP/who-disconnects-lambda-expression-slots from when it was raised 12 years ago :)

                        1 Reply Last reply
                        1

                        1/11

                        3 Apr 2025, 16:52

                        • Login

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