Qt图形视图框架

7.1.1 Graphics View的特点
(1)Graphics View框架结构中,系统可以利用Qt绘图系统的反锯齿、OpenGL工具来改善绘图性能。
(2)Graphics View支持事件传播体系结构,可以使图元在场景(scene)中交互能力提高1倍,图元能够处理键盘事件和鼠标事件。其中、鼠标包括鼠标的按下、移动
、释放和双击,还可以跟踪鼠标的移动。
(3)在Graphics View框架中,通过二元空间划分树(Binary SpacePartitioning,BSP)提供快速的图元查找,这样就能够实时地包含上百万个图元的大场景。

7.1.2 Graphics View的三元素
场景类(GraphicsScene),视图类(GraphicsView)和图元类(GraphicsItem)。其中场景类提供了一个用于管理位于其中的众多图元容器,视图类用于显示场景中的
图元,一个场景可以通过多个视图表现,一个场景包括多个几何图形。



1、场景类:QGraphicsScene类
它是一个用于放置图元的容器,本身是不可见的,必须通过与之相连的视图类来显示及与外界进行相互操作。通过QGraphicsScene::addItem()可以添加一个图元到到
场景中。图元可以通过多个函数进行检索。QGraphicsScene::items()和一些重载函数可以返回和点、矩形、多边形或向量路径相交的所有的图元。QGraphicsScene
::itemAt()返回指定点的最顶层图元。
场景类主要完成的工作包括提供对它包含的图元的操作接口和传递事件、管理各个图元的状态(如选择和焦点处理)、提供无变换的绘制功能(如打印)等。
事件传播体系结构将场景事件发送给图元,同时也管理图元之间的事件传播。如果场景接收了在某一点的鼠标单击事件,场景会将事件传给在这一点的图元。
QGraphicsScene  scene; QGraphicsRectItem  *rect=scene.addRect(QRectF(0,0,100,100)); QGraphicsItem  *item=scene.itemAt(50,50); QGraphicsScene的事件传播结
构会把场景事件投递到items,也管理多个items之间的传递。假如场景收到了鼠标在某个位置press事件,场景会把这个事件投递给处在那个位置的itemQGraphicsScene
也管理某种item状态,像选择与焦点。你可以通过调用QGraphicsScene::setSelectionArea()来选择items,它需要提供一个任意的形状为参数。这个函数也作为在
QGraphicsView实现橡皮筋选择功能的一个基础。为得到这些已经被选择的items,调用QGraphicsScene::selectedItem()另一个状态处理是是否一个item拥有键盘输入点。
你可以调用QGraphicsScene::setFocusItem()或QGraphics::setFocus()来设定焦点,也可用QGraphicsScene::focusItem()来得到当前拥有焦点的那个item。最后,
QGraphicsScene允许你通过调用QGraphicsScene::render()函数把部分场景送到绘图设备进行渲染。

2、视图类:QGraphicsView类
它提供一个可视的窗口,用于显示场景中的图元。在一场景中可以有多个视图,也可以为相同的数据集提供几种不同的视图。
QGraphicsView是可滚动的窗口部件,可以提供滚动条来浏览大的场景如果需要使用OPenGL,则可以使用QGraphicsView::setViewport()将视图设置为QGLWidget。
视图接收键盘和鼠标的输入事件,并将它们翻译为场景的坐标,实现场景缩放和旋转。QGraphicsView提供QGraphicsView::mapToScene()和QGraphicsView::
mapFromScene()用于与场景的坐标进行转换。

