Qt中调整QGraphicsItem大小后如何重建其局部坐标系?
解决QGraphicsItem调整大小时局部坐标系偏移问题
问题核心是你当前的代码仅修改了rect的边界来实现缩放,没有同步调整Item的pos(),导致Item的局部坐标系原点(对应pos()的场景位置)没有跟随左上角移动,最终pos()和scenePos()返回的还是初始位置。
正确的思路是:当拖拽左侧/上侧的手柄改变Item左上角位置时,同步调整Item的pos(),让pos()对应Item新的左上角场景坐标,同时在局部坐标系内保持rect的相对位置不变,只调整其宽高。
以下是修改后的核心代码:
def interactiveResize(self, mousePos): """ Perform shape interactive resize. """ offset = self.handleSize + self.handleSpace original_bounding_rect = self.mousePressRect # 保存初始boundingRect,避免实时计算偏差 original_rect = self.rect() original_pos = self.pos() self.prepareGeometryChange() if self.handleSelected == self.handleTopLeft: fromX = original_bounding_rect.left() fromY = original_bounding_rect.top() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() # 计算偏移量,调整Item的pos到新左上角 dx = toX - fromX dy = toY - fromY self.setPos(original_pos + QPointF(dx, dy)) # 计算新的宽高,调整rect new_width = original_bounding_rect.width() - dx new_height = original_bounding_rect.height() - dy self.setRect(QRectF(offset, offset, new_width - 2*offset, new_height - 2*offset)) elif self.handleSelected == self.handleTopMiddle: fromY = original_bounding_rect.top() toY = fromY + mousePos.y() - self.mousePressPos.y() dy = toY - fromY self.setPos(original_pos + QPointF(0, dy)) new_height = original_bounding_rect.height() - dy self.setRect(QRectF(original_rect.left(), offset, original_rect.width(), new_height - 2*offset)) elif self.handleSelected == self.handleTopRight: fromX = original_bounding_rect.right() fromY = original_bounding_rect.top() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() dy = toY - fromY self.setPos(original_pos + QPointF(0, dy)) new_width = toX - original_bounding_rect.left() new_height = original_bounding_rect.height() - dy self.setRect(QRectF(offset, offset, new_width - 2*offset, new_height - 2*offset)) elif self.handleSelected == self.handleMiddleLeft: fromX = original_bounding_rect.left() toX = fromX + mousePos.x() - self.mousePressPos.x() dx = toX - fromX self.setPos(original_pos + QPointF(dx, 0)) new_width = original_bounding_rect.width() - dx self.setRect(QRectF(offset, original_rect.top(), new_width - 2*offset, original_rect.height())) elif self.handleSelected == self.handleMiddleRight: fromX = original_bounding_rect.right() toX = fromX + mousePos.x() - self.mousePressPos.x() new_width = toX - original_bounding_rect.left() self.setRect(QRectF(offset, original_rect.top(), new_width - 2*offset, original_rect.height())) elif self.handleSelected == self.handleBottomLeft: fromX = original_bounding_rect.left() fromY = original_bounding_rect.bottom() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() dx = toX - fromX self.setPos(original_pos + QPointF(dx, 0)) new_width = original_bounding_rect.width() - dx new_height = toY - original_bounding_rect.top() self.setRect(QRectF(offset, offset, new_width - 2*offset, new_height - 2*offset)) elif self.handleSelected == self.handleBottomMiddle: fromY = original_bounding_rect.bottom() toY = fromY + mousePos.y() - self.mousePressPos.y() new_height = toY - original_bounding_rect.top() self.setRect(QRectF(original_rect.left(), offset, original_rect.width(), new_height - 2*offset)) elif self.handleSelected == self.handleBottomRight: fromX = original_bounding_rect.right() fromY = original_bounding_rect.bottom() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() new_width = toX - original_bounding_rect.left() new_height = toY - original_bounding_rect.top() self.setRect(QRectF(offset, offset, new_width - 2*offset, new_height - 2*offset)) self.updateHandlesPos()
关键修改点说明:
- 所有涉及左上角位置变化的手柄(TopLeft、TopMiddle、TopRight、MiddleLeft、BottomLeft),都会计算偏移量并调用
setPos()更新Item的位置,确保pos()对应新的左上角场景坐标。 - 调整
rect时,以局部坐标系的(offset, offset)为起点,仅修改宽高,保证局部坐标系原点与pos()对齐。 - 使用
mousePressRect(鼠标按下时的初始boundingRect)作为基准计算,避免实时计算带来的累积误差。
内容的提问来源于stack exchange,提问作者swgchlry
相关产品推荐
相关产品推荐

