You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:34:54