Qt学习笔记--图形视图框架
Qt图形视图、动画、状态机框架
Graphics View的坐标系统
3.图形项坐标
QGraphicsItem类的坐标系,若在调用QGraphicsItem类的paint()函数重绘图元 时,则以此坐标系为基准。它的坐标都以点(0,0)为中心点,这也是所有变换的中 心点。 图形项位置指的是图形项的中心点在它父亲的坐标系中的坐标。如无父亲图 形项,则选场景坐标系。以这种思想来看,场景指的就是那些祖先最少的图形项 的“父亲”。最上级的图形项位置就是在场景中的位置。 子图形项会随着父图形项的变换而变换。(一起缩放,一起旋转等)。
e
Graphics View的坐标系统
2.视图坐标
QGraphicsView类继承自QWidget类,因此它与其他的QWidget类一样,以窗口 的左上角作为自己坐标系的原点,如图所示。 视图坐标是widget的坐标,视图坐标中每个单位对应一个像素。这种坐标的 特殊之处在于它是相对于widget或是视口的,不会被所观察的场景所影响。 QGraphicsView的视口的左上角总是(0,0),右下角总是(视口宽,视口高)。 所有的鼠标事件与拖拽事件,最初以视图坐标表示,需要把这些坐标映射到场景 坐标以便与图形项交互。
Graphics View的坐标系统
1.场景坐标
QGraphicsScene类的坐标系以中心为原点(0,0),如图所示。 场景坐标系统描述了每个最顶级图形项的位置,也是从视图向场景投递场景 事件的基础。场景中的每个图形项有场景位置与包围矩形 (QGraphicsItem ::scenePos(), QGraphicsItem::sceneBoundingRect()), 另外,它有 自己本地图形项位置与包围矩形。场景位置描述了图形项在场景坐标下的位置, 它的场景包围矩形则用于QGraphicsScene决定场景中哪块区域发生了变化。场景 中的变化通过QGraphicsScene::changed ()信号来通知,它的参数是场景矩形列表。
QT图形视图框架
QT图形视图框架使⽤QPushButton、QLabel、QCheckBox等构成GUI的控件或⾃定义图形时,开发应⽤程序会变得很简单。
但是如果想在GUI中使⽤数⼗个或者数百个图形对象,向⽤户完美展⽰控制场景,则会受到很多的限制。
图形视图框架⽤来管理2D图形项,⽀持绘制、缩放、事件响应等等。
1、快速提供并管理⼤量对象2、将事件传递到每⼀个对象3、管理焦点处理或对象选择等状态图形视图框架是按照MVC设计模式绘图, MVC设计模式包括三个元素:数据的模型(Model),⽤户界⾯的视图(View) ,⽤户再界⾯上的操作控制Controller。
QGraphicsViewQGraphicsView 是为了在场景上显⽰图元⽽提供的类。
QGraphicsView包括可视控件区域和⽤于显⽰⼤场景滚动区域,可以接受⽤户输⼊事件。
QGraphicsView间接继承⾄QWidget。
QGraphicsSceneQGraphicsScene类可以保存图元,也可以处理⽤户输⼊事件。
是图形对象QGraphicsItem的容器,为管理⼤量的items提供⼀个快速的接⼝。
QGraphicsScene只继承⾃QObject,所以本⾝是不可见的,必须通过与之相连的视图类QGraphicsView来显⽰.QGraphicsItemQGraphicsItem是为了在图形视图上实现图形对象⽽提供的类。
⽀持⿏标、键盘、焦点事件,⽀持拖放,在它的基础上可以继承出各种图元类。
⽀持碰撞检测collision detection.1 QGraphicsScene的常⽤函数常⽤添加图元函数QGraphicsScene::setBackgroundBrush //填充背景⾊QGraphicsScene::setForegroundBrush //填充前景⾊QGraphicsScene::addSimpleText //添加简单⽂本QGraphicsScene::addLine //添加直线QGraphicsScene::addRect //添加矩形QGraphicsScene::addEllipse //添加椭圆QGraphicsScene::addWidget //添加窗⼝QGraphicsScene::addPixmap //添加图⽚例如:#include <QApplication>#include <QGraphicsView>#include <QGraphicsRectItem>#include <QLabel>int main(int argc, char** argv){QApplication app(argc, argv);QGraphicsView view;QGraphicsScene scene;view.setScene(&scene);view.show();view.resize(400, 400);/*设置场景的背景⾊前景⾊*/scene.setBackgroundBrush(QBrush(Qt::red));scene.setForegroundBrush(QBrush(QColor(0, 255, 0, 50)));/*添加线*/scene.addLine(0, 0, 100, 100, QPen(Qt::black));/*添加矩形*/scene.addRect(0, 100, 100, 100, QPen(Qt::yellow), QBrush(Qt::blue));/*添加椭圆*/scene.addEllipse(100, 0, 100, 100, QPen(Qt::red), QBrush(Qt::green));/*添加简单⽂本,并且设置⽂本字体,并且描边*/scene.addSimpleText("hello", QFont("system", 40))->setPen(QPen(QBrush(Qt::yellow), 3));/*添加图⽚,并且移动位置*/scene.addPixmap(QPixmap("E:\\qt_workspace\\pic\\wallet.png"))->setPos(200, 200);/*添加⼀个窗⼝*/QLabel label("widget");scene.addWidget(&label);return app.exec();}操作图元函数QGraphicsScene::itemAt //查找场景某个中最表层的itemQGraphicsScene::setSelectionArea //设置选定区域QGraphicsScene::setSceneRect //设置场景的区域⼤⼩QGraphicsScene::itemsBoundingRect //根据所有的item计算区域⼤⼩QGraphicsScene:: selectedItems //获取被选中的item,item必须为可选QGraphicsItem::ItemIsSelectable 2 QGraphicsItem的常⽤函数QGraphicsItem::rect //不带边框的图形区域QGraphicsItem::boundingRect //带边框的图形区域QGraphicsItem::collidesWithItem //碰撞检测QGraphicsItem::setScale //缩放QGraphicsItem::setRotation //旋转QGraphicsItem::setZValue //设置z坐标,图元的叠加先后顺序可以⽤它来设置QGraphicsItem::setPos //设置位置坐标设置item的属性void QGraphicsItem::setFlags(GraphicsItemFlags flags);/**参数GraphicsItemFlags flags 为枚举类型,可以以下值* QGraphicsItem::ItemIsMovable 是否可以移动* QGraphicsItem::ItemIsSelectable 是否可以被选中* QGraphicsItem::ItemIsFocusable 是否可以设置为焦点item*/3 图形视图的坐标系3.1 QGraphscItem图元坐标系图元对象都有⾃⾝的坐标系,坐标系以(0,0)为坐标原点,⾃左向右递增是x轴,⾃上⽽下递增是y轴,⽽且所有图元对象的移动转换作⽤点都是(0, 0),坐标值可以是浮点型数值。
Qt基础教程之ModelView(模型视图)结构
Model/View(模型/视图)结构是Qt 中用界面组件显示与编辑数据的一种结构,视图(View)是显示和编辑数据的界面组件,模型(Model)是视图与原始数据之间的接口。
GUI 应用程序的一个很重要的功能是由用户在界面上编辑和修改数据,典型的如数据库应用程序。
数据库应用程序中,用户在界面上执行各种操作,实际上是修改了界面组件所关联的数据库内的数据。
将界面组件与所编辑的数据分离开来,又通过数据源的方式连接起来,是处理界面与数据的一种较好的方式。
Qt 使用 Model/View 结构来处理这种关系,Model/View 的基本结构如图 1 所示。
图 1 Model/View基本结构其中各部分的功能如下:•数据(Data)是实际的数据,如数据库的一个数据表或SQL查询结果,内存中的一个 StringList,或磁盘文件结构等。
•视图或视图组件(View)是屏幕上的界面组件,视图从数据模型获得每个数据项的模型索引(model index),通过模型索引获取数据,然后为界面组件提供显示数据。
Qt 提供一些现成的数据视图组件,如 QListView、QTreeView 和QTableView 等。
•模型或数据模型(Model)与实际数据通信,并为视图组件提供数据接口。
它从原始数据提取需要的内容,用于视图组件进行显示和编辑。
Qt 中有一些预定义的数据模型,如 QStringListModel 可作为 StringList 的数据模型,QSqlTableModel 可以作为数据库中一个数据表的数据模型。
由于数据源与显示界面通过 Model/View 结构分离开来,因此可以将一个数据模型在不同的视图中显示,也可以在不修改数据模型的情况下,设计特殊的视图组件。
在 Model/View 结构中,还提供了代理(Delegate)功能,代理功能可以让用户定制数据的界面显示和编辑方式。
在标准的视图组件中,代理功能显示一个数据,当数据被编辑时,代理通过模型索引与数据模型通信,并为编辑数据提供一个编辑器,一般是一个 QLineEdit 组件。
QT学习笔记4:QT中GraphicsView编程
QT学习笔记4:QT中GraphicsView编程⼀、QGraphicsScene1、QGraphicsSceneQGraphicsScene继承⾃QObject,是⼀个管理图元的容器,与QGraphicsView合⽤可以在2D屏幕上显⽰如线、三⾓形、⽂本、⾃定义图元等图元。
QGraphicsScene是不可见的,只⽤于管理图元。
为了查看场景,需要创建⼀个视图组件。
⼀个场景分为三个层:图元层、前景层和背景层。
场景的绘制总是从背景层开始,然后是图形项层,最后是前景层。
2、事件处理与传播QGraphicsScene的责任之⼀是传播来⾃视图的事件。
要发送⼀个事件到场景,需要构造⼀个继承⾃QEvent的事件,使⽤QApplication::sendEvent()函数发送事件。
event()函数负责派发事件到各个图元。
常⽤的事件会被便利事件处理函数处理,如⿏标按下事件会被mousePressEvent()函数处理。
按键事件会被派发到焦点图元。
为了设置焦点图元,可以调⽤setFocusItem()函数,或是图元⾃⾝调⽤QGraphicsItem::setFocus()函数。
调⽤focusItem()函数可以获取当前的焦点图元。
为了兼容图形组件,场景维护着⾃⼰的焦点信息。
默认场景并没有焦点,并且所有的按键事件会别丢弃。
如果setFocus()函数被调⽤,或是场景中⼀个图元获得了焦点,场景会⾃动获得焦点。
如果场景有焦点,hasFocus()函数会返回true,按键事件会被发送到焦点图元。
如果场景失去了焦点,⽽图元有焦点(如调⽤clearFocus()函数),场景会维护图元的焦点信息,⼀旦场景重新获得焦点,会确保最后⼀个有焦点的图元获得焦点。
对于悬停效果,QGraphicsScene会派发悬停事件,如果某个图元接受了悬停事件(调⽤QGraphicsItem::acceptHoverEvents()),当⿏标进⼊图元的区域时,图元会接收到⼀个GraphicsSceneHoverEnter事件。
【图书】【C 】【QT】QT图形用户界面应用程序框架解析
X
画布模块 为可视化效果,图表和其它而优化的二维图形领 域。
表格模块 灵活的可编辑的表格/电子表格
X
X
XML模块 通过SAX接口和DOM Level 1很好且已经成形的 XML解析器。
SQL模块 SQL数据库访问类。
X
X
使用Qt快速地构建流行的GUI
GUN协议
为保证 GNU 软件可以自由地“使用、复制、修改和 发布”,所有 GNU 软件都包含一份在禁止其他人添 加任何限制的情况下,授权所有权利给任何人的协议 条款,GNU通用公共许可证(GNU General Public License,GPL)。这个就是被称为“反版权”的概 念。GNU 也针对不同场合,提供GNU宽通用公共许 可证 (GNU Lesser General Public License, LGPL) 与GNU自由文档许可证 (GNU Free Documentation License, GFDL) 这两种协议条款。
关于Qt
停靠窗口
停靠窗口是指用户可以在工具栏区域内或区域 间随意移动的窗口。用户可以对停靠窗口解锁, 使该窗口浮在应用程序顶部,也可以使窗口最 小化。
Qt Designer 设计者工具
功能强大的GUI 布局与窗体构造器,能够在所有支持平台上,以本地化 的视图外观与认知,快速开发高性能的用户界面。
关于Qt
Qt是一个用于桌面系统和嵌入式开发的跨平台 应用程序框架 ,由挪威TrollTech公司出品 用于本地化跨平台应用开发的领先性框架 对不同平台(Unix, Windows, and Mac)对 API进行了封装,如文件处理、网络(操作, 协议),进程处理、线程、数据库访问等
Qt图形视图体系结构示例解析(视图、拖拽、动画)
Qt图形视图体系结构⽰例解析(视图、拖拽、动画) 本博的⽰例来⾃与QT Example:C:\Qt\Qt5.9.3\Examples\Qt-5.9.3\widgets\graphicsview\dragdroprobot 将通过分析⽰例完成主要功能: (1)颜⾊图元绘制 (2)机器⼈图元绘制 (3)颜⾊图元的⿏标事件 (4)机器⼈图元的DragDrop事件 (5)图元动画效果⼀、颜⾊图元类实现 QGraphicsItem作为所有图元类的基类,⾃定义图元类需继承QGraohicsItem类,实现其基类的纯虚函数virtual QRectF boundingRect() const = 0;virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) = 0; boundingRect()设置图元的边界矩形范围,QGraphicsView使⽤此来确定图元是否需要重绘 paint()实现图元的绘制操作,⼀种⽅法是直接在paint中对图元进⾏绘制。
另⼀种⽅法可以通过shape返回QPainterPath,然后在paint中依据QPainterPath进⾏绘制 该⽰例实现了随机的10中颜⾊图元,boundRect()为QRectF(-15,-15,30,30),图元的中⼼坐标为(0,0)(1)⾃定义随机颜⾊m_pColor(qrand() % 256, qrand() % 256, qrand() % 256)(2)图元边界矩形设置QRectF ColorItem::boundingRect() const{return QRectF(-15,-15,30,30);}(3)图元绘制void ColorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){painter->setBrush(m_pColor);painter->drawEllipse(boundingRect());}(4)光标设置 当⿏标进⼊图元或是拖动图元时设置光标形状,光标形状查看枚举类型:CursorShapesetCursor(Qt::OpenHandCursor);setAcceptedMouseButtons(Qt::LeftButton);(5)设置ToolTip 当⿏标进⼊图元时显⽰提⽰内容:setToolTip(QString("QColor(%1,%2,%3)\n%4").arg(m_pColor.red()).arg(m_pColor.green()).arg(m_pColor.blue()).arg("Click and drag this color onto the robot!"));⼆、机器⼈头像图元类实现 颜⾊图元的实现中已经了解了基本实现⽅法,机器⼈图元的实现也不例外,由于机器⼈包括很多图元部分(头、⾝体等),我们可以采⽤⾯对对象继承的⽅式来实现。
GraphicsView框架简介
QT中Graphics View柜架是本文要介绍的内容,本文分为三部分为大家介绍,本篇文章为上篇,想要继续深入了解的请继续关注。
参考末尾。
先来看本节内容。
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查找函数都以出栈序列返回(也就是说,第一个返回的是最顶端的,最后一个返回的是最底端的)。
QT图形视图框架(The Graphics View Framework)
管理 widgets 在图形视图中的布局 在 QGraphicsScene 中所有图形对象的基 类 为 QGraphicsItem 提供简单的 动画支持 将多个图形对象组合成一个对象 图形视图中所有布局类的基类 允许布局类管理的自定义对象 直线对象,可以直接添加到 QGraphicsScene 管理 widgets 在图形视图中的的水平或者 垂直方向上的布局 所有需要处理信号 /槽 /属性的图形对象。 路径对象,可以直接添加到 QGraphicsScene 位图对象,可以直接添加到 QGraphicsScene 多边形对象,可以直接添加到 QGraphicsScene widget 代理,用于将一个 QWidget 对象嵌 入 一个 QGraphicsScene 中 矩形对象,可以直接添加到 QGraphicsScene 管理大量二维图形对象的管理器
• • • • •
鼠标按下、移动、释放和双击事件,同时还支持鼠标悬浮事件、滚轮事件和上下文菜单事件。 键盘输入焦点和键盘事件。 拖放。 组合:通过父对象 -子对象进行组合,或者通过 QGraphicsItemGroup 组合。 碰撞检测。
与 QGraphicsView 类似,处于局部坐标系下的图形对象,也提供了图形对象和场景之间的映射函数。 和 QGraphicsView 一样,图形对象同时还可以通过矩阵来变换其自身的坐标系统,这一点对于单个 图形对象的旋转和缩放非常有用。 图形视图架构 个图形对象可以包含其他对象(子对象)。父对象的变换矩阵同样也会应用到子对象上。但是,不管一 个对象累积了多少变换, QGraphicsItem::collidesWith()仍然会在局部坐标系下进行计算。
图形视图框架
The Graphics View Framework
Qt学习笔记图形视图框架
Qt学习笔记--图形视图框架(一)2010-07-11 07:40优点:处理多个图元,单击,拖动,选择图元架构:一个场景,多个图元位于其中,通过视图显示主要应用: 绘图软件,显示地图软件当使用没有变换的视图观察场景时,场景中的一个单元对应屏幕上的一个像素图元坐标通常以图元中心为原点,X轴正方向为向右,Y轴正方向为向下场景坐标的原点在场景中心,X轴正方向为向右,Y轴正方向为向下视图坐标以左上角为原点,X轴正方向为向右,Y轴正方向为向下所有的鼠标事件最开始都是使用视图坐标场景:图元的容器1.提供管理很多图元的接口2.传播事件到图元中3.管理图元状态,例如选择和焦点处理4.提供非转换的绘制功能,主要用于打印QGraphicsScene scene;QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100)); // 添加图元QGraphicsItem *item = scene.itemAt(50, 50); // 查询图元// item == rect;通过QGraphicsScene::setSelectionArea()可以选择场景的任一个图元,QGraphicsScene::setSelectedItems()返回被选择的图元设置焦点图元QGraphicsScene::setFocusItem(), setFocus(), QGraphicsScene::focusItem(), 返回焦点图元视图:一个可视的子部件,可视化场景的内容多个视图可以显示同一个场景坐标转换:QGraphicsView::mapToScene(), QGraphicsView::mapFromScene()图元:支持鼠标事件,滚轮事件,上下文菜单事件支持键盘输入焦点,按键事件支持拖放支持分组冲突探测提供坐标转换,图元与场景,图元与图元之间利用QGraphicsItem::shape()和QGraphicsItem::collidesWith()实现冲突探测,这2个函数都是虚函数相关类:QGraphicsScene, QGraphicsItem, QGraphicsViewQGraphicsItem子类:QGraphicsEllipseItem provides an ellipse itemQGraphicsLineItem provides a line itemQGraphicsPathItem provides an arbitrary path item QGraphicsPixmapItem provides a pixmap itemQGraphicsPolygonItem provides a polygon itemQGraphicsRectItem provides a rectangular item QGraphicsSimpleTextItem provides a simple text label itemQGraphicsTextItem provides an advanced text browser item QGraphicsSvgItem provides a SVG file itemQGraphicsScene:拥有多个图元,包含三层:背景层,图元层,前景层背景层和前景层可以使用QBrush绘制,也可以使用drawBackground(),drawForeground()实现如果使用图片作为背景,可以用texture QBrush(pixmap)实现前景层brush可以使用半透明的白色实现褪色效果,或者使用交叉模式实现网格重叠场景可以告诉我们,哪些图元发生冲突,哪些图元被选择,哪些图元位于一个特定的点或者区域每个图元可以是:1.顶级图元,场景是它的父亲;2.孩子,它的父亲是另一个图元,任何作用于父图元的转换都将自动应用于它的孩子2种分组方式:1.一个图元成为另一个图元的孩子;2.使用QGraphicsItemGroup。
Qt的Graphics-View框架和OpenGL结合详解
Qt的Graphics-View框架和OpenGL结合详解Qt的Graphics-View框架和OpenGL结合详解演⽰程序下载地址:程序源代码下载地址:这是⼀篇纯技术⽂,介绍了这⼀个⽉来我抽时间研究的成果。
Qt中有⼀个⾮常炫的例⼦:Boxes,它展⽰了Qt能够让其Graphics–View框架和Qt的OpenGL模块结合起来,渲染出⾮常出⾊的效果。
其实我私⾃认为凭这个程序,已经有很多游戏开发者关注Qt了,因为游戏开发⼀个⾮常常见的模块就是UI,⼀般情况下游戏引擎提供的UI模块⽐较弱,基本上都是游戏引擎+第三⽅GUI库进⾏结合的。
但是Qt以其Graphics–View框架能够⾮常轻松地将UI控件嵌⼊场景中,⽽且能够和OpenGL底层共存,更重要的是,凭借着Qt的qss,Qt可以定制许多GUI元素,这是⾮常具有吸引⼒的。
所以说,如果⼤家对游戏开发感兴趣,那么不妨看⼀下Qt。
好了,下⾯介绍⼀下前⼏天我制作并发布的⼀个demo。
这个demo是对Boxes这个例⼦进⾏模仿,结合学习《OpenGL超级宝典》,制作⽽成的,由于最近⽐较忙,所以总共花了将近⼀个⽉才完成,不得不说效率有点⼉低。
⾸先从MainWindow.cpp这个⽂件说起吧,⼀开始是要初始化MainWindow类的,这个类是继承QMainWindow的,这⾥重点说说它的构造函数:MainWindow::MainWindow(QWidget*pParent):QMainWindow(pParent){QGLWidget*pWidget=new QGLWidget(QGLFormat(QGL::SampleBuffers),this);pWidget->makeCurrent();//scene的内容GraphicsScene*pScene=new GraphicsScene(this);OpenGLView*pView=new OpenGLView(this);pView->setViewport(pWidget);pView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);pView->setScene(pScene);//选择不同的着⾊器的时候进⾏着⾊器连接connect(pScene,SIGNAL(SwitchShader(const QString&)),pView,SLOT(SwitchShader(const QString&)));connect(pScene,SIGNAL(SetLightPos(const QVector3D&)),pView,SLOT(SetLightPos(const QVector3D&)));setCentralWidget(pView);setWindowTitle(tr("Lightforshader"));resize(640,360);}⾸先在我们创建了⼀个QWidget,然后调⽤makeCurrent()成员函数,其实意思是让它的rendercontext设为当前的rendercontext。
QT开始学习图形视图框架(TheQGraphicsViewFramework)
QT开始学习图形视图框架(TheQGraphicsViewFramework)图形视图提供了一个外表(surface)来实现大量的客户所做的2D图形项的管理和相互的结合;一个视图窗口部件来使这些项可视化,并支持缩放和旋转。
该框架包括一个事件传播体系,可以使得场景中的项的交叉可以达到双精度的精确控制。
其中的项可以处理事件、鼠标按压、移动、释放和双击事件,它们也可以追踪鼠标的移动。
图形视图使用一个BSP(二进制空间分区Binary Space Partitioning)树来提供快速的项发现,正因为如此,它可以使巨大的场景实时地可视化,即便它有上百万个项(item)。
图形视图是在Qt4.2中引入的,取代了以前的QCanvas,如果需要从QCanvas移植,参见“Porting to Graphics View”主题:l 图形视图的体系架构场景(Scene)视图(View)项(Item)l 图形视图的坐标系统项坐标场景坐标视图坐标坐标映射l 主要的特性缩放和旋转打印拖放光标和提示动画OpenGL展示项的成组窗口部件和布局嵌入式窗口部件支持图形视图体系架构图形视图提供了基于项的模型—视图编程方式,很象交互视图(InterView)的方便的类如QTableWidget,QTreeWidget,QListWidget。
多个视图可以用来观察一个场景,场景包含了变化的几何形状的项。
场景(Scene)QGraphicsScene提供了图形视图的场景,场景承担下列的责任:提供一个快速的接口用来管理大量的项。
向每个项传递事件。
管理项的状态,如选中、焦点处理。
提供无变形的展示功能,主要为了打印。
场景作为QGraphicsItem对象的容器,项可以调用QGraphicsScene::addItem()加入场景。
QGraphicsScene::items()和它的重载可以返回所有的项,包括点、长方形、多边形、通用矢量路径。
QGraphicsScene::itemAt()返回在特定点上最上边的项。
明王讲的 qt开发笔记 大纲
明王是一名具有丰富经验的qt开发工程师,他有着多年的qt开发实战经验,曾参与多个大型项目的开发,积累了大量的qt开发经验和技巧。
在这篇文章中,我将根据明王的讲课内容,为大家整理出一份qt 开发笔记大纲,希望能够帮助那些正在学习qt开发的朋友们更好地系统地学习和掌握qt开发的知识。
一、qt开发环境的搭建1. 安装qt开发环境1.1 Windows评台下的qt安装1.2 Linux评台下的qt安装1.3 macOS评台下的qt安装2. qt开发工具的配置2.1 IDE的选择2.2 编译器的选择2.3 qt插件的安装二、qt基础知识1. qt的基本概念1.1 qt的特点1.2 qt的架构1.3 qt的应用范围2. qt的核心模块2.1 QtCore模块2.2 QtGui模块2.3 QtWidgets模块2.4 QtMultimedia模块2.5 QtNetwork模块2.6 QtSql模块2.7 QtWebKit模块2.8 其他模块介绍和应用场景分析三、qt UI设计与布局1. qt的UI设计工具1.1 Qt Designer介绍1.2 Qt Creator介绍2. qt的基本控件2.1 QLabel2.2 QPushButton2.3 QLineEdit2.4 QComboBox2.5 QCheckBox2.6 QRadioButton2.7 其他常用控件介绍3. qt的布局管理3.1 布局管理器的概念3.2 QHBoxLayout3.3 QVBoxLayout3.4 QGridLayout3.5 实际布局案例分析四、qt信号与槽机制1. 信号槽的基本概念1.1 信号和槽的作用1.2 信号槽的连接方式2. 信号槽的使用场景2.1 点击事件处理2.2 定时器事件处理2.3 自定义信号槽的应用2.4 多线程编程中的信号槽使用五、qt网络编程1. qt的网络模块介绍1.1 TCP编程1.2 UDP编程1.3 HTTP编程2. qt网络编程实例2.1 客户端/服务器模型的实现 2.2 文件传输应用案例2.3 网络数据采集与展示六、qt数据库编程1. qt的数据库模块介绍1.1 SQL数据库1.2 NoSQL数据库1.3 数据库连接方式2. qt数据库编程实例2.1 数据库的增删改查操作2.2 数据库事务处理2.3 数据库连接池的实现七、qt跨评台开发技巧1. 跨评台编译1.1 编写高度可移植的qt代码 1.2 跨评台兼容性测试1.3 跨评台发布与打包2. 跨评台开发注意事项2.1 界面效果的统一2.2 评台特定功能的处理2.3 跨评台性能优化策略八、qt性能调优与调试技巧1. qt性能调优工具介绍1.1 qt的性能监控工具1.2 qt的性能调优工具2. qt性能调优实践2.1 内存分析和优化2.2 界面渲染优化2.3 事件处理性能优化3. qt调试技巧3.1 调试工具的使用3.2 代码调试技巧3.3 内存泄露排查方法以上就是明王讲授的qt开发笔记大纲,希期对大家学习qt开发有所帮助。
图形视图框架
图形视图框架(The QGraphics View Framework)(转)图形视图提供了一个外表(surface)来实现大量的客户所做的2D图形项的管理和相互的结合;一个视图窗口部件来使这些项可视化,并支持缩放和旋转。
该框架包括一个事件传播体系,可以使得场景中的项的交叉可以达到双精度的精确控制。
其中的项可以处理事件、鼠标按压、移动、释放和双击事件,它们也可以追踪鼠标的移动。
图形视图使用一个BSP(二进制空间分区Binary Space Partitioning)树来提供快速的项发现,正因为如此,它可以使巨大的场景实时地可视化,即便它有上百万个项(item)。
图形视图是在Qt4.2中引入的,取代了以前的QCanvas,如果需要从QCanvas移植,参见“Porting to Graphics View”主题:●图形视图的体系架构✍场景(Scene)✍视图(View)✍项(Item)●图形视图的坐标系统✍项坐标✍场景坐标✍视图坐标✍坐标映射●主要的特性✍缩放和旋转✍打印✍拖放✍光标和提示✍动画✍OpenGL展示✍项的成组✍窗口部件和布局✍嵌入式窗口部件支持图形视图体系架构图形视图提供了基于项的模型—视图编程方式,很象交互视图(InterView)的方便的类如QTableWidget,QTreeWidget,QListWidget。
多个视图可以用来观察一个场景,场景包含了变化的几何形状的项。
场景(Scene)QGraphicsScene提供了图形视图的场景,场景承担下列的责任:✍提供一个快速的接口用来管理大量的项。
✍向每个项传递事件。
✍管理项的状态,如选中、焦点处理。
✍提供无变形的展示功能,主要为了打印。
场景作为QGraphicsItem对象的容器,项可以调用QGraphicsScene::addItem()加入场景。
QGraphicsScene::items()和它的重载可以返回所有的项,包括点、长方形、多边形、通用矢量路径。
第7章Qt5图形视图框架课件
7.2.1 飞舞的蝴蝶
在重画函数paint()中,首先判断当前已显示的图片是pix_up还是pix_down。 实现蝴蝶翅膀上下飞舞效果时,若当前显示的是pix_up图片,则重绘pix_down图 片,反之亦然。具体实现代码内容如下:
void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
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.1.3 GraphicsView的坐标系统
Graphics View框架提供了多种坐标变换函数,见表7.1。
Qt模型和视图
import QtQuick 2.2 import QtQml.Model 2.1 Rectangle{ ObjectModel{ id:itemModel Rectangle{height:30;width:80;color:”red”} Rectangle{height:30;width:80;color:”green”} Rectangle{height:30;width:80;color:”blue”} } ListView{ anchors.fill:parent model:itemModel} }
Qt模型和视图
组员:张 海 褚元凡 陆志恩
1.1 模型/视图架构简介
• 模型/视图架构中包含三个部分,模型(Model)、视图(View) 和委托(Delegate),其中模型用于提供数据,视图负责显示数 据,委托负责如何显示模型中的具体每一个数据。这种开发架构 将可视的数据模块化,从而让开发人员和设计人员能够分别控制 数据的不同层面。
1.2.3 DelegateModel
• DelegateModel类型封装了一个模型和用于显示这个模型的委托, 可以使用model属性指定模型,delegate属性指定委托 • 一般情况下并不需要使用DelegateModel。不过,如果需要将 QAbstractItemModel的子类作为模型使用的时候,使用 DelegateModel可以很方便的操作和访问modelIndex。另外, DelegateModel可以和Package一起,为多种视图提供委托,也可 以与DelegateModelGroup一起用于排序和过滤委托元素。
Qt图形视图框架一——QGraphicsItem
Qt图形视图框架⼀——QGraphicsItem⼀、概念介绍 之前最项⽬,⼀直在⽤2D绘图的QGraphics/view,由于今年肺炎疫情的影响⽆法出门,所以有时间把这块做⼀个总结。
在我们平时绘图中,如果我们在⼀块画布上绘制多个不规则图形并且还要监控每⼀个图形的⾏为(⽐如移动、叠加、碰撞、拖动、缩放、旋转等操作)时,我们就要⽤到Qt⾥的图形视图框架,QGraphicScene(场景)可以管理多个图形项QGraphicsItem(⽐如:QGraphicsRectItem(矩形的图形项,也就是图元)),QGraphicsView(视图)关联场景可以让场景中的所有图形项可视化,其次还提供了缩放和旋转,可以帮助⽂档中搜索Graphics View 关键字查阅。
⼆、简单应⽤⽰例 分别新建了⼀个场景,⼀个矩形图形项和⼀个视图,并将图形项添加到场景中,将视图与场景关联,最后显⽰视图就⾏了,场景是管理图形项的,所有的图形项必须添加到⼀个场景中,但是场景本⾝⽆法可视化,要想看到场景上的内容,必须使⽤视图,代码如下:#include <QtWidgets>#include <QApplication>int main(int argc,char* argv[ ]){QApplication app(argc,argv);// 场景QGraphicsScene *scene = new QGraphicsScene;// 矩形项QGraphicsRectItem *item =new QGraphicsRectItem(150,150,50,50);// 项添加到场景scene->addItem(item);// 视图QGraphicsView *view = new QGraphicsView;// 视图关联场景view->setScene(scene);// 显⽰视图view->show();return app.exec();}运⾏如下:三、图像项QGraphicsItem QGraphicsItem类是所有图形项的基类。
多年来开发QT累计的笔记
QT学习笔记-1.QT主要的对象说来惭愧学习c++很长时间了一直没有使用c++开发过软件界面所以现在想认认真真的学习一个c++图形界面框架库本来想学习Xwidget但是这个资料不大好找有啥问题不好解决那就学习QT吧不说QT的优缺点,不说如何编译QT从QT的主要库类开始吧知道了基本的对象之后如果需要学习看看文档就知道了如果需要编译QT的话再下个代码试着编译吧QApplication 应用程序类管理图形用户界面应用程序的控制流和主要设置QLabel 标签类提供文本或者图像的显示QPushButton 按钮类提供了命令按钮按钮的一种QButtonGroup 按钮组合类按钮组相关按钮的组合QGroupBox 群组类一个有标题的组合框QDateTimeEdit 日期时间编辑框类QLineEdit 行编辑框类单行文本编辑器QTextEdit 文本编辑框类单页面多信息编辑器对象QComboBox 组合框类QProgressBar 进度条类QLCDNumber 数字显示框类QScrollBar 滚动条类QSpinBox 微调框类QSlider 滑动条类QIconView 图标视图类QListView 列表视图类QListBox 列表框类QTable 表格类QValidator 有效性检查类QImage 图像类QMainWindow 主窗口类QPopupMenu 弹出性菜单类QMenuBar 菜单栏类QToolButton 工具按钮类QToolTip 提示类QWhatsThis 这是什么类QAction 动作类QHBoxLayout 水平布局类QVBoxLayout 垂直布局类QGridLayout 表格布局类QT对话框类QMessageBox 消息对话框类QProgressDialog 进度条对话框类QWizard 向导对话框类QFileDialog 文件对话框类QColorDialog 颜色对话框类QFontDialog 字体对话框类QPrintDialog 打印对话框类基本就这些对象了要系统学习QT 还需要看看QT的slot系统,QT库类接口等具体的学习就是看例子咯QT学习笔记-2.QT窗体布局和皮肤加载学习QT的一个原因是貌似QT做出来的界面比较绚丽我倒想看看能做出来啥样子的从QT窗体布局说起凡是窗体布局无非就是如何摆放的问题1.想当然如果摆放有2个方式一个是所见即所得,一个是使用布局管理器先说后者吧2.QT有好几种布局管理器无非就是啥子流式布局,格子布局等等从这个层级上说软件界面都是布局嵌套的3.布局和控件的关系一般是一个布局对应于一个控件容器(或者顶层控件)使用当前布局管理器加挂子控件(容器)即可然后给当前控件挂上布局管理器即可下面是一个简单的QT Layout的例子(从QT例子改的)1.class Dialog : public QDialog2.{3. Q_OBJECT4.public:5. Dialog();6.private:7. void createHorizontalGroupBox();8.9. enum {button_number = 4};10. QGroupBox *groupbox;11. QPushButton *buttons[button_number];12. QDialogButtonBox *buttonBox;13.};复制代码实现如下:1.#include <QtGui>2.3.#include "dialog.h"4.5.//! [0]6.Dialog::Dialog()7.{8. createHorizontalGroupBox();9.10. buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok11. | QDialogButtonBox::Cancel);12.13. connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));14. connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));15.16. QVBoxLayout *mainLayout = new QVBoxLayout;17. mainLayout->addWidget(groupbox);18. mainLayout->addWidget(buttonBox);19. setLayout(mainLayout);20.21. setWindowTitle(tr("LayoutTest"));22.}23.24.void Dialog::createHorizontalGroupBox()25.{26. groupbox = new QGroupBox(tr("Layout Test"));27. QHBoxLayout *layout = new QHBoxLayout;28.29. buttons[0] = new QPushButton(tr("Button1"));30. buttons[1] = new QPushButton(tr("Button2"));31. buttons[2] = new QPushButton(tr("Button3"));32. buttons[3] = new QPushButton(tr("Button4"));33.34. for(int i = 0;i<button_number;i++)35. layout->addWidget(buttons[i]);36. groupbox->setLayout(layout);37.}复制代码几个知识点:1.groupbox = new QGroupBox(tr("Layout Test"));Layout Test 是个文本这个无须解释那tr呢?查查资料知道是为了支持多语言先知道即可以后使用的话在具体查查吧2.QDialogButtonBox是个什么东西看看最终的程序界面吧原来是对话框的确认和取消按钮再看信号槽函数无非就是绑定按钮到操作函数connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));那accepted和accept函数有啥区别?看看文档accept函数的解释是:Hides the modal dialog and sets the result code to Accepted accpeted函数的解释是:This signal is emitted when the dialog has been accepted either在说说QT皮肤学习QT的主要目的就是想做做脸蛋好看好的软件界面那就试试看吧查到的QT有一个名叫QSS(CSS?)的文件可以原来换肤那就改改看吧#include <QApplication>#include <QFile>#include <QStyleFactory>#include <QTextStream>#include "dialog.h"void setSkin(QApplication* const app, QString const &skinFile);int main(int argc, char *argv[]){QApplication app(argc, argv);setSkin(&app ,"skin.qss");Dialog dialog;dialog.show();return app.exec();}void setSkin(QApplication* const app, QString const &skinFile){QFile qss(skinFile);qss.open(QFile::ReadOnly);app->setStyleSheet(qss.readAll());qss.close();}相应的QSS文件如下:QPushButton{color:red;background:url(setting.png)}这里把PushButton的文本颜色设置为红色同时把它的背景设置为图片stting.pngQT学习笔记-3.Codecs例子学习QT自带的例子Codecs是一篇关于保存和载入不同编码文本的例子其界面比较简单一个简单的单文档而已有2个主要的对象一个是MainWindow用于窗体主界面另外一个是PreviewForm用于显示编码格式列表1.其编码格式的获取部分代码如下:QMap<QString, QTextCodec *> codecMap;QRegExp iso8859RegExp("ISO[- ]8859-([0-9]+).*");foreach (int mib, QTextCodec::availableMibs()) {QTextCodec *codec = QTextCodec::codecForMib(mib);QString sortKey = codec->name().toUpper();int rank;if (sortKey.startsWith("UTF-8")) {rank = 1;} else if (sortKey.startsWith("UTF-16")) {rank = 2;} else if (iso8859RegExp.exactMatch(sortKey)) {if (iso8859RegExp.cap(1).size() == 1)rank = 3;elserank = 4;} else {rank = 5;}sortKey.prepend(QChar('0' + rank));codecMap.insert(sortKey, codec);}codecs = codecMap.values();通过使用foreach循环来获取支持的编码格式并保存不过看上去foreach (int mib, QTextCodec::availableMibs())有点奇怪查查资料解释是foreach(variables ,container)关键字是Qt对c++的一个扩展,主要用于按顺序历经容器(container)中的对象2关于文件菜单的生成和设置菜单的构造一个例子saveAsMenu = new QMenu(tr("&Save As"), this);这里有2个参数一个是菜单显示文另外一个是当前窗体指针然后就可以加载子菜单,设置分隔符,设置事件响应等操作了例子为:fileMenu = new QMenu(tr("&File"), this);fileMenu->addAction(openAct);fileMenu->addMenu(saveAsMenu);fileMenu->addSeparator();fileMenu->addAction(exitAct);那如何绑定菜单到当前窗体呢如下:menuBar()->addMenu(fileMenu);menuBar()->addSeparator();menuBar()->addMenu(helpMenu);menuBar()是QmainWindow的成员函数用于获取窗体菜单项指针3.QT对象QActionQT文档对QAction的解释是可以抽象用户接口对象-可以插入控件例子如下:openAct = new QAction(tr("&Open"), this);openAct->setShortcuts(QKeySequence::Open);connect(openAct, SIGNAL(triggered()), this, SLOT(open()));无非就是对象声明,设置快捷键,链接函数和响应而已4.窗体设置setWindowTitle(tr("Codecs"));resize(500, 400);5.消息对话框QMessageBox::about(this, tr("About Codecs"),tr("The <b>Codecs</b> example demonstrates how to read and write " "files using various encodings."));QT学习笔记-4.信号与插槽本文主要是对C++ GUI Programming with Qt4一书 Signals and Slots in Depth 部分的翻译信号与插槽机制是Qt编程的基础.它可以绑定对象而不需要对象之间彼此了解。
Qt2D绘图之六:图形视图框架的事件处理与传播
Qt2D 绘图之六:图形视图框架的事件处理与传播⼀、简介⽽对于键盘事件,它会传递给获得焦点的图形项,可以使⽤QGraphicsScene 类的setFocusItem()函数或者图形项⾃⾝调⽤setFocus()函数来设置焦点图形项。
默认的,如果场景没有获得焦点,那么所有的键盘事件都会被丢弃。
场景中的图形项获得了焦点,场景也会⾃动获得焦点。
图形视图框架中的事件都是⾸先由视图进⾏接收,然后传递给场景,再由场景传递给相应的图形项。
对于⿏标悬停效果,QGraphicsScene 会调度悬停事件。
图形项默认是⽆法接收悬停事件的,可 以使⽤QGraphicsItem 类的setAcceptHoverEvents()函数使图形项可以接收悬停事件。
如果⼀个图形项可以接收悬停事件,那么当⿏标进⼊它的区域之中时,它就会收到⼀个GraphicsSceneHoverEnter 事件。
如果⿏标继续在图形项的区域之中进⾏移动,那么QGraphicsScene 就会向该图形项发送GraphicsSceneHoverMove 事件。
当⿏标离开图形项的区域时,它将会收到⼀个GraphicsSceneHoverLeave 事件。
所有的⿏标事件都会传递到当前⿏标抓取的图形项,⼀个图形项如果可以接收⿏标事件(默认可以)⽽且⿏标在它的上⾯被按下,那么它就会成为场景的⿏标抓取的图形项。
⼆、实例下⾯来看⼀个例⼦。
新建空的Qt 项⽬,名称为myView 。
完成后myitem.h ⽂件内容如下:完成后先向本项⽬中添加⼀个Myltem ⾃定 义图形项,然后在myitem.h ⽂件中声明boundingRect()和paint()两个纯虚函数,再声明并定义⼀个公共的⽤于设置图形项填充⾊的函数和变量,最后添加⼀些事件处理函数的声明,#ifndef MYITEM_H#define MYITEM_H#include <QGraphicsItem>class MyItem : public QGraphicsItem{public:MyItem();//返回要绘制图形项的矩形区域 QRectF boundingRect() const;//⽤来执⾏实际的绘图操作 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget);//⽤来设置图形项填充⾊void setColor(const QColor &color) { brushColor = color; }protected: //⿏标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观 void mousePressEvent(QGraphicsSceneMouseEvent *event);//键盘按下事件处理函数,判断是否是向下⽅向键,如果是,则向下移动图形项 void keyPressEvent(QKeyEvent *event);//悬停事件处理函数,设置光标外观和提⽰void hoverEnterEvent(QGraphicsSceneHoverEvent *event);//右键菜单事件处理函数,为图形项添加⼀个右键菜单void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);private:QColor brushColor; //画刷颜⾊};#endif // MYITEM_H使⽤了变量作为画刷的颜⾊,就可以动态指定图形项的填充⾊了,默认情况下图形项的填充⾊设置为红⾊。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Qt学习笔记--图形视图框架(一)2010-07-11 07:40优点:处理多个图元,单击,拖动,选择图元架构:一个场景,多个图元位于其中,通过视图显示主要应用: 绘图软件,显示地图软件当使用没有变换的视图观察场景时,场景中的一个单元对应屏幕上的一个像素图元坐标通常以图元中心为原点,X轴正方向为向右,Y轴正方向为向下场景坐标的原点在场景中心,X轴正方向为向右,Y轴正方向为向下视图坐标以左上角为原点,X轴正方向为向右,Y轴正方向为向下所有的鼠标事件最开始都是使用视图坐标场景:图元的容器1.提供管理很多图元的接口2.传播事件到图元中3.管理图元状态,例如选择和焦点处理4.提供非转换的绘制功能,主要用于打印QGraphicsScene scene;QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100)); // 添加图元QGraphicsItem *item = scene.itemAt(50, 50); // 查询图元// item == rect;通过QGraphicsScene::setSelectionArea()可以选择场景的任一个图元,QGraphicsScene::setSelectedItems()返回被选择的图元设置焦点图元QGraphicsScene::setFocusItem(), setFocus(), QGraphicsScene::focusItem(), 返回焦点图元视图:一个可视的子部件,可视化场景的内容多个视图可以显示同一个场景坐标转换:QGraphicsView::mapToScene(), QGraphicsView::mapFromScene()图元:支持鼠标事件,滚轮事件,上下文菜单事件支持键盘输入焦点,按键事件支持拖放支持分组冲突探测提供坐标转换,图元与场景,图元与图元之间利用QGraphicsItem::shape()和QGraphicsItem::collidesWith()实现冲突探测,这2个函数都是虚函数相关类:QGraphicsScene, QGraphicsItem, QGraphicsViewQGraphicsItem子类:QGraphicsEllipseItem provides an ellipse itemQGraphicsLineItem provides a line itemQGraphicsPathItem provides an arbitrary path item QGraphicsPixmapItem provides a pixmap itemQGraphicsPolygonItem provides a polygon itemQGraphicsRectItem provides a rectangular item QGraphicsSimpleTextItem provides a simple text label itemQGraphicsTextItem provides an advanced text browser item QGraphicsSvgItem provides a SVG file itemQGraphicsScene:拥有多个图元,包含三层:背景层,图元层,前景层背景层和前景层可以使用QBrush绘制,也可以使用drawBackground(),drawForeground()实现如果使用图片作为背景,可以用texture QBrush(pixmap)实现前景层brush可以使用半透明的白色实现褪色效果,或者使用交叉模式实现网格重叠场景可以告诉我们,哪些图元发生冲突,哪些图元被选择,哪些图元位于一个特定的点或者区域每个图元可以是:1.顶级图元,场景是它的父亲;2.孩子,它的父亲是另一个图元,任何作用于父图元的转换都将自动应用于它的孩子2种分组方式:1.一个图元成为另一个图元的孩子;2.使用QGraphicsItemGroup。
使用分组,可以使位于同一个组的所有图元的操作都相同QGraphicsView:是一个Widget,用于显示一个场景,提供滚动条功能和转换功能,可以缩放和旋转场景。
默认使用内建的2D画图引擎,可以使用OpenGL:在构造后,调用setViewport()坐标系统:使用3种坐标系统:viewport, scene, itemviewport: 位于QGraphicsView内部scene: 逻辑坐标用于定位顶级图元item: 与图元相关,以图元的(0,0)为中心,移动图元时,它的坐标不会改变实践中,主要关注场景坐标(定位顶级图元)和图元坐标(定位子图元和绘制图元)在图元自己的坐标系统里面绘图意味着我们不用担心它在场景中的位置和应用于它的坐标转换Demo:// 主要特点:// 上下文菜单, 右键菜单// copy->paste方法//diagram.proTEMPLATE = appHEADERS = diagramwindow.h \link.h \node.h \propertiesdialog.hSOURCES = diagramwindow.cpp \link.cpp \main.cpp \node.cpp \propertiesdialog.cppFORMS = propertiesdialog.uiRESOURCES = resources.qrc//link.h#ifndef LINK_H#define LINK_H#include <QGraphicsLineItem>class Node;class Link : public QGraphicsLineItem // 如果使用信号和槽,采用多继承public QObject{public:Link(Node *fromNode, Node *toNode);~Link();Node *fromNode() const;Node *toNode() const;void setColor(const QColor &color);QColor color() const;void trackNodes(); // 节点移动时,跟踪节点private:Node *myFromNode; // 连线的2个节点Node *myToNode;};#endif//link.cpp#include <QtGui>#include "link.h"#include "node.h"Link::Link(Node *fromNode, Node *toNode){myFromNode = fromNode;myToNode = toNode;myFromNode->addLink(this); // 节点增加连线,每个节点有任意多个连线myToNode->addLink(this);setFlags(QGraphicsItem::ItemIsSelectable); // 连线可以被选择,然后删除setZValue(-1); // 在场景中显示的前后层次,因为连线是两个节点的中心,-1表示位于最后面,// 节点覆盖了部分连线setColor(Qt::darkRed); // 设置线的颜色trackNodes();}Link::~Link(){myFromNode->removeLink(this); // 删除连线时,将删除它在节点中的记录myToNode->removeLink(this);}Node *Link::fromNode() const{return myFromNode;}Node *Link::toNode() const{return myToNode;}void Link::setColor(const QColor &color){setPen(QPen(color, 1.0));}QColor Link::color() const{return pen().color();}void Link::trackNodes(){// pos()返回节点在场景中或者父图元中的位置setLine(QLineF(myFromNode->pos(), myToNode->pos()));}//node.h#ifndef NODE_H#define NODE_H#include <QApplication>#include <QColor>#include <QGraphicsItem>#include <QSet>class Link;class Node : public QGraphicsItem{Q_DECLARE_TR_FUNCTIONS(Node) // 在此类中增加tr()功能,直接使用,而不需要QObject::tr()了public:Node();~Node();void setText(const QString &text);QString text() const;void setTextColor(const QColor &color);QColor textColor() const;void setOutlineColor(const QColor &color);QColor outlineColor() const;void setBackgroundColor(const QColor &color);QColor backgroundColor() const;void addLink(Link *link);void removeLink(Link *link);QRectF boundingRect() const; // 重新实现,决定一个图元是否需要绘制,必须的QPainterPath shape() const; // 重新实现,返回图元的精确形状,// 决定一个点是否在图元内,或者2个图元是否发生冲突void paint(QPainter *painter, // 重新实现,画图,必须的const QStyleOptionGraphicsItem *option, QWidget *widget);protected:void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); // 双击事件,修改节点的文本QVariant itemChange(GraphicsItemChange change, // 重新实现,图元变化时,相关的连线发生变化const QVariant &value); // 没有使用mouseMoveEvent(),// 是因为程序可以改变节点位置private:QRectF outlineRect() const;int roundness(double size) const;QSet<Link *> myLinks;QString myText;QColor myTextColor;QColor myBackgroundColor;QColor myOutlineColor;};#endif//link.cpp#include <QtGui>#include "link.h"#include "node.h"Node::Node(){myTextColor = Qt::darkGreen;myOutlineColor = Qt::darkBlue;myBackgroundColor = Qt::white;setFlags(ItemIsMovable | ItemIsSelectable); // 节点可以移动,被选择}Node::~Node(){foreach (Link *link, myLinks) // 删除所有的连线,防止边界效应,不使用aDeleteAll()delete link;}void Node::setText(const QString &text){prepareGeometryChange(); // 改变节点内的文本时,矩形可能会发生变化myText = text;update();}QString Node::text() const{return myText;}void Node::setTextColor(const QColor &color){myTextColor = color;update();}QColor Node::textColor() const{return myTextColor;}void Node::setOutlineColor(const QColor &color){myOutlineColor = color;update();}QColor Node::outlineColor() const{return myOutlineColor;}void Node::setBackgroundColor(const QColor &color){myBackgroundColor = color;update();}QColor Node::backgroundColor() const{return myBackgroundColor;}void Node::addLink(Link *link){myLinks.insert(link); // 增加连线时,记录连线}void Node::removeLink(Link *link){myLinks.remove(link);}QRectF Node::boundingRect() const // View决定是否绘制矩形{const int Margin = 1;return outlineRect().adjusted(-Margin, -Margin, +Margin, +Margin); }QPainterPath Node::shape() const // View用于冲突探测{QRectF rect = outlineRect();QPainterPath path;path.addRoundRect(rect, roundness(rect.width()),roundness(rect.height()));return path;}// 绘制图元void Node::paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget * /* widget */){QPen pen(myOutlineColor);if (option->state & QStyle::State_Selected) { // 图元被选择pen.setStyle(Qt::DotLine);pen.setWidth(2);}painter->setPen(pen);painter->setBrush(myBackgroundColor);QRectF rect = outlineRect();painter->drawRoundRect(rect, roundness(rect.width()),roundness(rect.height()));painter->setPen(myTextColor);painter->drawText(rect, Qt::AlignCenter, myText);}// 双击节点,弹出标准输入对话框void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {QString text = QInputDialog::getText(event->widget(),tr("Edit Text"), tr("Enter new text:"),QLineEdit::Normal, myText);if (!text.isEmpty())setText(text);}// 拖动节点时,调用此函数QVariant Node::itemChange(GraphicsItemChange change,const QVariant &value){if (change == ItemPositionHasChanged) {foreach (Link *link, myLinks)link->trackNodes();}return QGraphicsItem::itemChange(change, value);}QRectF Node::outlineRect() const{const int Padding = 8;QFontMetricsF metrics = qApp->font();QRectF rect = metrics.boundingRect(myText); rect.adjust(-Padding, -Padding, +Padding, +Padding); rect.translate(-rect.center());return rect;}int Node::roundness(double size) const{const int Diameter = 12;return 100 * Diameter / int(size);}// diagramwindow.h#ifndef DIAGRAMWINDOW_H#define DIAGRAMWINDOW_H#include <QMainWindow>#include <QPair>class QAction;class QGraphicsItem;class QGraphicsScene;class QGraphicsView;class Link;class Node;class DiagramWindow : public QMainWindow{Q_OBJECTpublic:DiagramWindow();private slots:void addNode();void addLink();void del();void cut();void copy();void paste();void bringToFront();void sendToBack();void properties(); // 弹出属性设置对话框void updateActions(); // 更新菜单栏和工具栏的动作,哪些可用,哪些不可用private:typedef QPair<Node *, Node *> NodePair;void createActions();void createMenus();void createToolBars();void setZValue(int z);void setupNode(Node *node);Node *selectedNode() const;Link *selectedLink() const;NodePair selectedNodePair() const;QMenu *fileMenu;QMenu *editMenu;QToolBar *editToolBar;QAction *exitAction;QAction *addNodeAction;QAction *addLinkAction;QAction *deleteAction;QAction *cutAction;QAction *copyAction;QAction *pasteAction;QAction *bringToFrontAction;QAction *sendToBackAction;QAction *propertiesAction;QGraphicsScene *scene;QGraphicsView *view;int minZ; // sendToBack(), bringToFront()使用int maxZ;int seqNumber; // 唯一标示一个节点的文本};#endif//digramwindow.cpp#include <QtGui>#include "diagramwindow.h"#include "link.h"#include "node.h"#include "propertiesdialog.h"DiagramWindow::DiagramWindow(){scene = new QGraphicsScene(0, 0, 600, 500); // 创建场景,起始点为(0,0), 宽600,高500view = new QGraphicsView;view->setScene(scene); // 显示场景view->setDragMode(QGraphicsView::RubberBandDrag); // 选择多个节点方式:1.按ctrl;2.设置橡皮筋方式view->setRenderHints(QPainter::Antialiasing| QPainter::TextAntialiasing);view->setContextMenuPolicy(Qt::ActionsContextMenu); // 右键菜单setCentralWidget(view);minZ = 0;maxZ = 0;seqNumber = 0;createActions();createMenus();createToolBars();connect(scene, SIGNAL(selectionChanged()),this, SLOT(updateActions()));setWindowTitle(tr("Diagram"));updateActions();}// 增加一个节点void DiagramWindow::addNode(){Node *node = new Node;node->setText(tr("Node %1").arg(seqNumber + 1));setupNode(node);}void DiagramWindow::addLink(){NodePair nodes = selectedNodePair();if (nodes == NodePair())return;Link *link = new Link(nodes.first, nodes.second);scene->addItem(link);}// 删除选择的图元:首先删除连线,然后删除节点,以防止多次删除同一个连线void DiagramWindow::del(){QList<QGraphicsItem *> items = scene->selectedItems();QMutableListIterator<QGraphicsItem *> it(items);while (it.hasNext()) {Link *link = dynamic_cast<Link *>(it.next());if (link) {delete link;it.remove();}}qDeleteAll(items);}// 剪切操作:先复制,后删除void DiagramWindow::cut(){Node *node = selectedNode();if (!node)return;copy();delete node;}// 拷贝操作:值得研究!!!void DiagramWindow::copy(){Node *node = selectedNode();if (!node)return;QString str = QString("Node %1 %2 %3 %4").arg(node->textColor().name()).arg(node->outlineColor().name()).arg(node->backgroundColor().name()).arg(node->text());QApplication::clipboard()->setText(str);}void DiagramWindow::paste(){QString str = QApplication::clipboard()->text();QStringList parts = str.split(" ");if (parts.count() >= 5 && parts.first() == "Node") {Node *node = new Node;node->setText(QStringList(parts.mid(4)).join(" ")); // 连接字符串列表node->setTextColor(QColor(parts[1]));node->setOutlineColor(QColor(parts[2]));node->setBackgroundColor(QColor(parts[3]));setupNode(node);}}void DiagramWindow::bringToFront(){++maxZ;setZValue(maxZ); // 改变绘图顺序,首先绘制父图元,然后是子图元,根据子图元Z值的大小,// 值最小,最先绘制,值最大,最后绘制}void DiagramWindow::sendToBack(){--minZ;setZValue(minZ);}void DiagramWindow::properties(){Node *node = selectedNode();Link *link = selectedLink();if (node) {PropertiesDialog dialog(node, this);dialog.exec();} else if (link) {QColor color = QColorDialog::getColor(link->color(), this);if (color.isValid())link->setColor(color);}}// 更新动作使能void DiagramWindow::updateActions(){bool hasSelection = !scene->selectedItems().isEmpty();bool isNode = (selectedNode() != 0);bool isNodePair = (selectedNodePair() != NodePair());cutAction->setEnabled(isNode);copyAction->setEnabled(isNode);addLinkAction->setEnabled(isNodePair);deleteAction->setEnabled(hasSelection);bringToFrontAction->setEnabled(isNode);sendToBackAction->setEnabled(isNode);propertiesAction->setEnabled(isNode);foreach (QAction *action, view->actions())view->removeAction(action); // 删除右键菜单foreach (QAction *action, editMenu->actions()) {if (action->isEnabled())view->addAction(action); // 增加右键菜单}}void DiagramWindow::createActions(){exitAction = new QAction(tr("E&xit"), this);exitAction->setShortcut(tr("Ctrl+Q"));connect(exitAction, SIGNAL(triggered()), this, SLOT(close())); addNodeAction = new QAction(tr("Add &Node"), this); addNodeAction->setIcon(QIcon(":/images/node.png")); addNodeAction->setShortcut(tr("Ctrl+N"));connect(addNodeAction, SIGNAL(triggered()), this, SLOT(addNode()));addLinkAction = new QAction(tr("Add &Link"), this); addLinkAction->setIcon(QIcon(":/images/link.png")); addLinkAction->setShortcut(tr("Ctrl+L"));connect(addLinkAction, SIGNAL(triggered()), this, SLOT(addLink())); deleteAction = new QAction(tr("&Delete"), this);deleteAction->setIcon(QIcon(":/images/delete.png"));deleteAction->setShortcut(tr("Del"));connect(deleteAction, SIGNAL(triggered()), this, SLOT(del())); cutAction = new QAction(tr("Cu&t"), this);cutAction->setIcon(QIcon(":/images/cut.png"));cutAction->setShortcut(tr("Ctrl+X"));connect(cutAction, SIGNAL(triggered()), this, SLOT(cut())); copyAction = new QAction(tr("&Copy"), this);copyAction->setIcon(QIcon(":/images/copy.png"));copyAction->setShortcut(tr("Ctrl+C"));connect(copyAction, SIGNAL(triggered()), this, SLOT(copy())); pasteAction = new QAction(tr("&Paste"), this);pasteAction->setIcon(QIcon(":/images/paste.png"));pasteAction->setShortcut(tr("Ctrl+V"));connect(pasteAction, SIGNAL(triggered()), this, SLOT(paste())); bringToFrontAction = new QAction(tr("Bring to &Front"), this); bringToFrontAction->setIcon(QIcon(":/images/bringtofront.png")); connect(bringToFrontAction, SIGNAL(triggered()),this, SLOT(bringToFront()));sendToBackAction = new QAction(tr("&Send to Back"), this); sendToBackAction->setIcon(QIcon(":/images/sendtoback.png")); connect(sendToBackAction, SIGNAL(triggered()),this, SLOT(sendToBack()));propertiesAction = new QAction(tr("P&roperties..."), this);connect(propertiesAction, SIGNAL(triggered()),this, SLOT(properties()));}void DiagramWindow::createMenus(){fileMenu = menuBar()->addMenu(tr("&File"));fileMenu->addAction(exitAction);editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(addNodeAction);editMenu->addAction(addLinkAction);editMenu->addAction(deleteAction);editMenu->addSeparator();editMenu->addAction(cutAction);editMenu->addAction(copyAction);editMenu->addAction(pasteAction);editMenu->addSeparator();editMenu->addAction(bringToFrontAction); editMenu->addAction(sendToBackAction); editMenu->addSeparator();editMenu->addAction(propertiesAction);}void DiagramWindow::createToolBars(){editToolBar = addToolBar(tr("Edit"));editToolBar->addAction(addNodeAction); editToolBar->addAction(addLinkAction); editToolBar->addAction(deleteAction); editToolBar->addSeparator();editToolBar->addAction(cutAction);editToolBar->addAction(copyAction); editToolBar->addAction(pasteAction); editToolBar->addSeparator();editToolBar->addAction(bringToFrontAction); editToolBar->addAction(sendToBackAction);}void DiagramWindow::setZValue(int z){Node *node = selectedNode();if (node)node->setZValue(z);}void DiagramWindow::setupNode(Node *node) {node->setPos(QPoint(80 + (100 * (seqNumber % 5)), 80 + (50 * ((seqNumber / 5) % 7))));scene->addItem(node);++seqNumber;scene->clearSelection();node->setSelected(true);bringToFront();}// 返回一个选择的节点Node *DiagramWindow::selectedNode() const{QList<QGraphicsItem *> items = scene->selectedItems(); // 全部选择的节点if (items.count() == 1) {return dynamic_cast<Node *>(items.first());} else {return 0;}}Link *DiagramWindow::selectedLink() const{QList<QGraphicsItem *> items = scene->selectedItems();if (items.count() == 1) {return dynamic_cast<Link *>(items.first());} else {return 0;}}// 返回选择的节点对DiagramWindow::NodePair DiagramWindow::selectedNodePair() const{QList<QGraphicsItem *> items = scene->selectedItems();if (items.count() == 2) {Node *first = dynamic_cast<Node *>(items.first());Node *second = dynamic_cast<Node *>(st());if (first && second)return NodePair(first, second);}return NodePair();}// propertiesdialog.h#ifndef PROPERTIESDIALOG_H#define PROPERTIESDIALOG_H#include "ui_propertiesdialog.h"class Node;class PropertiesDialog : public QDialog, private Ui::PropertiesDialog {Q_OBJECTpublic:PropertiesDialog(Node *node, QWidget *parent = 0);private slots:void on_buttonBox_accepted(); // 快速信号连接void on_textColorButton_clicked();void on_outlineColorButton_clicked();void on_backgroundColorButton_clicked();private:void updateColorLabel(QLabel *label, const QColor &color);void chooseColor(QLabel *label, QColor *color);Node *node;QColor textColor;QColor outlineColor;QColor backgroundColor;};#endif//propertiesdialog.cpp#include <QtGui>#include "node.h"#include "propertiesdialog.h"PropertiesDialog::PropertiesDialog(Node *node, QWidget *parent) : QDialog(parent){setupUi(this);this->node = node;xSpinBox->setValue(int(node->x()));ySpinBox->setValue(int(node->y()));textLineEdit->setText(node->text());textColor = node->textColor();outlineColor = node->outlineColor();backgroundColor = node->backgroundColor(); updateColorLabel(outlineColorLabel, outlineColor); updateColorLabel(backgroundColorLabel, backgroundColor); updateColorLabel(textColorLabel, textColor);}void PropertiesDialog::on_buttonBox_accepted(){node->setPos(xSpinBox->value(), ySpinBox->value());node->setText(textLineEdit->text());node->setOutlineColor(outlineColor);node->setBackgroundColor(backgroundColor);node->setTextColor(textColor);node->update();QDialog::accept();}void PropertiesDialog::on_textColorButton_clicked(){chooseColor(textColorLabel, &textColor);}void PropertiesDialog::on_outlineColorButton_clicked(){chooseColor(outlineColorLabel, &outlineColor);}void PropertiesDialog::on_backgroundColorButton_clicked(){chooseColor(backgroundColorLabel, &backgroundColor);}void PropertiesDialog::updateColorLabel(QLabel *label,const QColor &color){QPixmap pixmap(16, 16);pixmap.fill(color);label->setPixmap(pixmap);}void PropertiesDialog::chooseColor(QLabel *label, QColor *color){QColor newColor = QColorDialog::getColor(*color, this); if (newColor.isValid()) {*color = newColor;updateColorLabel(label, *color);}}Qt学习笔记--图形视图框架(二)2010-07-11 07:41// demo: 城市地图// 主要特点:// 滚动和缩放: 鼠标滚动,放大或者缩小地图// 键盘操作: 上下左右,PageUp, PageDown// 自定义视图, 自定义图元// 显示注解// cityscape.h#ifndef CITYSCAPE_H#define CITYSCAPE_H#include <QMainWindow>class QGraphicsScene;class CityView;class Cityscape : public QMainWindow{Q_OBJECTpublic:Cityscape();private:void generateCityBlocks();QGraphicsScene *scene;CityView *view;};#endif// cityscape.cpp#include <QtGui>#include "annotation.h"#include "cityblock.h"#include "cityscape.h"#include "cityview.h"Cityscape::Cityscape(){scene = new QGraphicsScene(-22.25, -22.25, 1980, 1980); scene->setBackgroundBrush(QColor(255, 255, 238)); generateCityBlocks();view = new CityView;view->setScene(scene);setCentralWidget(view);setWindowTitle(tr("Cityscape"));}void Cityscape::generateCityBlocks(){QSet<QString> names;names << "Adams" << "Agnew" << "Arthur" << "Breckinridge" << "Buchanan" << "Burr" << "Bush" << "Calhoun" << "Carter" << "Cheney" << "Cleveland" << "Clinton" << "Colfax"<< "Coolidge" << "Curtis" << "Dallas" << "Dawes"<< "Eisenhower" << "Fairbanks" << "Fillmore" << "Ford"<< "Garfield" << "Garner" << "Gerry" << "Gore" << "Grant"<< "Hamlin" << "Harding" << "Harrison" << "Hayes"<< "Hendricks" << "Hobart" << "Hoover" << "Humphrey"<< "Jackson" << "Jefferson" << "Johnson" << "Kennedy"<< "King" << "Lincoln" << "Madison" << "Marshall"<< "McKinley" << "Mondale" << "Monroe" << "Morton"<< "Nixon" << "Pierce" << "Polk" << "Quayle" << "Reagan"<< "Rockefeller" << "Roosevelt" << "Sherman" << "Stevenson" << "Taft" << "Taylor" << "Tompkins" << "Truman" << "Tyler" << "Van Buren" << "Wallace" << "Washington" << "Wheeler" << "Wilson";QSetIterator<QString> i(names);for (int y = 0; y < 44; ++y) {for (int x = 0; x < 44; ++x) {int percentile;if (x > 20 && x < 24 && y > 20 && y < 24) { percentile = std::rand() % (std::rand() % 2 != 0? 10 : 100);} else if (x > 18 && x < 26 && y > 18 && y < 26) { percentile = std::rand() % (rand() % 3 != 0? 10 : 100);} else if (x > 15 && x < 29 && y > 15 && y < 29) { percentile = std::rand() % (std::rand() % 5 != 0? 10 : 100);} else {percentile = std::rand() % 100;}CityBlock::Kind kind;QString name;if (percentile == 0) {kind = CityBlock::Park;name = tr("%1 Park");} else if (percentile <= 2) {kind = CityBlock::SmallBuilding;} else if (percentile <= 4) {kind = CityBlock::Hospital;name = tr("%1 Hospital");} else if (percentile == 5) {kind = CityBlock::Hall;name = tr("%1 Hall");} else if (percentile <= 7) {kind = CityBlock::Building;name = tr("%1 Bldg");} else if (percentile <= 9) {kind = CityBlock::Tower;name = tr("%1 Tower");} else if (percentile <= 15) {kind = CityBlock::LShapedBlock;} else if (percentile <= 30) {kind = CityBlock::LShapedBlockPlusSmallBlock; } else if (percentile <= 70) {kind = CityBlock::TwoBlocks;} else {kind = CityBlock::BlockPlusTwoSmallBlocks;}CityBlock *block = new CityBlock(kind);block->setPos(QPointF(x * 44.5, y * 44.5));scene->addItem(block);if (!name.isEmpty()) {if (!i.hasNext())i.toFront();bool major = (std::rand() % 10 == 0);Annotation *annotation =new Annotation(name.arg(i.next()), major);annotation->setPos(block->pos());scene->addItem(annotation);}}}}// cityblock.h 自定义图元#define CITYBLOCK_H#include <QColor>#include <QGraphicsItem>#include <QPainterPath>class QGradient;class CityBlock : public QGraphicsItem{public:enum Kind { Park, SmallBuilding, Hospital, Hall, Building, Tower, LShapedBlock, LShapedBlockPlusSmallBlock, TwoBlocks, BlockPlusTwoSmallBlocks };CityBlock(Kind kind);QRectF boundingRect() const;void paint(QPainter *painter,const QStyleOptionGraphicsItem *option, QWidget *widget); private:int kind;QColor color;QPainterPath shape;};#endif// cityblock.cpp#include <QtGui>#include <cmath>#include "cityblock.h"CityBlock::CityBlock(Kind kind){this->kind = kind;int green = 96 + (std::rand() % 64);int red = 16 + green + (std::rand() % 64);int blue = 16 + (std::rand() % green);color = QColor(red, green, blue);if (kind == Park) {color = QColor(192 + (std::rand() % 32), 255,192 + (std::rand() % 16));shape.addRect(boundingRect());} else if (kind == SmallBuilding) {QRectF block(-7.5, -7.5, 15, 15);block.moveBottomLeft(QPointF((std::rand() % 6) - 3, (std::rand() % 6) - 3));shape.addRect(block);} else if (kind == Hospital) {int a = (std::rand() % 6) + 10;int b = (std::rand() % 6) + 10;QPolygonF block;block << QPointF(-5, -a) << QPointF(-5, -5) << QPointF(-10, -5) << QPointF(-10, 5) << QPointF(-5, 5) << QPointF(-5, 10)<< QPointF(5, 10) << QPointF(5, 5) << QPointF(b, 5)<< QPointF(b, -5) << QPointF(5, -5) << QPointF(5, -a); shape.addPolygon(block);} else if (kind == Hall) {int padding1 = (std::rand() % 8) + 2;int padding2 = (std::rand() % 8) + 2;shape.addEllipse(boundingRect().adjusted(+padding1, +padding1, -padding2, -padding2));} else if (kind == Building) {shape.addRect(boundingRect());。