Qt绘图之QGraphicsScene QGraphicsView QGraphicsItem详解(转)

Graphics View提供了一个界面,它既可以管理大数量的定制2D graphical items,又可与它们交互,有一个view widget可以把这些项绘制出来,并支持旋转与缩放。这个柜架也包含一个事件传播结构,对于在scene中的这些items,它具有双精度的交互能力。 Items能处理键盘事件,鼠标的按,移动、释放、双击事件,也可以跟踪鼠标移动。Graphics View使用BSP树来提供对item的快速查找,使用这种技术,它可以实时地绘制大规模场景,甚至以百万items计。Graphics View在Qt 4.2中被引用,它替代了它的前辈QCanvas。

Graphics View的体系结构

Graphics View提供的是一种类似于Qt model-view的编程。多个views可以监视同一个场景,而场景包含多个具有多种几何外形的items。

场景

QGraphicsScene 表示Graphics View中的场景,它有以下职责: 为管理大量的items提供一个快速的接口。 传播事件到每个item。 管理item的状态,例如选择,焦点处理。 提供未经变换的渲染功能,主要用于打印。 场景作为QGraphicsItem对象的容器。通过调用QgraphicsScene::addItem()把这些Items加入到场景中。可以使用众 多的查找函数来获取特定的items。QGraphicsScene:items()与它的许多重载函数可获取那些与点、矩形,多边形,向量路径等相交或 是有包含有关系的items。QGraphicsScene::itemAt()返回特定上最顶端的item。所有的item查找函数都以出栈序列返回 (也就是说,第一个返回的是最顶端的,最后一个返回的是最底端的)。 QGraphicsScene  scene; QGraphicsRectItem  *rect=scene.addRect(QRectF(0,0,100,100)); QGraphicsItem  *item=scene.itemAt(50,50); //item==rect; QGraphicsScene的事件传播结构会把场景事件投递到items,也管理多个items之间的传递。假如场景收到了鼠标在某个位置press事 件,场景会把这个事件投递给处在那个位置的item。QGraphicsScene也管理某种item状态,像选择与焦点。你可以通过调用 QGraphicsScene::setSelectionArea()来选择items,它需要提供一个任意的形状为参数。这个函数也作为在 QGraphicsView实现橡皮筋选择功能的一个基础。为得到这些已经被选择的items,调用 QGraphicsScene::selectedItem()。另一个状态处理是是否一个item拥有键盘输入焦点。你可以调用 QGraphicsScene::setFocusItem()或QGraphics::setFocus()来设定焦点,也可用 QGraphicsScene::focusItem()来得到当前拥有焦点的那个item。最后,QGraphicsScene允许你通过调用 QGraphicsScene::render()函数把部分场景送到绘图设备进行渲染。

视图

QGraphicsView 提供了视图部件,它可视化场景中的内容。你可以联结多个视图到同一个场景,对这个相同的数据集提供几个视口。视口部件是一个滚动区域,它提供了滚动条以对 大场景进行浏览。为了使用OpenGL,你应该调用QGraphicsView::setViewport()来把一个QGLWidget设为视口。视图 从键盘,鼠标接收输入事件,在发送这些事件到场景之前,会对这些事件进行适当的翻译(把事件坐标转换成对应的场景坐标)。

利 用转换矩阵,QGraphicsView::matrix(),视图可变换场景的坐标系统。这允许高级的导航特性,如缩放,旋转。为了方 便,QGraphicsView也提供了在视图与场景之间进行坐标转换的函 数:QGraphicsView::mapToScene(),QGraphicsView::mapForScene()。

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()。

Graphics View 坐标系统

Graphics View基于笛卡尔坐标系。item在场景中的位置与几何形状通过x,y坐标表示。当使用未经变形的视图来观察场景时,场景中的一个单位等于屏幕上的一个 像素。在Graphics View中有三个有效的坐标系统:Item坐标系,场景坐标系,视图坐标系。为了简化你的实现,Graphics View提供了方便的函数,允许三个坐标系之间相互映射。 当渲染时,Graphics View的场景坐标对应于QPainter的逻辑坐标,视图坐标与设备坐标相同。

Item坐标

