Proper way to remove connections from a QGraphicsScene
-
wrote 23 days ago last edited by
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?
-
wrote 23 days ago last edited by james b-s 4 Mar 2025, 18:31
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.
-
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.
wrote 23 days ago last edited by JonB 4 Mar 2025, 18:46@james-b-s
As @jeremy_k says, so long as yourBasicGraphicsScene
really is derived fromQGraphicsScene/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 (likethis
) that would still exist and cause this behaviour. -
wrote 22 days ago last edited by
The code that does the connect looks like this:
connect(&_graphModel,
&AbstractGraphModel::nodeUpdated,
this,
&BasicGraphicsScene::onNodeUpdated);I don't see any lambda involved
-
The code that does the connect looks like this:
connect(&_graphModel,
&AbstractGraphModel::nodeUpdated,
this,
&BasicGraphicsScene::onNodeUpdated);I don't see any lambda involved
wrote 22 days ago last edited by JonB 22 days ago@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. -
wrote 19 days ago last edited by
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
- I create a new scene
- I replace the scene held by the view with the new scene
- I verify that the view has the new scene
- I delete the old scene
- 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?
-
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
- I create a new scene
- I replace the scene held by the view with the new scene
- I verify that the view has the new scene
- I delete the old scene
- 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?
wrote 19 days ago last edited by JonB 4 Jul 2025, 17:00@james-b-s
As we suspected :) Thatconnect()
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 onthis
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 parameterconnect()
: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?
-
For Qt6.7 and up: https://doc.qt.io/qt-6/qobject.html#QT_NO_CONTEXTLESS_CONNECT
-
wrote 18 days ago last edited by
Unfortunately, that connect is third party code. I cannot change it.
-
wrote 18 days ago last edited by JonB 4 Aug 2025, 20:59
@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 theconnect()
and pass that todisconnect()
. 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 :)
11/11