有没有人有更好的方法将QGraphicsItem
的孩子约束到某个场景?
我已成功通过覆盖QGraphicsItem
将父级itemChange
正确约束到其场景,但现在我需要为子级QGraphicsItem
执行相同操作。
示例用例:
此代码在大多数情况下都有效。唯一的问题是 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;
}
对于父项,我用过:
newPos.setX(qMin(scRect.right(), qMax(newPos.x(), scRect.left())));
这完美无缺,但我很难知道如何在这里使用它。
答案 0 :(得分:2)
首先,具体而言,场景实际上没有边界。您要做的是将项目约束到您在其他位置设置的场景矩形。
我看到的问题在于你使用了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”平行。它们完全相同,但我认为在这种情况下读数略好一些。