I have a QGraphicsItem
called child_item
that is a child of another QGraphicsItem
called parent_item
. I need to unparent child_item
from parent_item
so that child_item
has no parent.
But when I try childItem.setItemParent(None)
my script crashes.
Apparently this is because when you remove a QGraphicsItem
's parent in this way the item is returned to Qt...
For now I've just created a global_parent
QGraphicsItem
so that if any item needs to be unparented I will simply parent it under the global_parent
and if a QGraphicsItem
has the parent global_parent
my code will act like it doesn't have a parent but I would like a better solution.
Any ideas please?
POINT_SIZE = 7
class Test_Box(QGraphicsItem):
# Constants
WIDTH = 50 * POINT_SIZE
HEIGHT = 13 * POINT_SIZE
RECT = QRectF(0, 0, WIDTH, HEIGHT)
CORNER_RADIUS = 1.5 * POINT_SIZE
def __init__(self, position, parent=None):
super(Test_Box, self).__init__(parent)
# Settings
self.setFlags( self.flags() |
QGraphicsItem.ItemIsSelectable |
QGraphicsItem.ItemIsMovable |
QGraphicsItem.ItemIsFocusable |
QGraphicsItem.ItemSendsScenePositionChanges )
self.setPos(position)
def boundingRect(self):
return Test_Box.RECT
def paint(self, painter, option, widget):
# Draw Box
brush = QBrush()
painter.setBrush(brush)
painter.drawRoundedRect(Test_Box.RECT, Test_Box.CORNER_RADIUS, Test_Box.CORNER_RADIUS)
def itemChange(self, change, variant):
super(Test_Box, self).itemChange(change, variant)
if change == QGraphicsItem.ItemScenePositionHasChanged:
self.setParentItem(None)
return QGraphicsItem.itemChange(self, change, variant)
Calling setItemParent and setting the item's parent to another item does work though so I'm using a generic parent in the meantime.
If that setParent
is not a typo, then that is your issue. A QGraphicsItem
has no setParent
method and that should give you an error. You should rather use setParentItem
:
children.setParentItem(None)
Edit
I created a test case based on your item:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
POINT_SIZE = 7
class Test_Box(QGraphicsItem):
# Constants
WIDTH = 50 * POINT_SIZE
HEIGHT = 13 * POINT_SIZE
RECT = QRectF(0, 0, WIDTH, HEIGHT)
CORNER_RADIUS = 1.5 * POINT_SIZE
def __init__(self, position, parent=None):
super(Test_Box, self).__init__(parent)
# Settings
self.setFlags( self.flags() |
QGraphicsItem.ItemIsSelectable |
QGraphicsItem.ItemIsMovable |
QGraphicsItem.ItemIsFocusable |
QGraphicsItem.ItemSendsScenePositionChanges )
self.setPos(position)
def boundingRect(self):
return Test_Box.RECT
def paint(self, painter, option, widget):
# Draw Box
brush = QBrush()
painter.setBrush(brush)
painter.drawRoundedRect(Test_Box.RECT, Test_Box.CORNER_RADIUS, Test_Box.CORNER_RADIUS)
def itemChange(self, change, variant):
super(Test_Box, self).itemChange(change, variant)
if change == QGraphicsItem.ItemScenePositionHasChanged:
self.setParentItem(None)
return QGraphicsItem.itemChange(self, change, variant)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.scene = QGraphicsScene()
self.item1 = Test_Box(QPointF(0, 0))
self.item2 = Test_Box(QPointF(20, 20))
self.item11 = Test_Box(QPointF(10, 5), self.item1)
self.scene.addItem(self.item1)
self.scene.addItem(self.item2)
self.view = QGraphicsView(self.scene)
self.listItems = QPushButton('list')
self.listItems.clicked.connect(self.printItems)
layout = QHBoxLayout()
layout.addWidget(self.view)
layout.addWidget(self.listItems)
self.setLayout(layout)
def printItems(self):
for item in self.scene.items():
print item, item.parentItem()
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
And it works as expected, but I did find some odd behavior. If I don't keep references for items in the Window
class, namely if I do the following then the application crashes when I move items.
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.scene = QGraphicsScene()
item1 = Test_Box(QPointF(0, 0))
item2 = Test_Box(QPointF(20, 20))
item11 = Test_Box(QPointF(10, 5), item1)
self.scene.addItem(item1)
self.scene.addItem(item2)
self.view = QGraphicsView(self.scene)
self.listItems = QPushButton('list')
self.listItems.clicked.connect(self.printItems)
layout = QHBoxLayout()
layout.addWidget(self.view)
layout.addWidget(self.listItems)
self.setLayout(layout)
def printItems(self):
for item in self.scene.items():
print item, item.parentItem()
I don't actually know what happens but looks like the items are garbage collected, which shouldn't happen since addItem
would give the ownership to the scene
and that should keep the items 'alive'. This may be a bug in PyQt, but I'm not sure.