第7章 Qt 5图形视图框架图形视图体系结构7.17.2【实例】:图形视图7.1 图形视图体系结构7.1.1 Graphics View的特点Graphics View框架结构的主要特点如下1)Graphics View框架结构中,系统可以利用Qt绘图系统的反锯齿、OpenGL工具来改善绘图性能2)Graphics View支持事件传播体系结构,可以使图元在场景(scene)中的交互能力提高1倍,图元能够处理键盘事件和鼠标事件其中,鼠标事件包括鼠标按下、移动、释放和双击,还可以跟踪鼠标的移动3)在Graphics View框架中,通过二元空间划分树(Binary Space Partitioning,BSP)提供快速的图元查找,这样就能够实时地显示包含上百万个图元的大场景7.1.2 Graphics View的三元素它们三者之间的关系如图7.1所示7.1.2 Graphics View的三元素1.场景类:QGraphicsScene类场景类主要完成的工作包括提供对它包含的图元的操作接口和传递事件、管理各个图元的状态(如选择和焦点处理)、提供无变换的绘制功能(如打印)等事件传播体系结构将场景事件发送给图元,同时也管理图元之间的事件传播。
如果场景接收到了在某一点的鼠标单击事件,场景会将事件传给在这一点的图元管理各个图元的状态(如选择和焦点处理)可以通过QGraphicsScene:: setSelectionArea()函数选择图元,选择区域可以是任意的形状,使用QPainterPath表示若要得到当前选择的图元列表,则可以使用函数QGraphicsScene:: selectedItems()可以通过QGraphicsScene:: setFocusItem()函数或QGraphicsScene:: setFocus()函数来设置图元的焦点,获得当前具有焦点的图元使用函数QGraphicsScene::focusItem()7.1.2 Graphics View的三元素2.视图类:QGraphicsView类它提供一个可视的窗口,用于显示场景中的图元在同一个场景中可以有多个视图,也可以为相同的数据集提供几种不同的视图QGraphicsView是可滚动的窗口部件,可以提供滚动条来浏览大的场景如果需要使用OpenGL,则可以使用QGraphicsView::setViewport()将视图设置为QGLWidget视图接收键盘和鼠标的输入事件,并将它们翻译为场景事件(将坐标转换为场景的坐标)。
使用变换矩阵函数QGraphicsView::matrix()可以变换场景的坐标,实现场景缩放和旋转QGraphicsView提供QGraphicsView::mapToScene()和QGraphicsView:: mapFromScene()用于与场景的坐标进行转换7.1.2 Graphics View的三元素3.图元类:QGraphicsItem类QGraphicsItem主要有以下几点功能 处理鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件 处理键盘输入事件 处理拖曳事件 分组 碰撞检测7.1.3 GraphicsView的坐标系统1.场景坐标 场景坐标是所有图元的基础坐标系统场景坐标系统描述了顶层的图元,每个 图元都有场景坐标和相应的包容框场景坐标的原点在场景中心,坐标原点是X轴 正方向向右,Y轴正方向向下 QGraphicsScene类的坐标系以中心为原点(0,0),如图7.2所示7.1.3 GraphicsView的坐标系统2.视图坐标 视图坐标是窗口部件的坐标视图坐标的单位是像素QGraphicsView视图的 左上角是(0,0),X轴正方向向右,Y轴正方向向下。
所有的鼠标事件最开始都是 使用视图坐标 QGraphicsView类继承自QWidget类,因此它与其他的QWidget类一样,以窗 口的左上角作为自己坐标系的原点,如图7.3所示7.1.3 GraphicsView的坐标系统3.图元坐标 图元使用自己的本地坐标,这个坐标系统通常以图元中心为原点,这也是所 有变换的原点图元坐标方向是X轴正方向向右,Y轴正方向向下创建图元后, 只需注意图元坐标就可以了,QGraphicsScene和QGraphicsView会完成所有的变 换 QgraphicsItem类的坐标系,若在调用QgraphicsItem类的paint()函数重绘图 元时,则以此坐标系为基准,如图7.4所示7.1.3 GraphicsView的坐标系统Graphics View框架提供了多种坐标变换函数,见表7.1映 射 函 数转 换 类 型QgraphicsView::mapToScene()视图到场景QgraphicsView::mapFromScene()场景到视图QgraphicsItem:: mapFromScene()场景到图元QGraphicsItem:: mapToScene()图元到场景QGraphicsItem:: mapToParent()子图元到父图元QGraphicsItem:: mapFromParent()父图元到子图元QGraphicsItem:: mapToItem()本图元到其他图元QGraphicsItem:: mapFromItem()其他图元到本图元7.2 【实例】:图形视图7.2.1 飞舞的蝴蝶以下是实现上述例子的具体操作步骤。
1)新建Qt Widgets Application(详见1.3.1节),项目名为“Butterfly”,基类选择“QMainWindow”,类名命名默认为“MainWindow”,取消“创建界面”复选框的选中状态单击“下一步”按钮,最后单击“完成”按钮,完成该项目工程的建立2)在“Butterfly”项目名上单击鼠标右键,在弹出的快捷菜单中选择“添加新文件.”菜单项,在弹出的对话框中选择“C++ Class”选项单击“Choose.”按钮,弹出对话框,在“Base class”后面的下拉列表框中选择基类名“QObject”,在“Class name”后面的文本框中输入类的名称“Butterfly”3)单击“下一步”按钮,单击“完成”按钮,添加文件“butterfly.h”和“butterfly. cpp”7.2.1 飞舞的蝴蝶(4)Butterfly类继承自QObject类、QGraphicsItem类,在头文件“butterfly.h” 中完成的代码具体内容 (5)在源文件“butterfly. cpp”中完成的代码具体内容如下: #include “butterfly.h“ #include const static double PI=3.1416; Butterfly::Butterfly(QObject *parent) {up = true;//给标志蝴蝶翅膀位置的变量赋初值pix_up.load(“up.png“);//调用QPixmap的load()函数加载所用到的图片pix_down.load(“down.png“);startTimer(100);//启动定时器,并设置时间间隔为100毫秒 }7.2.1 飞舞的蝴蝶boundingRect()函数为图元限定区域范围。
此范围是以图元自身的坐标系为基础设定的具体实现代码内容如下: QRectF Butterfly::boundingRect() const {qreal adjust =2;return QRectF(-pix_up.width()/2-adjust,-pix_up.height()/2-adjust,pix_up.width()+adjust*2,pix_up.height()+adjust*2); }7.2.1 飞舞的蝴蝶在重画函数paint()中,首先判断当前已显示的图片是pix_up还是pix_down 实现蝴蝶翅膀上下飞舞效果时,若当前显示的是pix_up图片,则重绘pix_down图 片,反之亦然具体实现代码内容如下: void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {if(up){painter-drawPixmap(boundingRect().topLeft(),pix_up);up=!up;}else{painter-drawPixmap(boundingRect().topLeft(),pix_down);up=!up;} }7.2.1 飞舞的蝴蝶定时器的timerEvent()函数实现蝴蝶的飞舞,具体实现代码内容如下: void Butterfly::timerEvent(QTimerEvent *) {//边界控制qreal edgex=scene()-sceneRect().right()+boundingRect().width()/2; //限定蝴蝶飞舞的右边界qreal edgetop=scene()-sceneRect().top()+boundingRect(). height()/2; //限定蝴蝶飞舞的上边界qreal edgebottom=scene()-sceneRect().bottom()+boundingRect(). height()/2; //限定蝴蝶飞舞的下边界if(pos().x()=edgex)//若超过了右边界,则水平移回左边界处setPos(scene()-sceneRect().left(),pos().y());if(pos().y()sceneRect().bottom());if(pos().y()=edgebottom)//若超过了下边界,则垂直移回上边界处setPos(pos().x(),scene()-sceneRect().top());angle+=(qrand()%10)/20.0;qreal dx=fabs(sin(angle*PI)*10.0);qreal dy=(qrand()%20)-10.0;setPos(mapToParent(dx,dy));//(a) }7.2.1 飞舞的蝴蝶(6)完成了蝴蝶图元的实现后,在源文件“main.cpp”中将它加载到场景中, 并关联一个视图,具体实现代码内容如下: #include #include “butterfly.h“ #include int main(int argc,char* argv[]) {QApplication a(argc,argv);QGraphicsScene *scene = new QGraphicsScene;scene-setSceneRect(QRectF(-200,-200,400,400));Butterfly *butterfly = new Butterfly;butterfly-setPos(-100,0);scene-addItem(butterfly);QGraphicsView *view = new QGraphicsView;view-setScene(scene);view-resize(400,400);view-show();return a.exec(); }7.2.1 飞舞的蝴蝶(7)运行程序,将程序中用到的图片保存到该工程的D:\Qt\CH7\CH701\ build-Butterfly-Desktop_Qt_5_4_0_MinGW_32bit-Debug文件夹中,运行结果如图 7.5所示。
7.2.2 地图浏览器 通过实现一个地图浏览器的基本功能(包括地图的浏览、放大、缩小,以及显 示各点的坐标等)的例子,如图7.6所示,介绍如何使用Graphics View框架实例 文件见光盘CH7027.2.2 地图浏览器 以下是实现这个例子的。