如何正确实现QGraphicsItemGroup网格吸附逻辑?现有实现存在偏移问题
自定义QGraphicsItemGroup网格吸附问题修复
问题现象
开发自定义QGraphicsItemGroup时,开启网格吸附(10像素步长)后,拖动组会以场景(0,0)为基准偏移。比如组初始在(100,100),拖动时会表现得像从(0,0)位置开始移动,无法保持拖动时鼠标与组的相对位置。
问题原因
当前代码直接使用鼠标的场景位置计算网格对齐坐标,忽略了鼠标在组内的点击偏移量——也就是按下鼠标时,鼠标点相对于组原点的距离。拖动时直接把组的原点设置为鼠标对齐后的位置,导致组的位置跳变,而非基于原拖动逻辑的偏移。
修复代码
from PyQt5.QtWidgets import QGraphicsItemGroup, QGraphicsSceneMouseEvent, QStyle from PyQt5.QtGui import QColor, QPen from PyQt5.QtCore import Qt class CustomGraphicsItemGroup(QGraphicsItemGroup): def __init__(self, widget): super().__init__() self.widgets = widget self._mouse_offset = None # 记录鼠标相对于组的偏移 def paint(self, painter, option, widget=None): super().paint(painter, option, widget) if option.state & QStyle.State_Selected: pen = QPen(QColor('#e00202'), 2, cap=Qt.RoundCap) painter.setPen(pen) painter.drawRect(self.boundingRect()) def mousePressEvent(self, event: QGraphicsSceneMouseEvent): # 记录按下鼠标时,鼠标相对于组原点的偏移(组坐标系下的位置) self._mouse_offset = event.pos() super().mousePressEvent(event) def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent): if self.widgets.isChecked(): block_size = 10 # 1. 获取鼠标当前场景位置 scene_pos = event.scenePos() # 2. 减去鼠标相对于组的偏移,得到组原点应该在的场景位置 target_scene_pos = scene_pos - self._mouse_offset # 3. 对组原点的目标位置做网格对齐 x = int(target_scene_pos.x() / block_size) * block_size y = int(target_scene_pos.y() / block_size) * block_size # 4. 设置组的位置 self.setPos(x, y) else: super().mouseMoveEvent(event)
关键改动说明
- 添加
mousePressEvent:记录按下鼠标时,鼠标在组局部坐标系下的位置,这个偏移量在拖动过程中保持不变。 - 修改
mouseMoveEvent:用鼠标当前场景位置减去偏移量,得到组原点的目标场景位置,再对这个目标位置做网格对齐,确保拖动时鼠标与组的相对位置和按下时一致,不会出现跳变。
内容的提问来源于stack exchange,提问作者user23995616
相关产品推荐
相关产品推荐

