图形项坐标
- 以图形项的左上角为原点。
- 创建自定义图形项时,只需要考虑图形项的坐标系统
- 没有父图形项的是顶层图形项,在场景坐标系中,可以用setPos()函数指定图形项的位置,没有指定时出现在原点处。子图形项的坐标不会受到父图形项的变换的影响,相对于场景而言,子会随着父的变换而变换。
- 所有图形项会使用确定的顺序来进行绘制,该顺序决定单击场景时获取鼠标的顺序。默认是父图形项先被绘制,再是子图形项,用Z值设定层叠顺序,setZValue()改变一个图形项的Z值。Z值大的在上面。子图形项默认显示在父图形项的上面。
场景坐标(QPainter的逻辑坐标)
- 图形项的基础坐标系统,描述每一个顶层图形项的位置,原点在场景的中心
- 每一个图形项都有本地坐标,边界矩形,场景坐标(QGraphicsItem::scenePos()),场景中的边界矩形(QGraphicsItem::sceneBoundingRect())
视图坐标(设备坐标)
部件的坐标,原点在视图的左上角,所有鼠标事件和拖放事件都是通过视图坐标被接收
坐标映射
- 场景映射到图形项,图形项之间的映射,视图映射到场景
- 可以调用QGraphicsView::mapToScene()和QGraphicsScene::itemAt()以获取光标下的图形,第一个函数将视口坐标映射到场景,第二个获取场景中顶层图形项
- 获取视口中的位置,先用QGraphicsView::mapToScene()将视口坐标映射到场景,再用QGraphicsView::mapFromScene()将场景坐标转变为视口坐标。
- QPoint viewPos = event->pos(); //鼠标事件返回的坐标是视口坐标
- QPoint scenePos = mapToScene(viewPos); //将视口坐标映射成场景坐标
- scene()->itemAt(scenePos); //itemAt()的参数是场景坐标,此处的场景坐标即鼠标指向的位置
- item->setPos(); //在没有父图形项时,作为顶层图形项,设置的参数是相对于场景原点的偏移量;有父图形项时,设置的参数是相对于父图形项的原点的偏移量
- item->setParentItem(rectItem); //设置父图形项,父图形项的旋转平移时,子图形项会做相应的变化
1、 Qt中事件传递是由父向子传递,同样在视图场景中事件传递是View->Scene->Item这样的顺序,所以上层的事件函数重写必须调用父类事件函数,实现事件的向下传递,不至于阻塞后面元素的事件处理。
2、 在View中调用setBackgroundBrush方法会阻止Scene中drawBackground方法的调用,这个帮助中有说明,属于帮助看的不仔细。另外View/Scene中的drawBackground和drawForeground方法类似事件函数,调用顺序是View->Scene,所以在自定义View中drawBackground和drawForeground方法时需要调用父类方法。
3、 QGraphicsScene::sceneRect和QGraphicsView::sceneRect是有区别的,QGraphicsScene::sceneRect是场景的实际范围大小,是一个抽象逻辑概念,例如用场景作为画布,为画布的实际大小。QGraphicsView::sceneRect则是在View中需要给Scene预留的区域大小,这个类似窗口概念,QGraphicsView::sceneRect的大小直接影响则View窗口中滚动条的出现。在开发中QGraphicsScene::sceneRect最好小于等于QGraphicsView::sceneRect大小,以保证在缩放View时通过滚动条可以查看到完整的Scene区域。
4、 QGraphicsItemGroup的位置问题,创建的group在场景中的初始pos()始终为(0,0),这一点与普通item不同。不知道Qt对QGraphicsItemGroup这样设计的原因是什么,把它理解成普通item确实带来不少问题,感觉是个“坑”。一般item的pos()就是item的sceneBoundingRect的左上角,所以为了统一我们也可以对group取sceneBoundingRect().topLeft()作为它的pos。对group setPos时先计算新pos与topLeft点的offset,然后通过group.setPos(group.pos()+offset)来实现group新位置移动。
5、 给Item设置新的位置,在对item进行了一些列复杂的transform变换或其他操作后,有时候会出现setPos时位置与预想的不一致,多半是item相对Scene的坐标系映射关系发生了我们未察觉的变化导致的。这个时候你再对item setPos到Scene中具体的某个点时会出现偏差,我遇见类似问题的一个思路是,不要使用setPos设置绝对的位置点,而是先求取原pos与要设置pos的offset,然后同4中那样通过item.setPos(item.pos()+offset)来实现item新位置设置,一般可以达到预期的位置。
坐标说明
QGraphicsRectItem setPos 设置在Scene中的坐标
QGraphicsRectItem item(20,20,60,60) 设置的是在item上的坐标
CustomItem *pItem = new CustomItem();
pItem->setRect(20, 20, 60, 60); //设置的使在item上的坐标
Scence->setSceneRect(0,0,800,800);//设置场景范围 //一定要定义setSceneRect,如果不定义可能会出现setPos无效
void GraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsRectItem * item1 = addRect(event->scenePos().toPoint().x(),event->scenePos().toPoint().y(),10,10,QPen("yellow")); //这个方框在 item坐标的 event.x event.y
item1->setPos(event->scenePos().x(),event->scenePos().y());
QGraphicsRectItem * item2 = addRect(0,0,10,10,QPen("red")); //这个方框在 item坐标的 0,0
item2->setPos(event->scenePos().x(),event->scenePos().y());
}
QGraphicsItem::scenePos() //获取scene 坐标
QGraphicsItem::sceneBoundingRect() //获取 scene 坐标的边界矩形
View->centerOn(point); //point 为scene坐标, 让point坐标位于view中心