调整 QGraphicsRectItem 的大小和重新绘制的 PyQt 问题
Posted
技术标签:
【中文标题】调整 QGraphicsRectItem 的大小和重新绘制的 PyQt 问题【英文标题】:PyQt issue with resizing and repainting of QGraphicsRectItem 【发布时间】:2019-03-21 17:43:48 【问题描述】:我正在尝试创建一个可调整大小的 QGraphicsRectItem,并带有选择不同绘制样式的选项。
如果我创建一个仅具有调整大小功能的简单矩形,那么它会按预期工作:
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)
当我尝试修改它以更改笔样式和颜色(如果处于活动状态)时,它变得无法选择且无法聚焦。不仅如此,边界矩形出乎意料地消失了。这是修改后的版本:
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
我猜主要问题在于重新实现的 paint() 函数,但我仍然没有想出任何想法 在哪里 ...
谁能解释我做错了什么? 哪里出错了,如何让这个东西正常工作?
【问题讨论】:
【参考方案1】:我的触摸板上没有中间按钮,所以我用右键实现了逻辑,但我给出了一个 10 像素的小边缘,您可以在其中更改矩形的大小。
要更改样式,您只需更改 QGraphicsItem 的 QPen。
import functools
from PyQt5 import QtCore, QtGui, QtWidgets
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))
def mouseMoveEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
super(Rectangle, self).mouseMoveEvent(event)
if event.buttons() & QtCore.Qt.RightButton:
rect = QtCore.QRectF(QtCore.QPoint(), event.pos()).normalized()
self.prepareGeometryChange()
self.setRect(rect)
def contextMenuEvent(self, event):
super(Rectangle, self).contextMenuEvent(event)
delta = 10
r = self.boundingRect()
r.adjust(delta, delta, -delta, -delta)
if not r.contains(event.pos()):
return
self.setSelected(True)
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 paint(self, painter, option, widget):
painter.setPen(self.pen())
painter.setBrush(self.brush())
if option.state & QtWidgets.QStyle.State_Selected:
pen = self.pen()
pen.setColor(QtCore.Qt.blue)
painter.setPen(pen)
painter.setBrush(QtCore.Qt.NoBrush)
painter.drawRect(self.boundingRect())
def setStyle(self, style):
pen = self.pen()
pen.setStyle(style)
self.setPen(pen)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
scene = QtWidgets.QGraphicsScene(-400, -400, 800, 800)
w = QtWidgets.QGraphicsView(scene)
scene.addItem(Rectangle(100, 100, 100, 100))
w.show()
sys.exit(app.exec_())
【讨论】:
以上是关于调整 QGraphicsRectItem 的大小和重新绘制的 PyQt 问题的主要内容,如果未能解决你的问题,请参考以下文章
QGraphicsRectItem中如何实现信号和槽?子类化 qobject 和 qgraphicsrectitem 但出现错误
如何在一个类中继承 QGraphicsRectItem 和 QGraphicsEllipseItem?
QGraphicsView Scale & QGraphicsRectItem 绘画未能调用