为什么自定义QGraphicsItem会导致场景或视图移动,除非boundingRect为空
Why could a custom QGraphicsItem cause the scene or view to move unless boundingRect is empty?
My Qt 4.8.1 C++类绘制十字线子类QGraphicsItem并实现其paint()和boundingRect()方法。paint()方法由两个drawLine()和一个drawText()调用组成。原点居中。boundingRect()还考虑这些坐标(-,-,+,+)以及每个方向上的半笔宽度。
创建、移动(或定位)然后将对象添加到(可见)场景时,视图会移动一些像素,以便场景内容稍微向右下移动。如果boundingRect()返回一个空的QRectF(),则不会发生此偏移。
- 附加元素不会引起场景的进一步移动
- 场景的先前更新()不会改变行为
- 较大的弹跳Rect似乎可以增加运动
- 更改视图的变换不会更改行为
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)
...
明天我也许可以创建一个最小的例子,但也许有人能够从这个问题的一般描述中猜到我的错误。或者,我们当然非常欢迎进一步调试的提示!
编辑感谢里亚特切的建议。一些进一步的调试输出显示sceneRight()确实发生了更改,它精确地扩展了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);
,这样无论比例尺如何,十字线都保持相同的大小。这显然会导致添加时boundrect"停留"在场景的原点,并忽略setPos()。
继续。。。
场景有一个边界矩形,默认情况下它是包含所有项目的最小矩形。如果在该矩形之外的场景中添加某些内容,则边界矩形将展开。
视图尊重场景的矩形。如果场景的矩形小于视图的视口大小,则视图的滚动条将被隐藏,并且场景内容将显示在视口的中心。所以,若添加一个项目,场景的边界矩形会发生变化,所有内容都会发生移动。如果视口小于边界矩形,则会显示滚动条。
如果要避免这种行为,可以使用QGraphicsView::setSceneRect
或QGraphicsScene::setSceneRect
来固定矩形位置。请注意,设置矩形之外的所有内容在视图中将不可用且不可见。
还要考虑切换到QGraphicsPathItem
(和QGraphicsScene::addPath
)。它可以用来绘制十字光标。
我正在尝试是否可以用解决这个问题
QRectF save = scene->sceneRect();
scene->addItem( myGraphicsItem );
scene->setSceneRect( save );
正如里亚特切在另一个音符上所建议的那样,它是有效的。
然而,不幸的是,我仍然不完全理解造成这种情况的原因。
以下是文档对这个标志的描述:
Q图形项目::项目忽略转换
0x20
项目忽略继承的转换(即,其位置仍然固定在父对象,但父对象或视图的旋转、缩放或剪切变换被忽略)。此标志用于保留文本标签项目水平和未缩放,因此如果视图为转变。设置后,项目的视图几何体和场景几何体将单独维护。必须调用deviceTransform()才能映射坐标并检测视图中的碰撞。默认情况下,此标志已禁用。此标志在问题4.3中引入。注意:使用此标志设置您仍然可以缩放项目本身,以及缩放转换将影响项目的子项。
以下是一些可能相关的信息:
- https://bugreports.qt-project.org/browse/QTBUG-19039
- ItemIgnoresTransformations打开时QGraphicsView的fitInView出现问题
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 将对象移动到std::shared_ptr
- 何时在引用或唯一指针上使用移动语义
- 视图中的参数推导失败:take_while
- 如何从具有移动语义的类对象中生成共享指针
- 将shared_ptr移动到<StructA>shared_ptr<变体<结构A、结构 B>>
- C / C++ 移位/偏移/向左或向右移动位图?
- MSVC将仅移动结构参数解释为指针
- OpenVR:向视图方向移动
- 如何将到达图形视图右侧(末端)的QGraphicsPixmapItem移动到左侧(开始)侧(就像在贪吃蛇游戏中发生的事情
- Qt 如何使用鼠标移动事件移动视图
- SFML 视图:设置中心与移动。快把我逼疯了
- 如何在移动列表视图中添加滚动条?并且用户只能垂直滚动特定区域
- SDL2:移动所有东西而不是使用视图端口是不是很糟糕
- 用鼠标中键按下qt图表移动视图
- SFML中移动位置的居中视图
- QT 图形场景/视图 - 使用鼠标四处移动
- 在不同的视图中上下移动QListWidget中的项目
- 为什么自定义QGraphicsItem会导致场景或视图移动,除非boundingRect为空
- 在MFC对话框的列表视图上鼠标移动事件