Items 位于它们自己的坐标系中。它的坐标都以点(0,0)为中心点,这也是所有变换的中心点。在item坐标系中的几何图元,经常被称为item点,item 线,item矩形。当创建一个定制的item,item坐标是所需要考虑的。QGraphicsScene与QGraphicsView可以为你执行所有 转换,这使得实现定制的item变得容易。举例来说,假如你收到鼠标按或是拖进入事件,事件的位置以item坐标的形式给出。 QGraphicsItem::contain()虚函数,当某个点的位置在你的item范围内时,返回true,否则返回false。这个点参数使用 item坐标,相似地,item的包围矩形与形状也使用item坐标。 Item位置指的是item的中心点在它父亲的坐标系中的坐标。以这种思想来看,场景指的就是那些祖先最少的item的“父亲”。最上级的Item位置就 是在场景中的位置。 子坐标与父坐标之间是相关的,假如孩子未经变换,子坐标与父坐标之间的差值等于在父坐标系下,父item与子item之间的距离。例如,假如一个未经变换 的子item位置与其父item的中心重合,那么这两个item的坐标系统完全相同。如果孩子的位置是(10,0),那么孩子坐标系中的(0,10)点, 对应于父坐标系中的(10,10)点。 因为item的位置与变换是相对于父item的,子item的坐标不会被父亲的变换影响,尽管父item的变换隐含地对子item做了变换。在上面的例子 中,即使父item旋转,缩放,子item的(0,10)点依然对应于父item的(10,10)点。然而,相对于场景来讲,子item会遵循父item 的变换。假如父item被缩放(2X,2X),子item的位置在场景中的坐标是(20,0),它的(10,0)点则与场景中的(40,0)对应 。除了QGraphicsItem::pos(),QGraphicsItem的函数以Item坐标工作,如一个item’s包围矩形总是以item坐标 的形式给出。

场景坐标

场 景坐标系统描述了每个最顶级item的位置,也是从视图向场景投递场景事件的基础。场景中的每个item有场景位置与包围矩形 (QGraphicsItem::scenePos(),QGraphicsItem::sceneBoundingRect()), 另外,它有自己本地item位置与包围矩形。场景位置描述了item在场景坐标下的位置,它的场景包围矩形则用于QGraphicsScene决定场景中 哪块区域发生了变化。场景中的变化通过QGraphicsScene::changed()信号来通知,它的参数是场景矩形列表。

视图坐标

视 图坐标是widget的坐标,视图坐标中每个单位对应一个像素。这种坐标的特殊之处在于它是相对于widget或是视口的,不会被所观察的场景所影响。 QGraphicsView的视口的左上角总是(0,0),右下角总是(视口宽,视口高)。所有的鼠标事件与拖拽事件,最初以视图坐标表示,就应该把这些 坐标映射到场景坐标以便与item交互。

坐标映射

经 常,处理场景中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进行映射。

关键特性

缩放与旋转

QGraphicsView 通过QGraphicsView::setMatrix()支持同QPainter一样的仿射变换,通过对一个视图应用变换,你可以很容易地支持普通的导 航特性如缩放与旋转。下面是一个例子: class View:;public QGraphicsView { Q_OBJECT //….. public slots: void zoomIn() {scale(1.2,1.2);} void zoomOut() {scale(1/1.2,1/1.2);} void rotateLeft() {rotate(-10);} void rotateRight() {rotate(10);} }; 这些槽应与QToolButtons联接,并使autoRepeat有效。当对视图变换时,QGraphicsView会对视图中心进行校正。

拖拽

因 为QGraphicsView继承自QWidget,它也提供了像QWidget那样的拖拽功能,另处,为了方便,Graphics View柜架也为场景,每个item提供拖拽支持。当视图接收到拖拽事件,它可翻译为QGraphicsSceneDragDropEvent,再发送到 场景。场景接管这个事件,把它发送到光标下接受拖拽的第一个item。 从一个item开始拖拽时,创建一个QDrag对象,传递开始拖拽的那个widget的指针。Items可以同时被多个视图观察,但只有一个视图可以开始 拖拽。拖拽在多数情况下是从按下鼠标或是移动鼠标开始的,因此,在 mousePressEvent()或mouseMoveEvent()中,你可以从事件中得到那个原始的widget指针,例如: void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { QMimeData *data=new QMimeData; data->setColor(Qt::green); QDrag *drag=new QDrag(event->widget()); drag->setMimeData(data); drag->start(); } 为了在场景中载取拖拽事件,你应重新实现QGraphicsScene::dragEnterEvent()和在QGraphicsItem的子类里任何 与你特定场景需要的事件处理器。items也可以通过调用QGraphicsItem::setAcceptDrops()获得拖拽支持,为了处理将要进 行的拖拽,你需要重新实现 QGraphicsItem::dragEnterEvent(),QGraphicsItem::dragMoveEvent(),QGraphicsItem::dragLeaveEvent() 和QGraphicsItem::dropEvent()。

光标与工具提示

像 QWidget一样,QGraphicsItem也支持光标(QgraphicsItem::setCursor)与工具提示 (QGraphicsItem::setToolTip())。当光标进入到item的区域,光标与工具提示被QGraphicsView激活(通过调用 QGraphicsItem::contains()检测)。你也可以直接在视图上设置一个缺省光标 (QGraphicsView::setCursor)。

动画

Graphics View支持几种级别的动画。你可以很容易地通过把QGraphicsItemAnimatoin与你的item联结来 装配出动画路径,这允许以时间线来控制动画,在所有平台上以稳定的速率运作。QGraphicsItemAnimation允许你为item的位置,旋 转,缩放,剪切,变换等产生一条路径,动画可以用QSlider来控制,或更为普遍使用的QTimeLine。 另一种是从QObject和QGraphicsItem继承,item可以设置自己的定时器,以在QObject::timeEvent()中增加步进的 方式来控制动画。 第三种,是通过调用QGraphicsScene::advance()来推进场景,它又依次调用QGraphicsItem::advance().

OpenGL渲染

为 了使用OpenGL渲染,你要设置一个新的QGLWidget作为QGraphicsView的视 口:QGraphicsView::setViewPort()。假如你让OpenGL提供反锯齿功能,你需要OpenGL采样缓冲支持。 QGraphicsView view(&scene); view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));