3、图元类:QGraphicsItem类
The Item QGraphicsItem 是场景中图形items的基类。Graphics View 提供了一些标准的、用于典型形状的items。像矩形(QGraphicsRectItem),椭(QGraphicsEllipseItem),
文本(QGraphicsTextItem),当你写定制的item时,那些最有用的一些QGraphicsItem特性也是有效的。除此这外,QGraphicsItem支持以下特性: *鼠标按、移动、释放、
双击事件,鼠标悬停事件,滚轮事件,弹出菜单事件。 *键盘输入焦点,键盘事件。 *拖拽 *组,包括父子关系,使用QGraphicsItemGroup *碰撞检测 Items如同
QGraphicsView一样,位于本地坐标系,它也为item与场景之间,item与item之间的坐标转换提供许多工具函数。而且,也像QGraphicsView一样,它使用矩阵来变换它
的坐标系统:QGraphicsItem::matrix()。它对旋转与缩放单个的Item比较有用。 Items可以包含别的items(孩子)。父items的转换被它的子孙所继承。然而,它的所有函
数(也就是,QGraphicsItem::contains(),QGraphicsItem::boundingRect(),QGraphicsItem::collidesWith()),不会积累这些转换,依然在本地坐标下工作。 QGraphicsItem
通过QGraphicsItem::shape(),QGraphicsItem::collideWith())来支持碰撞检测。这两个都是虚函数。从shape()返回你的item的形状(以本地坐标QPainterPath表示),
QGraphicsItem会为你处理所有的碰撞检测。假如你想提供自己的碰撞检测,你应该重新实现QGraphicsItem::collideWith()。

7.13 Graphics View的坐标系统
Graphics View基于笛卡尔坐标系。item在场景中的位置与几何形状通过x,y坐标表示。当使用未经变形的视图来观察场景时,场景中的一个单位等于屏幕上的一个像素。
在Graphics View中有三个有效的坐标系统:Item坐标系,场景坐标系,视图坐标系。为了简化你的实现,Graphics View提供了方便的函数,允许三个坐标系之间相互映
射。 当渲染时,Graphics View的场景坐标对应于QPainter的逻辑坐标,视图坐标与设备坐标相同。
1、场景坐标
场景坐标是所有图元的基础坐标系统。场景坐标系统描述了顶层的图元,每个图元都有场景坐标和相应的包容框。场景坐标的原点在场景中心,坐标原点是X轴正方向向
右,Y轴正方向向下。
 QGraphicsScene类的坐标系以中心为原点(0,0)。



2、视图坐标
是图坐标是窗口部件的坐标。视图坐标的单位是像素。QGraphicsView视图的左上角是(0,0),X轴正方向向右,Y轴正方向向下。所有的鼠标事件最开始都是使用视图
坐标。
QGraphicsView类继承自QWidget类,因此它与其他的QWidget类一样,以窗口的左上角作为自己的坐标系的原点。



3、图元坐标
  
图元使用自己的本地坐标,这个坐标系统通常以图元中心为原点,这也是所有变换的原点。图元坐标方向是X轴正方向向右,Y轴正方向向下。创建图元后,只需注意图
元坐标就可以了,QGraphicsScene和QGraphicsView会完成所有的变换。
QGraphicsItem类的坐标系,若在调用QGraphicsItem类的paint()函数重绘图元时,则以此坐标系为基准。



经常,处理场景中item时,在场景与item之间,item与item之间,视图与场景之间进行坐标映射,形状映射是非常有用的。举例来讲,当你在QGraphicsView的视口中击
鼠标时,你应该通过调用QGraphicsView::mapToScence()与QGraphicsScene::itemAt()来获知光标下是场景中的哪个item。假如你想获知一个item位于视口中的什么位
置,你应该先在item上调用QGraphicsItem::mapToScene(),然后调用QGraphicsView::mapFromScene()。最后,假如你想在一个视图椭圆中有哪些items,你应该把
QPainterPath传递到mapToScene(),然后再把映射后的路径传递到QGraphicsScene::items()。 你可以调用QGraphicsItem::mapToScene()与QGraphicsItem::
mapFromScene()在item与场景之间进行坐标与形状的映射。也可以在item与其父item之间通过QGraphicsItem::mapToParent()与QGraphicsItem::mapFromItem()进行映
射。所有映射函数可以包括点,矩形,多边形,路径。视图与场景之间的映射也与此类似。对于从视图与item之间的映射,你应该首先映射到场景,然后再从场景item
进行映射。



main.cpp

