You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

限制QGraphicsItem移动区域的Python实现(无需修改QGraphicsScene尺寸)

需求回顾

你现在有一个包含可移动QGraphicsItem的QGraphicsScene,目前项能在整个场景范围内自由移动,想要限制它们的可移动区域,同时保持QGraphicsScene的原有尺寸不变。

核心思路

其实不用动场景本身,只需要给每个需要限制移动的QGraphicsItem重写itemChange方法——当项的位置发生变化时,提前检查新位置是否在允许的范围内,如果超出就修正位置,这样就能把项“锁”在指定区域里了。

修改后的完整代码

from PySide2.QtCore import QPointF, QRectF, QEvent
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.scene_.setSceneRect(0, 0, 400, 400)
        self.setScene(self.scene_)
        self.polyCreator()

    def polyCreator(self):
        # 创建自定义的带移动限制的多边形项
        poly_points = (QPointF(0, 0), QPointF(0, 50), QPointF(50, 50), QPointF(50, 0))
        polygon = QPolygonF(poly_points)
        new_poly = RestrictedPolygonItem(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)
        self.scene_.addItem(new_poly)

class RestrictedPolygonItem(QGraphicsPolygonItem):
    def __init__(self, polygon, parent=None):
        super().__init__(polygon, parent)
        # 定义允许的移动区域:这里设置为场景内(50,50)到(350,350)的矩形
        self.allowed_rect = QRectF(50, 50, 300, 300)

    def itemChange(self, change, value):
        # 当项的位置即将发生变化时触发
        if change == QGraphicsPolygonItem.ItemPositionChange and self.scene():
            # 获取项的边界矩形
            item_rect = self.boundingRect()
            # 计算新位置对应的项的全局矩形
            new_item_rect = QRectF(value.x(), value.y(), item_rect.width(), item_rect.height())
            
            # 检查是否超出允许区域,超出则修正位置
            if not self.allowed_rect.contains(new_item_rect):
                # 计算修正后的x坐标
                if new_item_rect.left() < self.allowed_rect.left():
                    value.setX(self.allowed_rect.left())
                elif new_item_rect.right() > self.allowed_rect.right():
                    value.setX(self.allowed_rect.right() - item_rect.width())
                
                # 计算修正后的y坐标
                if new_item_rect.top() < self.allowed_rect.top():
                    value.setY(self.allowed_rect.top())
                elif new_item_rect.bottom() > self.allowed_rect.bottom():
                    value.setY(self.allowed_rect.bottom() - item_rect.height())
        
        return super().itemChange(change, value)

if __name__ == '__main__':
    app = QApplication([])
    win = Test()
    win.show()
    app.exec_()

关键改动说明

  1. 自定义RestrictedPolygonItem类:继承自QGraphicsPolygonItem,专门用来处理移动限制逻辑
  2. 定义允许区域:在__init__里设置allowed_rect,你可以根据需求修改这个矩形的参数(x起点、y起点、宽度、高度)
  3. 重写itemChange方法:
    • 监听ItemPositionChange事件,这是项位置即将改变的前置触发点
    • 计算项移动后的全局边界,和允许区域对比
    • 如果超出允许区域,就把位置修正到刚好在区域内的位置,确保整个项都不会超出限制范围

现在你运行代码,拖动灰色矩形就会发现它被限制在你设定的区域里了,而QGraphicsScene的尺寸还是原来的400x400,完全符合你的需求~

内容的提问来源于stack exchange,提问作者user17796485

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 22:07:50