除非boundingRect为空,为什么自定义QGraphicsItem会导致场景或视图移动?

时间:2013-07-09 16:30:14

标签: c++ qt qgraphicsview qgraphicsitem qgraphicsscene

我的Qt 4.8.1 C ++类用于绘制十字准线子类QGraphicsItem并实现其paint()boundingRect()方法。 paint()方法由两个drawLine()和一个drawText()调用组成。原点是中心的。 boundingRect()也尊重这些坐标( - , - ,+,+)以及每个方向的半笔宽度。

创建,移动(或定位)然后将对象添加到(可见)场景时,视图会移动几个像素,以便场景内容稍微向右移动。 如果boundingRect()返回一个空的QRectF(),则不会发生这种转变。

  • 其他元素不会导致场景进一步移动。
  • 场景的先前更新()不会改变行为
  • 更大的boundingRect似乎增加了运动
  • 更改视图的转换不会改变行为

itemChange()被多次调用,但似乎没有提供线索(在我看来):

Crosshair::Crosshair being created, id= "1"  at  QPointF(63.6, 88.487) scenePos= QPointF(33.6, 58.487) 
Crosshair::Crosshair position QPointF(63.6, 88.487) 
Crosshair::itemChange  ItemFlagsChange QVariant(uint, 1) 
Crosshair::itemChange  ItemFlagsHaveChanged QVariant(uint, 1) 
Crosshair::itemChange  ItemFlagsChange QVariant(uint, 33) 
Crosshair::itemChange  ItemFlagsHaveChanged QVariant(uint, 33) 
Crosshair::itemChange  ItemFlagsChange QVariant(uint, 2081) 
Crosshair::itemChange  ItemFlagsHaveChanged QVariant(uint, 2081) 
[...]
Crosshair::itemChange  ItemPositionChange QVariant(QPointF, QPointF(63.6, 88.487) ) 
Crosshair::itemChange  ItemPositionHasChanged QVariant(QPointF, QPointF(63.6, 88.487) ) 
Crosshair::itemChange  ItemSceneChange QVariant(QGraphicsScene*, ) 
Crosshair::itemChange  ItemSceneHasChanged QVariant(QGraphicsScene*, ) 
[...]
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
Crosshair::itemChange  ItemVisibleChange QVariant(bool, true) 
Crosshair::itemChange  ItemVisibleHasChanged QVariant(bool, true) 
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
...

我明天可能会创建一个最小的例子,但也许有人能够从这个问题的一般描述中猜出我的错误。 或者,当然非常欢迎进一步调试的提示!

<小时/> 修改的 感谢Riateche的建议。 一些进一步的调试输出显示sceneRect()确实被改变,它完全扩展了Crosshair的边界矩形的大小,例如从QRectF(0,0 1680x636)QRectF(-11.5,-11.5 1691.5x647.5)。场景的itemsBoundingRect保持不变。 现在我没有提到视图已经使用fitInView(scene()->itemsBoundingRect(), Qt::KeepAspectRatio);进行了缩放/转换,并注意到当场景以100%(例如resetTransform())观看时确实不会发生移位。 但是当我在boundingRect()中添加元素时,我仍然不明白为什么/为什么sceneRect()会发生变化。它必须与我的自定义实现有关,因为添加椭圆不会导致场景/视图的移位。

好的,我们走了:我也没有提到我使用setFlag(QGraphicsItem::ItemIgnoresTransformations);,因此无论规模如何,十字准线都保持相同的大小。这显然会导致边界在添加时“停留”在场景的原点,并忽略setPos()。

继续......

2 个答案:

答案 0 :(得分:3)

场景有一个边界矩形,默认情况下是包含所有项目的最小矩形。如果向此矩形之外的场景添加内容,则会扩展边界矩形。

视图尊重场景的矩形。如果场景的rect小于视图的视口大小,则视图的滚动条将被隐藏,场景内容将在视口的中心中显示。因此,如果添加一个项目,场景的边界矩形会发生变化,所有内容都会被移动。如果视口小于边界rect,则会出现滚动条。

如果您想避免此行为,可以使用QGraphicsView::setSceneRectQGraphicsScene::setSceneRect来修正矩形位置。请注意,设置矩形之外的所有内容都将在视图中不可用且不可见。

另请考虑切换为QGraphicsPathItem(和QGraphicsScene::addPath)。它可以用来绘制十字准线。

答案 1 :(得分:0)

我正在尝试是否可以使用

解决问题
QRectF save = scene->sceneRect();
scene->addItem( myGraphicsItem );
scene->setSceneRect( save );

正如Riateche所说的不同,并且它有效。

然而,遗憾的是,我仍然不完全了解其原因。

以下是documentation对此标志的评价:

  

QGraphicsItem :: ItemIgnoresTransformations

     

0x20

     

该项目忽略   继承的变换(即,它的位置仍然固定在其上   父级,但父级或视图旋转,缩放或剪切变换   被忽略了)。此标志对于保留文本标签项非常有用   水平和非标度,因此如果视图是可读的,它们仍然是可读的   转化。设置时,项目的视图几何和场景几何   将单独维护。您必须调用deviceTransform()进行映射   坐标并检测视图中的碰撞。默认情况下,此标志   被禁用。这个标志在Qt 4.3中引入。注意:有了这个标志   设置您仍然可以缩放项目本身,以及该比例转换   会影响该项目的孩子。

以下是一些可能相关的信息: