如何限制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_()
关键改动说明
- 自定义RestrictedPolygonItem类:继承自QGraphicsPolygonItem,专门用来处理移动限制逻辑
- 定义允许区域:在
__init__里设置allowed_rect,你可以根据需求修改这个矩形的参数(x起点、y起点、宽度、高度) - 重写itemChange方法:
- 监听
ItemPositionChange事件,这是项位置即将改变的前置触发点 - 计算项移动后的全局边界,和允许区域对比
- 如果超出允许区域,就把位置修正到刚好在区域内的位置,确保整个项都不会超出限制范围
- 监听
现在你运行代码,拖动灰色矩形就会发现它被限制在你设定的区域里了,而QGraphicsScene的尺寸还是原来的400x400,完全符合你的需求~
内容的提问来源于stack exchange,提问作者user17796485
相关产品推荐
相关产品推荐

