I'm trying to create a resizable QGraphicsRectItem with an option to choose different draw styles.
If I create a simple rect with a resize feature only, then it works as expected:
class Rectangle(QtWidgets.QGraphicsRectItem):
def __init__(self, x, y, w, h):
super(Rectangle, self).__init__(0, 0, w, h)
self.setPen(QtGui.QPen(QtCore.Qt.red, 2))
self.setFlags(QtWidgets.QGraphicsItem.ItemIsSelectable
| QtWidgets.QGraphicsItem.ItemIsMovable
| QtWidgets.QGraphicsItem.ItemIsFocusable
| QtWidgets.QGraphicsItem.ItemSendsGeometryChanges
| QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges)
self.setPos(QtCore.QPointF(x, y))
self.rect = rect = QtCore.QRectF(0, 0, 200, 200)
def boundingRect(self):
return self.rect.adjusted(-10, -10, 10, 10)
def mouseMoveEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
super(Rectangle, self).mouseMoveEvent(event)
if event.buttons() & QtCore.Qt.RightButton:
self.rect = QtCore.QRectF(QtCore.QPoint(), event.pos()).normalized()
self.prepareGeometryChange()
self.setRect(self.rect)
When i try to modify it to change pen styles and color if active, it becomes unselectable and unfocusable. More than that, the bounding rect disappears unexpectedly. Here's a modified version:
class Rectangle(QtWidgets.QGraphicsRectItem):
def __init__(self, position, scene, style=QtCore.Qt.SolidLine,
rect=None, matrix=QtGui.QMatrix()):
super(Rectangle, self).__init__()
# self.setPen(QtGui.QPen(QtCore.Qt.red, 2))
self.setFlags(QtWidgets.QGraphicsItem.ItemIsSelectable
| QtWidgets.QGraphicsItem.ItemIsMovable
| QtWidgets.QGraphicsItem.ItemIsFocusable
| QtWidgets.QGraphicsItem.ItemSendsGeometryChanges
| QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges)
if rect is None:
rect = QtCore.QRectF(0, 0, 200, 200)
self.size = QtCore.QPointF(200, 200)
self.rect = rect
self.style = style
self.setPos(position)
self.setMatrix(matrix)
scene.clearSelection()
scene.addItem(self)
self.setSelected(True)
self.setFocus()
global RAW
RAW = True
self.pen = QtGui.QPen(self.style)
self.pen.setColor(QtCore.Qt.black)
self.pen.setWidth(1)
def parentWidget(self):
return self.scene().views()[0]
def boundingRect(self):
return self.rect.adjusted(-10, -10, 10, 10)
def paint(self, painter, option, widget):
if option.state & QtWidgets.QStyle.State_Selected:
self.pen.setColor(QtCore.Qt.blue)
painter.setPen(self.pen)
painter.drawRect(self.rect)
def itemChange(self, change, variant):
if change != QtWidgets.QGraphicsItem.ItemSelectedChange:
global RAW
RAW = True
return QtWidgets.QGraphicsItem.itemChange(self, change, variant)
def contextMenuEvent(self, event):
wrapped = []
menu = QtWidgets.QMenu(self.parentWidget())
for text, param in (("&Solid", QtCore.Qt.SolidLine),
("&Dashed", QtCore.Qt.DashLine),
("D&otted", QtCore.Qt.DotLine),
("D&ashDotted", QtCore.Qt.DashDotLine),
("DashDo&tDotten", QtCore.Qt.DashDotDotLine)):
wrapper = functools.partial(self.setStyle, param)
wrapped.append(wrapper)
menu.addAction(text, wrapper)
menu.exec_(event.screenPos())
def setStyle(self, style):
#self.prepareGeometryChange()
self.style = style
self.update()
global RAW
RAW = True
def mousePressEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
super(Rectangle, self).mouseMoveEvent(event)
if event.buttons() & QtCore.Qt.MiddleButton:
if self.isSelected():
self.rect = QtCore.QRectF(QtCore.QPoint(), event.pos()).normalized()
self.prepareGeometryChange()
self.setRect(self.rect)
global RAW
RAW = True
I guess that the main problem lays in reimplemented paint() function but I still haven't come up with any idea where exactly...
Could anyone explain what am I doing wrong? Where's a mistake and how to make this thing work properly?
I do not have the middle button on my touchpad so I have implemented the logic with the right button but I have given a small edge of 10px where you can change the size of the rectangle.
To change the style you just have to change the QPen of the QGraphicsItem.