Item组

通 过把一个item做为另一个item的孩子,你可以得到item组的大多数本质特性:这些items会一起移动,所有变换 会从父到子传递。QGraphicsItem也可以为它的孩子处理所有的事件,这样就允许以父亲代表它所有的孩子,可以有效地把所有的items看作一个 整体。 另外,QGraphicsItemGroup是一个特殊的item,它既对孩子事件进行处理又有一个接口把items从一个组中增加和删除。把一个 item加到 QGraphicsItemGroup仍会保留item的原始位置与变换,而给一个item重新指定父item则会让item根据其新的父亲重新定位。可 以用QGraphicsScene::createItemGroup()建组。

1 //myitem.cpp
2 //myitem.h
3 #ifndef MYITEM_H
4 #define MYITEM_H
5  
6 #include <QGraphicsItem>
7  
8 class MyItem : public QGraphicsItem
9 {
10 public:
11 MyItem();
12 QRectF boundingRect() const;
13 void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);
14 };
15  
16 #endif // MYITEM_H

1 //myitem.cpp
2 #include "myitem.h"
3 #include
4 MyItem::MyItem()
5 {
6 }
7  
8 QRectF MyItem::boundingRect() const
9 {
10 qreal adjust=0.5;
11 return QRectF(-18-adjust,-22-adjust,36+adjust,60+adjust);
12 }
13  
14 void MyItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget)
15 {
16 painter->drawRect(0,0,200,200);
17  
18 }

