ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Qt QGraphicsScene QGraphicsView QGraphicsItem学习记录

2020-08-14 10:34:49  阅读:223  来源: 互联网

标签:QGraphicsView 场景 Qt QGraphicsScene 视图 400 图形 函数


一.场景(QGraphicsScene)

QGraphicsScene 提供了图形视图框架的场景,相当于一块画布,并具有以下功能。

1.一个管理大量图形项的快速接口。

2.向每个图形项传播事件

3.管理图形项的状态,比如选择,焦点处理等

4.提供无转换的渲染功能,主要用于打印

简单地一个场景使用

1 QGraphicsScene scene;//场景
2 scene.addText("Hello, world!");//添加文本图形项
3 QGraphicsView view(&scene);//设置视图
4 view.show();
1 addText("Hello, world!") 相当于执行了以下两句
2 
3 QGraphicsTextItem *item = new QGraphicsTextItem("Hello, world!");
4 scene.addItem(item);

如果场景要删除一个图形项,可以使用

removeItem(item)

函数。

一般而言,场景层从下到上共分为3层,分别为背景层(backgroundLayer), 图形项层(Itemlayer)与前景层(ForegroundLayer)。场景绘制总是从背景层开始,然后是图形层,最后是前景层。

1 scene.setForegroundBrush(QColor(255,255,255,100));//前景层颜色为白色半透明
2 scene.setBackgroundBrush(Qt::green);//背景色设置为绿色

对于前景层,我们一般不进行设置,或者像上面这样设置为半透明的白色。对于背景层,这里设置为了绿色,当然,我们也可以将一张图片设置为背景。

scene.setBackgroundBrush(QPixmap(":/background.jpg"));

2. 场景边界矩形

场景大小默认是没有限制的,图形项可以放到场景的任何位置。而场景的边界矩形仅用于场景内部进行索引的维护。

因为如果没有边界矩形,场景就要搜索所有的图形项,然后确定出其边界,这是十分费时的。所以如果要操作一个较大的场景,我们应该给出它的边界矩形。设置边界矩形,可以使用setSceneRect()函数。

3.图形项查找

场景最大的优势之一就是可以快速的锁定图形项的位置,即使有上百万个图形项,items()函数也能在数毫秒的时间内锁定一个图形项的位置。items()函数有几个重载函数来方便的进行图形项的查找。但是有时在场景的一个点可能重叠着几个图形项,这时我们可以使用itemAt()函数返回最上面的一个图形项。对于这些函数的使用,我们到后面讲视图时再举例讲解。

4.事件处理和传播

场景可以传播来自视图的事件,将事件传播给该点最顶层的图形项。但是就像我们在讲图形项时所说的那样,如果一个图形项要接收键盘事件,那么它必须获得焦点。而且,如果我们在场景中重写了事件处理函数,那么在该函数的最后,必须调用场景默认的事件处理函数,只有这样,图形项才能接收到该事件。这一点我们也到后面讲视图时再细讲。

二.视图(QGraphicsView)

QGraphicsView 提供了视图窗口部件,它使场景的内容可视化。你可以给一个场景关联多个视图,从而给一个数据集提供多个视口。视图部件是一个滚动区域,就是说,它可以提供一个滚动条来显示大型的场景。如果要使用OpenGL,你可以使用QGraphicsView::setViewport()函数来添加QGLWidget 。

(一)缩放与旋转

