如何限制 QGraphicsScene 中自定义 QGraphicsItem 可以移动的区域?

问题描述 投票:0回答:2

我有一个 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的回答)

python pyside2
2个回答
2
投票

这个概念是在最终应用之前限制新位置。

为此,您还需要设置

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()
    是所有项目的现有(并且非常重要)功能,您不得覆盖它;

0
投票
通过重新实现

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 提供的方法不适合我的目的。

© www.soinside.com 2019 - 2024. All rights reserved.