1 //main.cpp
2 #include <QtGui/QApplication>
3 #include
4 #include
5  #include
6  #include
7 #include"myitem.h"
8 int main(int argc, char *argv[])
9 {
10     QApplication a(argc, argv);
11  
12     QGraphicsScene scene;
13     scene.setSceneRect(-300,-300,600,600);
14     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
15  
16     MyItem *item=new MyItem;
17     scene.addItem(item);
18  
19     QGraphicsView view(&scene);
20     view.setRenderHint(QPainter::Antialiasing);
21     view.setCacheMode(QGraphicsView::CacheBackground);
22     view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
23     view.setDragMode(QGraphicsView::ScrollHandDrag);
24     view.resize(400,300);
25     view.show();
26     return a.exec();
时间: 2024-12-25 15:08:03

Qt绘图之QGraphicsScene QGraphicsView QGraphicsItem详解(转)的相关文章

Qt绘图之QGraphicsScene QGraphicsView QGraphicsItem详解

Graphics View提供了一个界面,它既可以管理大数量的定制2D graphical items,又可与它们交互,有一个view widget可以把这些项绘制出来,并支持旋转与缩放.这个柜架也包含一个事件传播结构,对于在scene中的这些items,它具有双精度的交互能力.Items能处理键盘事件,鼠标的按,移动.释放.双击事件,也可以跟踪鼠标移动.Graphics View使用BSP树来提供对item的快速查找,使用这种技术,它可以实时地绘制大规模场景,甚至以百万items计.Graph

qt的资源替换搜索QDir详解

QDir对跨平台的目录操作提供了很多的便利,为了更加方便的提供全局资源的查找,QDir提供了搜索路径替换功能,解决了资源搜索不便的问题,也能提高文件查找的效率. QDir通过已知的路径前缀去搜索并定位文件,搜索路径增加是有序的.从第一个设置的搜索路径开始,是不是觉得和cocos2d的路径搜索非常相似呢. 见如下QT的原版例子 QDir::setSearchPaths("icons", QStringList(QDir::homePath() + "/images")

Qt on Android: Qt Quick 之 Hello World 图文详解

在上一篇文章,<Qt on Android:QML 语言基础>中,我们介绍了 QML 语言的语法,在最后我们遗留了一些问题没有展开,这篇呢,我们就正式开始撰写 Qt Quick 程序,而那些问题,随着本系列文章的展开也会一一被干掉. 在开始介绍 Qt Quick 应用的基本元素之前,我们先来创建一个 HelloQtQuickApp 项目,就是经典的 Hello World 了. 笔者的教程最终会面向 Qt Quick 与 C++ 混合编程,所以我们 HelloQtQuickApp 从零开始.

Android中Canvas绘图之Shader使用图文详解

概述 我们在用Android中的Canvas绘制各种图形时,可以通过Paint.setShader(shader)方法为画笔Paint设置shader,这样就可以绘制出多彩的图形.那么Shader是什么呢?做过GPU绘图的同学应该都知道这个词汇,Shader就是着色器的意思.我们可以这样理解,Canvas中的各种drawXXX方法定义了图形的形状,画笔中的Shader则定义了图形的着色.外观,二者结合到一起就决定了最终Canvas绘制的被色彩填充的图形的样子. 类android.graphics

Qt中QGraphics类坐标映射关系详解(有图有真相,实例讲解)

如果你英文足够好,可以参考Qt帮助文档中的:The Graphics View Coordinate System. --------------------------------------------------------------------------------------------------------------------------- 首先,先上显示界面图(Embeded dialog),下面就是以该实例讲解: 1.QGraphicsItem及其衍生类以及其他可作为图

Android绘图监听接口OnPreDrawListener详解

public static interface ViewTreeObserver.OnPreDrawListener 我们先看下API中的定义: 类概述: 为即将绘制视图树时执行的回调函数定义的接口. 共有方法: public abstract boolean onPreDraw () 即将绘制视图树时执行的回调函数.这时所有的视图都测量完成并确定了框架. 客户端可以使用该方法来调整滚动边框,甚至可以在绘制之前请求新的布局. 综上,ViewTreeObserver是用来帮助我们监听某些View的

Qt Quick 之 PathView 详解

开始的开始,请给我的决赛博文投票:点此进入投票页面,网页最下方有投票按钮,投我一票,谢谢. PathView ,顾名思义,沿着特定的路径显示 Model 内的数据. Model 可以是 QML 内建的 ListModel . XmlListModel ,也可以是在 C++ 中实现的 QAbstractListModel 的派生类. PathView 恐怕是 Qt Quick 提供的 Model-View 类库中最复杂也最灵活的一个了. 要使用一个 PathView ,至少需要设置 model .

Qt Quick 之 QML 与 C++ 混合编程详解

Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的,也有很多局限性,原来 Qt 的一些技术,比如低阶的网络编程如 QTcpSocket ,多线程,又如 XML 文档处理类库 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可用,要么用起来不方便,所以呢,很多时候我们是会基于这样的原则来混合使用 QML 和 C++: QML 构建界面, C++ 实现非界面的业务逻辑和复杂运算. 请给

Qt on Android: Qt Quick 组件与对象动态创建详解

在<Qt on Android: Qt Quick 事件处理之信号与槽>一文中介绍自定义信号时,举了一个简单的例子,定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Connections 对象连接到组件的 colorPicked 信号,改变文本的颜色. 当时用到的 Component . Loader 两个特性,一直没来得及介绍,可能很多人都还在雾里看花呢.这次呢,我们就来仔仔细细地把他们讲清楚. 请给我的参赛文章<Qt on Androi