Qt Graphics View 框架

这几天做迷彩设计相关编程用了很多QPainter相关的操作,写了不少Qt代码让我对Qt又有了进一步的认识。最近翻看Qt 的 Demos and Examples 发现在Graphics view里面有一个elastic node的示例,程序仅仅定义了背景和小球绘制操作便完成了复杂的鼠标,键盘等交互。在让我大为惊叹Qt 强大的同时,也决定学一学。查找了Qt 帮助文档,这一系列操作都用到了Qt Graphics View Framework

 

Graphics View 框架提供了一个界面,用于管理和交互大量的用户自定义的2D图形物件,并且有一个view widget(QGraphicsView)用户可视化这些物件,支持zoom和rotate。这个框架包含了一个事件传播构架,允许了double精度的场景中物体交互能力。物件的键盘,鼠标的按下,移动,松开,双击事件都已经定义好了,并且可以跟踪鼠标移动。

 

Graphics view 构架

所有的item都被绘制到了一个场景中用于显示,这个场景就是QGraphicsScene,这个场景有如下功能:

1、  为管理大量item提供了一个快速交互界面。

2、  能够将键盘,鼠标等事件传递到每个item。

3、  可以管理item的状态,例如选择,焦点等。

4、  提供了不变形的绘制,主要用于打印绘画结果。

 

场景就像一个容易囊括了所有item,可以通过addItem()添加物体,可以通过item()查找物体,itemAt()返回最上面的item,所有item按照降序堆栈排列。第一个加入的在栈顶,最后一个加入的在栈底。

 

QGraphicsScene的事件传递架构非常给力,能够将场景获得的事件精确传递到相应item,例如鼠标在某点点击了一下,Scene能够将这个事件传递给在这个点上的item(最上面的那个item),于是这个item被选中或者执行别的动作,具体取决于item的mousePressEvent函数的处理。

 

QGraphicsScene中,你可以用setSelectionArea()选择区域中的许多个item,仅仅需要调用这个函数你就能获得选中item的结果,真是太强大了,如果要自己写函数鼠标选择的区域选了哪些item,你需要遍历每个item,对于每个item又要判断是否全部在区域内,于是item要包围核,要范围面积等等变量来表示。想想就觉得真心麻烦。这个函数确实为开发者节约了不少时间。

 

View

QGraphicsView提供了用于显示的widget,用于显示scene,你可以将多个view联系到同一个scene,给相同的数据提供多个视口,视口支持openGL,甚至可以将QGLWidget作为视口,只要调用一下QGraphicsView::setViewport()。View接收交互事件,进行坐标转换后变成scene event交给场景。QGraphicsView::mapToScene(), QGraphicsView::mapFromScene()等多个函数可以在view和scene之间转换坐标系。

  1. QGraphicsScene scene;  
  2. myPopulateScene(&scene);  
  3. QGraphicsView view(&scene);  
  4. view.show();  

Item

QGraphicsItem是场景中所有物件的基类,GraphicsView也提供了一些标准item,例如矩形QGraphicsRectItem,椭圆QGraphicsEllipseItem,还有文本,QGraphicsTextItem,最给力的当然是你自定义的item,item支持以下操作:

1、  鼠标点击,移动,松开,双击,飞越,滚轮,菜单事件。

2、  键盘输入。

3、  拖拽

4、  Group,可以通过父子关系或者QGraphicsItemGroup

5、  碰撞检测

 

每个Item都有一个局部坐标系,可以通过这个坐标系进行选择,移动等操作,transform()函数通过控制矩阵可以轻松实现这些操作。

 

有一个很NB的功能就是item支持碰撞检测,怎么检测呢,首先需要为每一类item定义好它的bounding box,同过boundingRect()函数可以设置这个item外围矩形包围盒,而更精确的是用shape()函数定义item外边框路径,这个路径是QPainterPath,这个路径可以是直接,贝塞尔曲线等任何线条,collidesWith()是一个虚函数,定义完成后便能完成碰撞检测功能了。

 

其他的Graphics类

QGraphicsAnchorLayout是用于将几个widget以锚点的形式随意排列的layout。

QGraphicsEffect提供了一些图形特效。

主要有以下4个标准特效:

Qt provides the following standardeffects:

·        QGraphicsBlurEffect - blurs the item by a given radius

·        QGraphicsDropShadowEffect - renders a dropshadow behind the item

·        QGraphicsColorizeEffect - renders the item in shades of any given color

·        QGraphicsOpacityEffect - renders the item with an opacity

 

Graphics view 坐标系

坐标系由(x,y)表示,一个单位就是屏幕上一个像素。在这个框架内一共有3个坐标系,item局部坐标系,场景坐标系,view坐标系,有函数用于在这些坐标系之间进行映射。

Item coordinates

Item的坐标建立在它的中心点(0,0)附近,这也是所有变形的中心位置,几何图元常常由局部坐标系中的点,线,矩形来构建。

构建自定义的item时,仅仅需要考虑局部坐标就行了,QGraphicsView和QGraphicsScene会进行其他所有的变形。鼠标事件用于item时,会自动将点转换到item坐标系中。Item的bounding rect 和 shape都在局部坐标系中定义。

 

子item的中心位置将会保存到父item的坐标系中用于自动查找判断,最上层item的中心坐标将会保存到scene坐标系中。

 

父item的旋转缩放操作将会影响子item跟着一起变,但不会影响子item与父Item的坐标系,例如,有父子2个item,在父坐标系中,子的位置在(10,0)。于是,子坐标系中位置为(0,10)的点在父坐标系下的坐标是(10,10)。然后,我对父item进行了旋转和缩放,子坐标系下(0,10)的点在父坐标系下仍然是(10,10),但是在scene坐标系下就会产生变化了,子item会随着父产生形变,如果父进行了缩放为(2x,2x),在scene坐标系下,子的位置为(20,0),子坐标系中(10,0)的点在scene下的坐标为(40,0)。QGraphicsItem::pos()是少数几个例外的,它返回item在父坐标系下的坐标.

 

旋转和缩放操作相当简单,在QGraphicsView中调用ratate()和scale()函数。

 ————————————————————————————————————————————————————————

光说不练嘴把式,必须随便搞个test project。

GraphicWidget继承自QGraphicsView,重载了一个函数,drawBackground().

EllipseItem继承自QGraphicsItem,重载了若干函数:

  1. QRectF boundingRect() const;  
  2. void paint(QPainter *painter, const QStyleOptionGraphicsItem*option, QWidget *widget);  
  3. protected:  
  4. QVariant itemChange(GraphicsItemChange change, const QVariant &value);  
  5. void mousePressEvent(QGraphicsSceneMouseEvent *event);  
  6. void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);  

boundingRect必须得重载,不然编译器说这个是抽象类,不能够实例化。

在mousePressEvent()中调用QGraphicsItem::mousePressEvent(event);便万事大吉,方便shi了。

其他雷同。

在EllipseItem中保存了父节点指针。

在graphicWidget构造函数中new一个scene,设置一下,然后new一个EllipseItem出来,放入scene,指定位置,就可以了。

出来的结果是,你可以任意移动出现的小圆球。

 

待续...

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值