#include <QApplication>
#include "butterfly.h"
#include <QGraphicsScene>
 
 
int main(int argc, char *argv[])
{
  
    QApplication a(argc, argv);
    //创建一个场景指针对象
    QGraphicsScene *scence = new QGraphicsScene;
    //设置场景区域的大小
    scence->setSceneRect (QRectF(-200, -200, 400, 400));
    //创建一个蝴蝶图元指针对象
    Butterfly *butterfly = new Butterfly;
    //设置蝴蝶图元的起始位置
    butterfly->setPos (-100, 0);
    //添加一个图元到场景中
    scence->addItem (butterfly);
 
 
    //创建一个视图指针对象
    QGraphicsView *view = new QGraphicsView;
    //将这个场景设置到视图中
    view->setScene (scence);
    //设置视图的大小
    view->resize (800, 400);
    view->show ();
 
 
    return a.exec();
}

butterfly.h

#ifndef BUTTERFLY_H
#define BUTTERFLY_H
 
 
#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QGraphicsScene>
#include <QGraphicsView>
 
 
/*
 * void timerEvent(QimerEvent*): 定时器实现动画的原理是在定时器的timerEvent()中对QGraphicsItem进行重绘
 * QRectF boundingRect() const: 为图元限定区域或范围,所有继承自QGraphicsItem的自定义图元都必须实现此函数
 * bool up: 用于标志蝴蝶翅膀的位置(位于上或下)以便实现动态效果
*/
class Butterfly : public QObject, public QGraphicsItem
{
  
    Q_OBJECT
public:
    explicit Butterfly(QObject *parent = 0);
    void timerEvent (QTimerEvent*);
    QRectF boundingRect () const;
 
 
signals:
 
 
public slots:
    //重绘函数
protected:
    void paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
 
 
private:
    bool up;
    //用于表示两幅蝴蝶的图片
    QPixmap pix_up;
    QPixmap pix_down;
 
 
    qreal angle;
};
 
 
#endif // BUTTERFLY_H

butterfly.cpp

#include "butterfly.h"
#include <math.h>
 
 
/*
 * up = true 给标志蝴蝶翅膀位置的变量赋初值
 * 调用QPixmap的load()函数加载所用到的图片
 * 启动定时器,并设置时间间隔为100毫秒
*/
 
 
const static double PI=3.1416;
 
 
Butterfly::Butterfly(QObject *parent) : QObject(parent)
{
  
    up = true;
    pix_up.load ("up.png");
    pix_down.load ("down.png");
    startTimer (100);
}
 
 
/*
 * boundingRect()函数为图元限定区域范围,此范围是以图元自身的坐标系为基础设定的。
 *
*/
QRectF Butterfly::boundingRect () const
{
  
    qreal adjust = 2;
 
 
    return QRectF(-pix_up.width () / 2 - adjust, -pix_up.height () / 2 -adjust,
                  pix_down.width () + adjust * 2, pix_down.height () + adjust * 2);
}
 
 
/*
 * 首先判断当前已显示的图片是pix_up还是pix_down。实现蝴蝶翅膀上下飞舞效果时,若当前显示的pix_up图片,则重绘制
 * pix_down图片,绘制pix_up图片
*/
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;
    }
}
 
 
/*
 * 蝴蝶飞舞的边界控制
 * 限定蝴蝶飞舞的右边界
 * 限定蝴蝶飞舞的上边界
 * 限定蝴蝶飞舞的下边界
*/
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 () <= edgetop)
    {
  
        setPos (pos().x (), scene ()->sceneRect ().bottom ());
    }
    //如果超出了下边界,则垂直移动到上边界处
    if(pos().y () >= edgebottom)
    {
  
       setPos (pos().x (), scene ()->sceneRect ().top ());
    }
 
 
    //angle(0, 0.45)
    angle += (qrand () % 10) / 20.0;
    //abs()函数求整数的绝对值,fabs()求浮点数的绝对值
    qreal dx = fabs(sin(angle * PI) * 10.0);
    //dy(0,9)
    qreal dy = (qrand() % 20) - 10.0;
    //dx,dy完成蝴蝶随机飞行的路径,且dx,dy是相对于蝴蝶的坐标系而言,因此使用mapToParent()函数映射为场景坐标
    setPos(mapToParent (dx, dy));//映射为场景坐标
 
 
}
 
7.2.2 地图浏览器例子
主要介绍Graphics View框架
效果如下:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值