1 QGraphicsView::scale(xScale, yScale);//在分别在x,y方向上缩放xScale,yScale倍。若为1.0倍,则不进行缩放。
2 QGraphicsView::rotate(90);//顺时针旋转90度
(二)场景边框与场景对齐方式 我们在上面讲场景时就提到了场景边框(SceneRect),这里再说说它在视图中的作用。我们前面说过,视图是可以提供滚动条的,但是,这只是在视图窗口小于场景时才自动出现的。如果我们不定义场景边框,那么当场景中的图形项移动到视图可视窗口以外的地方时,视图就会自动出现滚动条,但是即使是图形项再次回到可视区域,滚动条也不会消失。为了解决这个问题,我们可以为场景设置边框,这样,当图形项移动到场景边框以外时,视图是不会提供额外的滚动区域的。        而当整个场景都可视时,也就是说视图没有滚动条时,我们可以通过setAlignment()函数来设置场景在视图中的对齐方式,如左对齐Qt::AlignLeft ,向上对齐Qt::AlignTop ,中心对齐Qt::AlignCenter。更多的对齐方式,可以查看帮助中Qt::Alignment 关键字。默认的对齐方式是Qt::AlignCenter 。而且几种对齐方式可以通过“按位或”操作一起使用。我们在上面的程序中的myitem.cpp文件中的构造函数最后添加一行代码:
setAlignment(Qt::AlignLeft | Qt::AlignTop);
(三)拖动模式 在QGraphicView中提供了三种拖动模式,分别是:
1 QGraphicsView::NoDrag :忽略鼠标事件,不可以拖动。
2 QGraphicsView::ScrollHandDrag :光标变为手型,可以拖动场景进行移动。
3 QGraphicsView::RubberBandDrag :使用橡皮筋效果,进行区域选择,可以选中一个区域内的所有图形项。
我们可以利用setDragMode()函数进行相应设置。 下面我们更改上面的程序。在myview.cpp中的构造函数中的最后添加一行代码:
setDragMode(QGraphicsView::ScrollHandDrag);//手型拖动
并将场景外框放大一点:
scene->setSceneRect(0,0,800,800);
这时运行程序,虽然出现了小手,但是并不能拖动场景。为什么呢?我们在mousePressEvent()函数中添加一行代码:
QGraphicsView::mousePressEvent(event);
这时再运行程序,发现已经成功了。效果如下: 我们在事件函数的最后添加了一行:
QGraphicsView::mousePressEvent(event);
这样程序才能执行默认的事件。这也是我们下面要说的事件传播的内容的一部分。 (四)事件传递 在上面我们看到必须在事件函数的最后将event参数传递出去,才能执行默认的事件操作。其实不止上面那一种情况,在图形视图框架中,鼠标键盘等事件是从视图进入的,视图将它们传递给场景,场景再将事件传递给该点的图形项,如果该点有多个图形项,那么就传给最上面的图形项。所以要想使这个事件能一直传播下去,我们就需要在重新实现事件处理函数时,在其最后将event参数传给默认的事件处理函数。比如我们重写了场景的键盘按下事件处理函数,那么我们就在该函数的最后写上
QGraphicsScene::keyPressEvent(event);
一行代码。
(五)背景缓存 如果场景的背景需要大量耗时的渲染,可以利用CacheBackground来缓存背景,当下次需要渲染背景时,可以快速进行渲染。它的原理就是,把整个视口先绘制到一个pixmap上。但是这个只适合较小的视口,也就是说,如果视图窗口很大,而且有滚动条,那么就不再适合缓存背景。我们可以使用
setCacheMode(QGraphicsView::CacheBackground);
来设置背景缓存。默认设置是没有缓存QGraphicsView::CacheNone   (六)OpenGL渲染 QGraphicsView默认使用一个QWidget作为视口部件,如果我们要使用OpenGL进行渲染,可以使用setViewport()函数来添加一个QGLWidget对象。看下面的例子。 我们先在项目文件graphicsView04.pro中加入
QT += opengl
说明要使用OpenGL模块,然后在myview.cpp文件中添加头文件:
#include <QtOpenGL>
最后在构造函数中加入代码:
1 QGLWidget *widget =new QGLWidget(this);
2 setViewport(widget);
这样便使用OpenGL进行渲染了。关于OpenGL,我们在后面的3D绘图部分再讲。 (七)打印 图形视图框架提供了两个打印函数render(),一个是在QGraphicsScene中,一个是在QGraphicsView中,并且它们的函数原型是一模一样的。不过它们实现的效果稍有不同。看一面的例子。 我们更改鼠标按下事件槽函数的内容如下:
1 void MyView::mousePressEvent(QMouseEvent*event)
2 {
3     rotate(90); //视图旋转顺时针90度
4    QPixmap pixmap(400,400);  //必须指定大小
5    QPainter painter(&pixmap);
6    render(&painter,QRectF(0,0,400,400),QRect(0,0,400,400));  //打印视图指定区域内容
7     pixmap.save("../graphicsView04/save.png");
8    QGraphicsView::mousePressEvent(event);
9 }
这里我们使用了视图的render()函数,其中的QRectF参数是指设备的区域,这里是指pixmap。而QRect参数是指视图上要打印的区域。我们利用QPixmap类的save()函数,将pixmap图片保存到我们项目源码目录中,文件名为“save.png”。下面是运行程序后,点击鼠标,生成的图片的效果: 我们每点击一次鼠标,就会旋转视图,那么生成的图片就是当前视口的截图。下面我们使用场景的打印函数,将上面的打印一行的代码改为:
scene()->render(&painter,QRectF(0,0,400,400),QRect(0,0,400,400));//打印场景内容
这时无论视图怎样变换,生成的图片总是一样的。而且它并没有打印场景背景的图片。就像我们看到的,视图的打印函数是依据视图的坐标系进行打印的,我们看到的就是打印出来后的效果,它可以看做是程序窗口的截屏。而场景的打印函数,是依据场景的坐标系的,无论视图怎么转换,只要场景坐标系没有变换,它打印出来的图片都是一样的。

标签:QGraphicsView,场景,Qt,QGraphicsScene,视图,400,图形,函数
来源: https://www.cnblogs.com/ybqjymy/p/13500759.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有