一个例子,搞懂QGraphicsView,QGraphicsScene坐标系统以及sceneRect设置

在使用Qt Graphics-View框架进行绘制时,一直云里雾里搞不懂绘制位置关系,官方的文档写的也是不咋地,懂得人能看懂,不懂的人看了也不懂。这篇文章通过一个例子,讲清楚item、scene、view的坐标关系,并且解释下,QGraphicView里可以setSceneRect,QGraphicsScene中也可以setSceneRect,这里究竟有什么区别呢?

1. item坐标系

item坐标系,即自定义类型并且继承QGraphicsItem的item,继承QGraphicsItem后必须重写boundingRect()和paint()绘制方法。

其中paint()即在item自己的坐标下进行绘制。x轴指向右,y轴指向下,不论在哪里绘制,即使绘制在负坐标,比如一条直线从(-100,-100)连接到(100,100),也完全没有问题。不会因为坐标是负的,就被裁掉了。

绘制好的item的(0,0)点,即原点,默认和Scene的(0,0)点(原点)重合。所以,当把item直接add进Scene时,它就会出现在Scene场景的(0,0)处。

2.scene坐标系

scene坐标系即场景坐标系,就是整个绘制场景,是所有item的容器,当设置item的pos时,item的坐标就会改变,即改变item在scene里的摆放位置。

QGraphicsItem* item = new CustomItem();
item->setPos(100,100);//将item向右下各移动100像素

3.view坐标系

view坐标系相当于摄像机,只是用一个方框来查看scene而已。既然是查看,当然可以放大看,旋转看,不论怎么看,都不影响scene里面设置的物体本来位置和大小。这里就会涉及到两个问题,如果view查看框大于Scene的大小,如果view查看框小于scene的大小,会有什么区别呢?

3.1 view查看框>Scene的大小

这种情况比较简单,view大于Scene,那就按照Qt默认的Alignment方式,将Scene放在View中。其中默认的Alignment方式就是Qt::AlignmentCenter,此时Scene的中心放在View的中心

3.2 view查看框<Scene的大小

view小于Scene,但是view仍要能显示全Scene的内容,那该怎么办呢?那就出现滚动条呗,横向不够加横滚动条,竖向不够那就加竖向的滚动条。一旦加了滚动条,那就view最左侧为scene的最左,view的最右侧就是scene的最右侧,上下同理。

3.3 view查看框部分>Scene的大小

所谓部分大于,那就包括横向大于Scene但是竖向小于,或者相反。此时,就是上面两种情况的混合。View大于的,就居中(其实可以修改Alignment的策略为AlignLeft,或者AlignRight);View小于的,就出滚动条。

4.例子

有如下的代码,会出现怎样的绘制呢?

m_graphicsScene.addItem(new WatchDial());

   
m_graphicsScene.setSceneRect(-120,-40,300,600);

ui->graphicsView->setScene(&m_graphicsScene);
//ui->graphicsView->setSceneRect(-30,50,1000,10);

其中,graphicsView进行了如下的设置,表示为一个宽、高为500的Widget。注意,graphicsView的起始点坐标为(40,10),只是说明其在centralWidget中偏一点,由于Scene在View中画,View的偏移不会影响Scene的绘制。

graphicsView = new QGraphicsView(centralwidget);
graphicsView->setObjectName("graphicsView");
graphicsView->setGeometry(QRect(40, 10, 500, 500));

而watchDial是一个在它自己的Item坐标下,圆心(0,0),半径120的圆盘。

绘制示意图

在这个图中,R120的圆即为watchDial,其中心为Scene的(0,0);而Scene设置为左上角(-120,-40),宽度为300,高度为600的矩形,即为黄色矩形标注的地方;由于Scene的宽为300,小于View的宽500,所以在横向,Scene居中显示;Scene的高为600,大于View的高500,因此纵向为滚动条显示形式,且滚动的两端为Scene纵向的两端。红色的框即为view显示的框,也就是最后显示出来的地方。

这个图就是最后的显示效果,当竖向的滚动条拉到顶时,可以看到多半个时钟,且时钟中心距离左右两侧的像素点为 276,625-276=350像素,由于我的显示器有1.25倍的放缩,对应为220.8和280,与示意图一致。

那还剩最后一个问题,QGraphicsView也可以设置SceneRect,QGraphicsScene也可以设置SceneRect,这两个有什么区别呢?

其实都是设置SceneRect,没有区别。不过如果View设置了,那么Scene的设置就无效了。我们看把代码写成这个样子,看看效果。

   m_graphicsScene.setSceneRect(-120,-40,300,600);

   ui->graphicsView->setScene(&m_graphicsScene);
   ui->graphicsView->setSceneRect(-30,50,1000,10);

 这里面,Scene和View同时设置了两个SceneRect,但是View的生效。示意图如下

可见,红色的View框里能显示多半个表盘,且红色的View框在竖直方向上,恰好与Scene中心对齐,而横向则有滚动条。且表盘中心(Scene的(0,0)点)距离左侧为30个像素,距离顶部为195个像素,距离底部为305个像素。和实际测量结果一致(注意,我的电脑有1.25倍的放缩比例)37,245,625-245=380。

5. 目前,还剩下QGraphicsView里面的变换,比如Scale,shear,translate没有讲。实验后发现当试图移动Scene在View中的位置时,Translate没有效果,但是Scale啥的可以对Scene中的物体进行放缩,这个应该是Qt的bug吧,外网上说这个bug修正了,我仍旧不知道translate该怎么使用。外网建议通过设置ScrollBar的位置实现Scene的移动,我觉得这样应该也行吧。

附录一下我参考的文章,感觉人家写的挺有借鉴效果的。

https://blog.csdn.net/wingover/article/details/88036106

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值