如何实现点击QGraphicsView/QGraphicsScene画布可绘制且可拖动的QGraphicsRectItem
解决QGraphicsView点击生成矩形+自由拖动问题
问题原因
你的代码存在两个核心问题:
- 重写
GraphicsView.mousePressEvent时完全覆盖了父类逻辑,没有调用super().mousePressEvent(event),导致QGraphicsScene无法将鼠标事件传递给已存在的矩形项,只有当点击位置恰好落在矩形的pen线条上时,才会触发item的鼠标事件,所以拖动异常困难。 - 每次点击都会无条件生成新矩形,就算点击的是已有的矩形,也会在上面叠加新的,干扰正常拖动操作。
解决方案
修改GraphicsView的mousePressEvent逻辑:先判断点击位置是否存在可交互的图形项,不存在时再生成新矩形;同时必须调用父类的鼠标事件处理方法,让场景中的item能正常接收鼠标事件。
修改后的完整代码
from PyQt5.QtCore import Qt from PyQt5.QtGui import QBrush, QMouseEvent, QPen from PyQt5.QtWidgets import ( QApplication, QGraphicsItem, QGraphicsRectItem, QGraphicsScene, QGraphicsView, ) class RectangleItem(QGraphicsRectItem): def __init__(self, x: float, y: float, width: float, height: float): super().__init__(x, y, width, height) self.setBrush(QBrush(Qt.red)) self.setPen(QPen(Qt.black, 20)) self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) class GraphicsView(QGraphicsView): def __init__(self, scene: QGraphicsScene): super().__init__(scene) def mousePressEvent(self, event: QMouseEvent): scene_position = self.mapToScene(event.pos()) # 获取点击位置的所有图形项,过滤出可移动的项 clicked_items = [item for item in self.scene().items(scene_position) if item.flags() & QGraphicsItem.ItemIsMovable] if not clicked_items: # 未点击到可移动item时,生成新矩形 rectangle = RectangleItem(scene_position.x(), scene_position.y(), 100, 100) self.scene().addItem(rectangle) # 调用父类方法,让场景处理item的鼠标事件 super().mousePressEvent(event) app = QApplication([]) scene = QGraphicsScene() view = GraphicsView(scene) view.show() app.exec()
关键说明
self.scene().items(scene_position)会返回点击位置的所有图形项,我们通过过滤ItemIsMovable标记,判断是否点击到了已有的可拖动矩形。- 只有在未点击到可拖动item时才生成新矩形,避免叠加干扰。
super().mousePressEvent(event)是核心:它会让QGraphicsView把鼠标事件传递给场景,再由场景分发给对应的item,这样矩形就能响应任意位置的点击拖动了。
内容的提问来源于stack exchange,提问作者eraintash
相关产品推荐
相关产品推荐

