PyQt - 是否有将 QGraphicsItem 移动限制到特定线路路径的实现?

PyQt - Is there an implementation to constrain QGraphicsItem movement to a certain line path?

我试图通过在移动矩形鼠标时使矩形项目的原点跟随此 QGraphicsLineItem 来限制此 QGraphicsRectItem 的移动。

有什么方法可以做到吗?

我通过创建修改后的矩形项目和订单项,通过简单的实现获得了它:

class Rectangle(QGraphicsRectItem):
    def __init__(self, x=0, y=0, w=0, h=0, pathes=[]):
        super(Rectangle, self).__init__(x, y, w, h)  # x, y are internal object coordinates
        self.setTransformOriginPoint(int(w / 2), int(h / 2))  # setting the origin point to the middle
        self.origin = self.transformOriginPoint()  # returns QPointF
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges)

        self.pathes = pathes


    def item_on_path(self, new_point):
        new_point = QPointF(new_point.x() + self.origin.x(), new_point.y() + self.origin.y())
        for path in self.pathes:
            if path.contains(new_point):
                return True
        return False


class Line(QGraphicsLineItem):
    def __init__(self, pt1, pt2):
        super(Line, self).__init__(pt1[0], pt1[1], pt2[0], pt2[1])

然后用QShortcut创建场景对象进行键盘控制并设置场景:

class graphicsViewObject(QGraphicsView):
    def __init__(self):
        super(graphicsViewObject, self).__init__()

        self.scene = QGraphicsScene()

        black_pen = QPen(Qt.black)
        black_pen.setWidth(5)

        self.setScene(self.scene)

        self.speed = 10  # keyboard movement change value

        pt1 = (200, 200)
        pt2 = (800, 200)

        self.line_1 = Line(pt1, pt2)
        self.line_1.setPen(black_pen)
        self.scene.addItem(self.line_1)

        self.rect = Rectangle(w=200, h=200, pathes=[self.line_1])
        self.rect.setPen(black_pen)
        self.rect.setBrush(QBrush(Qt.red))
        self.scene.addItem(self.rect)

        # Moving the rectangle origin to the first point of the line
        self.rect.setPos(QPointF(pt1[0] - self.rect.origin.x(), pt1[1] - self.rect.origin.y()))

        QShortcut(Qt.Key_Up, self, self.fooUp)
        QShortcut(Qt.Key_Down, self, self.fooDown)
        QShortcut(Qt.Key_Left, self, self.fooLeft)
        QShortcut(Qt.Key_Right, self, self.fooRight)


    def fooUp(self):
        for item in self.scene.selectedItems():
            pos = item.scenePos()
            pos.setY(pos.y() - self.speed)
            item_inside_scene = self.scene.sceneRect().contains(item.mapRectToScene(item.boundingRect()))
            if item.item_on_path(pos) and item_inside_scene:
                item.setPos(pos)


    def fooDown(self):
        for item in self.scene.selectedItems():
            pos = item.scenePos()
            pos.setY(pos.y() + self.speed)
            item_inside_scene = self.scene.sceneRect().contains(item.mapRectToScene(item.boundingRect()))
            if item.item_on_path(pos) and item_inside_scene:
                item.setPos(pos)


    def fooLeft(self):
        for item in self.scene.selectedItems():
            pos = item.scenePos()
            pos.setX(pos.x() - self.speed)
            item_inside_scene = self.scene.sceneRect().contains(item.mapRectToScene(item.boundingRect()))
            if item.item_on_path(pos) and item_inside_scene:
                item.setPos(pos)


    def fooRight(self):
        for item in self.scene.selectedItems():
            pos = item.scenePos()
            pos.setX(pos.x() + self.speed)
            item_inside_scene = self.scene.sceneRect().contains(item.mapRectToScene(item.boundingRect()))
            if item.item_on_path(pos) and item_inside_scene:
                item.setPos(pos)