Pyside6 how to disconnect connection?
-
@Dariusz I think that the problem is another, or your implementation does not generate the behavior you expect, so it is necessary that you provide an MRE in order to analyze the cause or solution of the problem. I have not asked you for the code of your project, if your project is small then it can be an MRE, but I have asked you to create another script focused on the functionality that generates problems.
-
This might fall into that lambda exception I hinted at. If
self
is a QGraphicsItem, that isn't derived from QObject, and as such doesn't get the automatic disconnection behavior.https://doc.qt.io/qt-6/qobject.html#connect-4 is the C++ equivalent.
-
@jeremy_k said in Pyside6 how to disconnect connection?:
This might fall into that lambda exception I hinted at. If
self
is a QGraphicsItem, that isn't derived from QObject, and as such doesn't get the automatic disconnection behavior.https://doc.qt.io/qt-6/qobject.html#connect-4 is the C++ equivalent.
I think that you are right. QGraphicsItem is not QObject, thus it does not have auto clean up functionality. I believe that's why I have to manually clean up connections.
-
@eyllanesc said in Pyside6 how to disconnect connection?:
Note: Using shiboken2.delete does not remove the python object (the wrapper) but only the handled C++ object.
This is frustrating... I miss C++ aff!
So shibokeh delete the C++ obejct, how do I delete python Object?del self
? -
@Dariusz said in Pyside6 how to disconnect connection?:
In python you can't delete an object,del
only deletes the variable name but not the object(the memory space). I don't understand why deleting an item must imply deleting the connection that is in the scope of the scene. -
@Dariusz said in Pyside6 how to disconnect connection?:
@eyllanesc said in Pyside6 how to disconnect connection?:
Note: Using shiboken2.delete does not remove the python object (the wrapper) but only the handled C++ object.
This is frustrating... I miss C++ aff!
So shibokeh delete the C++ obejct, how do I delete python Object?del self
?That, or remove all references to the item. If the object isn't referenced via a variable that is in scope somewhere else, the python garbage collector should eventually clean up.
-
@eyllanesc said in Pyside6 how to disconnect connection?:
@jeremy_k Exactly, that's why I think the OP has an XY problem
Well the initial signal problem is now solved. Since I delete items and scene remain active, scene does not clean up connections. So I have to manually clean them up.
My second problem is how to properly delete a qgraphicsitem with its children in python. Perhaps I should make another topic for that as this one has solved my main issue.
-
@Dariusz I don't understand how you have solved your current problem, and so far I don't understand what the connection (or disconnection) of the pinReleaseEvent signal of the scene has to do with the elimination of an item since they are 2 different objects. If anyone understands please explain it to me
-
@eyllanesc said in Pyside6 how to disconnect connection?:
@Dariusz The connection you show is not made by the QGraphicsItem but by the scene, so the one that removes the connection in the last instance is the scene.
The issue is that the QGraphicsItem is on the receiving end of the connection, and is effectively captured. The caller doesn't know that the captured item is no longer valid, leading to an invalid condition at call time. In C++, it would be undefined behavior. I don't know what the python terminology is.
Generic C++ example:
int *i = new int; *i = 0; auto f = [i]() { *i++; }; delete i; f();
-
@jeremy_k The question is the following: in bindings such as PySide or PyQt, the ownership of the items is held by the scene, so when you remove the item from the scene then the item has no ownership and is eventually removed by the python GC (python is not C++), and at the time the GC removes the python object it also removes its connections.
-
@eyllanesc said in Pyside6 how to disconnect connection?:
@jeremy_k The question is the following: in bindings such as PySide or PyQt, the ownership of the items is held by the scene, so when you remove the item from the scene then the item has no ownership and is eventually removed by the python GC (python is not C++), and at the time the GC removes the python object it also removes its connections.
Unles signal holds a pointer to object and thus it will never get deleted... since scene didn't disconnect the signal since scene.removeItem() does not delete the item, nor item is QObject so its treated as lambda function (I guess?) as @jeremy_k suggested...
-
@Dariusz To provide what I indicate I can provide a MWE, where every 1 second a signal is emitted and that is connected to an item, in the fifth second the item is removed but it does not cause any error.
from PySide6 import QtCore, QtWidgets class FooItem(QtWidgets.QGraphicsEllipseItem): def foo_slot(self): print("slot") class Scene(QtWidgets.QGraphicsScene): fooSignal = QtCore.Signal() class View(QtWidgets.QGraphicsView): def __init__(self, parent=None): super().__init__(parent) scene = Scene(self) self.setScene(scene) timer = QtCore.QTimer(self, interval=1000) timer.timeout.connect(self.scene().fooSignal) timer.start() item = FooItem() self.scene().addItem(item) self.scene().fooSignal.connect(item.foo_slot) QtCore.QTimer.singleShot(5000, self.remove_item) def remove_item(self): items = self.scene().items() if items: item = items[0] self.scene().removeItem(item) if __name__ == "__main__": app = QtWidgets.QApplication([]) w = View() w.show() app.exec_()
Output:
slot slot slot slot slot
-
The code I had issues with, using PyQt5, is:
from PyQt5.QtCore import QObject obj1 = QObject() obj2 = QObject() obj1.destroyed.connect(lambda: obj2.deleteLater()) del obj2 del obj1
Here, the capture is explicit, and the punishment is swift:
Traceback (most recent call last): File "<stdin>", line 1, in <lambda> NameError: name 'obj2' is not defined Abort trap: 6
-
@jeremy_k First of all GC only removes the objects that have no references.
The problem is very different, in principle when deleteLater is called it deletes the C ++ object and then a reference to the python object is eliminated, if it no longer has references the object would be eliminated as I already indicated, but in your particular case the lambda method has a scope so it has a reference and therefore the python object (the wrapper) will not be eliminated but the C ++ object