I want to know if there's a way of getting a QGraphicsItem's id. Nothing complicated. Lets say I have a QGraphicsScene and I created a lot of rectangles of the same size and color in it. Even if not with ids, than how can I identify them?
UPDATE Here's some of my code
class Test(QtWidgets.QDialog):
def __init__(self):
super(Test, self).__init__()
loader = QtUiTools.QUiLoader()
self.ui = loader.load(ui_path, self)
self.variables()
self.ui.create_button.clicked.connect(self.creator)
self.scene.focusItemChanged.connect(self.nameDisplay)
def variables(self):
self.scene = QtWidgets.QGraphicsScene()
self.ui.canvas_area.setScene(self.scene)
def creator(self):
rect = self.scene.addRect(-20,-20,40,40, QPen(Qt.red), QBrush(Qt.gray))
rect.setFlag(QGraphicsItem.ItemIsMovable)
rect.setFlag(QGraphicsItem.ItemIsFocusable)
rect.setFlag(QGraphicsItem.ItemIsSelectable)
def nameDisplay(self, newFocusItem, oldFocusItem, reason):
self.ui.name_line.setText(str(self.scene.focusItem()))
if __name__ == '__main__':
test_window = Test()
test_window.ui.show()
Thanks in advance!
QGraphicsItem is not a QObject, so it doesn't support the property system, but it has limited support for storing properties through setData()
.
class Test(QtWidgets.QDialog):
count = 0
# ...
def creator(self):
rect = self.scene.addRect(-20,-20,40,40, QPen(Qt.red), QBrush(Qt.gray))
rect.setFlag(QGraphicsItem.ItemIsMovable)
rect.setFlag(QGraphicsItem.ItemIsFocusable)
rect.setFlag(QGraphicsItem.ItemIsSelectable)
rect.setData(0, self.count)
self.count += 1
def nameDisplay(self, newFocusItem, oldFocusItem, reason):
if newFocusItem and newFocusItem.data(0) is not None:
self.ui.name_line.setText('Item {}'.format(newFocusItem.data(0)))
Note: the key
argument of setData()
and data()
must be an integer, and there's no way to know if (and which) keys are set: you can only check if the key value is not None
. If you need more complex data mapping, you can use a dictionary as value, or just subclass (see below).
It's important to consider that while one might try to set an attribute for the item returned by addRect()
, it wouldn't work: we should remember that PyQt is a binding to Qt, and all python objects used for Qt objects are wrappers.
Consider the following:
def creator(self):
# ...
rect.id = self.count
def nameDisplay(self, newFocusItem, oldFocusItem, reason):
print(hasattr(newFocusItem, 'id')
This will always print False
, and that's because we only created an attribute for the wrapper reference in creator
, but since that reference is just local and the attribute is set on that reference (not the wrapped object), it will be garbage collected and the attribute will be lost.
A possible option would be to add a persistent reference for each item:
class Test(QtWidgets.QDialog):
def __init__(self):
# ...
self.items = []
def creator(self):
# ...
rect.id = self.count
self.items.append(rect)
But I'd suggest to stick with the setData()
option, as it is more compliant with how Qt works.
Alternatively, we can create a custom QGraphicsRectItem subclass and add it with self.scene.addItem()
. In that case, the python wrapper will be persistent and the attribute will be preserved:
class MyRect(QtWidgets.QGraphicsRectItem):
def __init__(self, id, x, y, w, h, pen, brush):
super().__init__(x, y, w, h)
self.id = id
self.setPen(pen)
self.setBrush(brush)
class Test(QtWidgets.QDialog):
# ...
def creator(self):
rect = MyRect(self.count, -20, -20, 40, 40, QPen(Qt.red), QBrush(Qt.gray))
self.scene.addItem(rect)
# ...
def nameDisplay(self, newFocusItem, oldFocusItem, reason):
if hasattr(newFocusItem, 'id'):
self.name_line.setText('Item {}'.format(newFocusItem.id))