PyQt6拖动矩形时mouseMoveEvent异常跳动问题求助
PyQt6 GanttItem拖动时自发跳动问题修复
我在PyQt6中实现了基于QGraphicsItem的GanttItem组件,添加鼠标拖动功能后,拖动矩形时出现自发左右跳动的异常情况。控制台打印的event.pos().x()值随机跳变(如332.0与-212.0交替)。
示例代码
from PyQt6.QtWidgets import QGraphicsItem, QGraphicsScene, QGraphicsView, QApplication from PyQt6.QtGui import QBrush, QPainter, QMouseEvent from PyQt6.QtCore import QRectF, Qt class GanttItem(QGraphicsItem): def __init__(self, start, duration, name, color, parent=None): super().__init__(parent) self.start = start self.duration = duration self.name = name self.color = color self.dragging = False def boundingRect(self): return QRectF(0, 0, self.duration * 30, 50) def paint(self, painter, option, widget): painter.setBrush(QBrush(self.color)) painter.drawRect(self.boundingRect()) painter.drawText(self.boundingRect(), Qt.AlignmentFlag.AlignCenter, self.name) def mousePressEvent(self, event: QMouseEvent): self.dragging = True self.mouse_press_pos = event.pos() def mouseReleaseEvent(self, event: QMouseEvent): self.dragging = False def mouseMoveEvent(self, event: QMouseEvent): if self.dragging: event_x = event.pos().x() print(event_x) self.setPos(event_x, self.pos().y())
演示效果

控制台输出示例
332.0 -212.0 331.0 -213.0 90.0 -210.0
问题原因
核心问题是坐标系混淆:
event.pos()返回的是鼠标相对于当前GanttItem自身坐标系的位置,不是场景全局坐标。- 当调用
self.setPos(event_x, ...)修改Item位置后,下一次mouseMoveEvent触发时,event.pos()的参考系已经变成Item新的位置,导致位置计算完全错乱,出现来回跳动。
修复方案
修改鼠标事件处理逻辑,记录按下时的关键坐标,基于场景坐标系计算偏移:
修正后的代码
class GanttItem(QGraphicsItem): def __init__(self, start, duration, name, color, parent=None): super().__init__(parent) self.start = start self.duration = duration self.name = name self.color = color self.dragging = False def boundingRect(self): return QRectF(0, 0, self.duration * 30, 50) def paint(self, painter, option, widget): painter.setBrush(QBrush(self.color)) painter.drawRect(self.boundingRect()) painter.drawText(self.boundingRect(), Qt.AlignmentFlag.AlignCenter, self.name) def mousePressEvent(self, event: QMouseEvent): self.dragging = True # 记录鼠标在Item自身坐标系内的按下偏移量 self.mouse_item_offset = event.pos() def mouseReleaseEvent(self, event: QMouseEvent): self.dragging = False def mouseMoveEvent(self, event: QMouseEvent): if self.dragging: # 用鼠标场景位置减去偏移量,得到Item目标位置 target_pos = event.scenePos() - self.mouse_item_offset # 仅更新X轴位置,保持Y轴不变 self.setPos(target_pos.x(), self.pos().y())
逻辑说明
mousePressEvent中:self.mouse_item_offset记录鼠标按下时相对于Item左上角的偏移,避免拖动时Item直接跳转到鼠标位置。mouseMoveEvent中:event.scenePos()获取鼠标在场景全局坐标系的位置,减去偏移量后得到Item的目标位置,彻底避免坐标系混淆导致的跳动问题。
内容的提问来源于stack exchange,提问作者Lukas Fürst
相关产品推荐
相关产品推荐

