我有一个 QGraphicsScene,其中有 QGraphicsItems。这些项目是可移动的,我可以在整个 QGraphicsScene 中移动它们,但我想限制这些项目可以移动的区域。 QGraphicsScene 的大小不必改变。如果有人给我一个如何在 python 中执行此操作的示例,我将非常感激。
这就是我现在拥有的
from PySide2.QtCore import QPointF
from PySide2.QtWidgets import QWidget, QVBoxLayout, QGraphicsView, \
QGraphicsScene, QGraphicsPolygonItem, QApplication
from PySide2.QtGui import QPen, QColor, QBrush, QPolygonF
class Test(QWidget):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.resize(1000, 800)
self.layout_ = QVBoxLayout()
self.view_ = GraphicsView()
self.layout_.addWidget(self.view_)
self.setLayout(self.layout_)
class GraphicsView(QGraphicsView):
def __init__(self):
super(GraphicsView, self).__init__()
self.scene_ = QGraphicsScene()
self.polygon_creation = self.PolyCreation()
self.scene_.setSceneRect(0, 0, 400, 400)
self.setScene(self.scene_)
self.polyCreator()
def polyCreator(self):
self.polygon_creation.poly()
polygon = self.polygon_creation.polygon()
new_poly = self.scene().addPolygon(polygon)
new_poly.setBrush(QBrush(QColor("gray")))
new_poly.setPen(QPen(QColor("gray")))
new_poly.setFlag(QGraphicsPolygonItem.ItemIsSelectable)
new_poly.setFlag(QGraphicsPolygonItem.ItemIsMovable)
new_poly.setFlag(QGraphicsPolygonItem.ItemIsFocusable)
new_poly.setPos(0, 0)
class PolyCreation(QGraphicsPolygonItem):
def __init__(self):
super().__init__()
self.setAcceptHoverEvents(True)
def poly(self):
self.poly_points = (QPointF(0, 0),
QPointF(0, 50),
QPointF(50, 50),
QPointF(50, 0))
self.shape = QPolygonF(self.poly_points)
self.setPolygon(self.shape)
if __name__ == '__main__':
app = QApplication([])
win = Test()
win.show()
app.exec_()
我也在cpp中找到了答案,但我不太理解它,所以如果有人可以用python“翻译”它,那就太好了。 这是链接限制qgraphicsitem的可移动区域(请检查@Robert的回答)
这个概念是在最终应用之前限制新位置。
为此,您还需要设置ItemSendsGeometryChanges
标志并检查
ItemPositionChange
更改,然后将项目边界矩形与场景的边界矩形进行比较,并最终在更正后返回不同的位置。
class PolyCreation(QGraphicsPolygonItem):
def __init__(self):
super().__init__(QPolygonF([
QPointF(0, 0),
QPointF(0, 50),
QPointF(50, 50),
QPointF(50, 0)
]))
self.setBrush(QBrush(QColor("gray")))
self.setPen(QPen(QColor("blue")))
self.setFlags(
self.ItemIsSelectable
| self.ItemIsMovable
| self.ItemIsFocusable
| self.ItemSendsGeometryChanges
)
self.setAcceptHoverEvents(True)
def itemChange(self, change, value):
if change == self.ItemPositionChange and self.scene():
br = self.polygon().boundingRect().translated(value)
sceneRect = self.scene().sceneRect()
if not sceneRect.contains(br):
if br.right() > sceneRect.right():
br.moveRight(sceneRect.right())
if br.x() < sceneRect.x():
br.moveLeft(sceneRect.x())
if br.bottom() > sceneRect.bottom():
br.moveBottom(sceneRect.bottom())
if br.y() < sceneRect.y():
br.moveTop(sceneRect.top())
return br.topLeft()
return super().itemChange(change, value)
class GraphicsView(QGraphicsView):
def __init__(self):
super(GraphicsView, self).__init__()
self.scene_ = QGraphicsScene()
self.scene_.setSceneRect(0, 0, 400, 400)
self.setScene(self.scene_)
self.scene_.addItem(PolyCreation())
备注:
sceneTransform()
来获取多边形的实际边界矩形;
boundingRect()
并使用笔宽度的一半来调整;
(0, 0)
,再次指定是没有意义的;
shape()
是所有项目的现有(并且非常重要)功能,您不得覆盖它;
mouseMoveEvent 方法,可以轻松限制项目离开 sceneRect:
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent):
# 1. Finding the maximum movements that can be made before leaving the scene's
# bounding rectangle:
rect = self.mapRectToScene(self.boundingRect())
max_left_move = self.scene().sceneRect().left() - min(rect.left(), rect.right())
max_right_move = self.scene().sceneRect().right() - max(rect.left(), rect.right())
max_up_move = self.scene().sceneRect().top() - min(rect.top(), rect.bottom())
max_down_move = self.scene().sceneRect().bottom() - max(rect.top(), rect.bottom())
# 2. Calculating the initial vector of movement
move = event.pos() - event.buttonDownPos(Qt.LeftButton)
# 3. Correcting the movement vector if it causes the item to leave the area:
move.setX(np.clip(move.x(), max_left_move, max_right_move))
move.setY(np.clip(move.y(), max_up_move, max_down_move))
# 4. Moving the item
self.moveBy(move.x(), move.y())
由于我需要通过转换来限制项目,@musicamante 提供的方法不适合我的目的。