将 child QGraphicsItem 约束到场景?

Constraining child QGraphicsItem to scene?

有没有人有更好的方法来将 QGraphicsItem 的 child 约束到场景?

我已经通过覆盖 itemChange 成功地将 parent QGraphicsItem 正确地约束到它的场景,但现在我需要对 child [=12] 做同样的事情=].

示例Use-case:

此代码在大多数情况下都有效。唯一的问题是 QGraphicsItem 击中任何一侧时的速度都会影响其停止位置:

QVariant SizeGripItem::HandleItem::itemChange(GraphicsItemChange change,
                                              const QVariant &value)
{
    QPointF newPos = value.toPointF();
    if (change == ItemPositionChange)
    {
        if(scene())
        {
            newPos.setY(pos().y()); // Y-coordinate is constant.

            if(scenePos().x() < 0 ) //If child item is off the left side of the scene,
            {
                if (newPos.x() < pos().x()) // and is trying to move left,
                {
                  newPos.setX(pos().x()); // then hold its position
                }
            }
            else if( scenePos().x() > scene()->sceneRect().right()) //If child item is off the right side of the scene,
            {
                if (newPos.x() > pos().x()) //and is trying to move right,
                {
                  newPos.setX(pos().x()); // then hold its position
                }
            }
        }
    }
 return newPos;
}

对于 parent 项,我使用了: newPos.setX(qMin(scRect.right(), qMax(newPos.x(), scRect.left()))); 效果很好,但我不知道如何或是否可以在这里使用它。

首先,具体来说,场景实际上是没有边界的。您要做的是将项目限制在您在别处设置的场景矩形中。

我看到的问题是您对 scenePos 的使用。这是一个 ItemPositionChange;该项目的 scenePos 尚未更新为新位置,因此当您检查 scenePos 是否超出场景矩形时,您实际上是在检查上次位置更改的结果,而不是当前位置更改的结果。正因为如此,您的项目最终刚好离开场景矩形的边缘,然后粘在那里。离边缘多远取决于您移动鼠标的速度,这决定了 ItemPositionChange 通知之间的距离。

相反,您需要将新位置与场景矩形进行比较,然后将返回的值限制在场景矩形内。你需要场景坐标中的新位置来进行比较,所以你需要这样的东西:

QPoint new_scene_pos = mapToScene (new_pos);

if (new_scene_pos.x() < scene()->sceneRect().left())
    {
    new_scene_pos.setX (scene()->sceneRect().left());
    new_pos = mapFromScene (new_scene_pos);
    }

显然,这不是完整的代码,但这些是您需要进行的转换和检查,以将其保留在左侧。右边非常相似,所以直接用new_scene_pos比较一下。

请注意,我没有假设 sceneRecT 的左边缘为 0。我确定这就是您在设置 sceneRect 的地方编码的内容,但是使用实际的左值而不是假设它为 0 可以消除任何问题如果您稍后更改了您计划使用的场景坐标范围。

我在 sceneRect 调用中使用 "left" 而不是 "x" 只是因为它与另一侧使用 "right" 并行。它们完全一样,但我认为在这种情况下读起来稍微好一些。