Qt绘图之QGraphicsSceneQGraphicsViewQGraphicsItem详解
  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 #include <QGraphicsItem>
6class MyItem : public QGraphicsItem
day by day
7 {
8public:
9    MyItem();
10    QRectF boundingRect() const;
11void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);
12 };
13#endif// MYITEM_H
1//myitem.cpp
2 #include "myitem.h"
3 #include
4
5 MyItem::MyItem()
6 {
7
8 }
9
10 QRectF MyItem::boundingRect() const
11 {
12    qreal adjust=0.5;
13return QRectF(-18-adjust,-22-adjust,36+adjust,60+adjust);
14 }
15
16void MyItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget)
17 {
18    painter->drawRect(0,0,200,200);
19 }
1//main.cpp
22
3 #include <QtGui/QApplication>
4 #include
5 #include
6 #include
7 #include
8 #include"myitem.h"
9
10int main(int argc, char *argv[])
11 {
12    QApplication a(argc, argv);
13    QGraphicsScene scene;
14    scene.setSceneRect(-300,-300,600,600);
15    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
16    MyItem *item=new MyItem;
17    scene.addItem(item);
18    QGraphicsView view(&scene);
19    view.setRenderHint(QPainter::Antialiasing);
20    view.setCacheMode(QGraphicsView::CacheBackground);
21    view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
马兰谣 伴奏
22    view.setDragMode(QGraphicsView::ScrollHandDrag);
23    size(400,300);
24    view.show();
();
26 }