原文地址:Graphics View Framework | Qt Widgets 6.5.2
Graphics View 图形视图提供了一个用于管理和与大量自定义 2D 图形项目交互的图面,以及一个用于可视化项目的视图小部件,并支持缩放和旋转。
该框架包括一个事件传播架构,允许对场景中的项目进行精准交互功能。可以处理关键事件、鼠标按下、移动、释放和双击事件,还可以跟踪鼠标移动。
图形视图使用BSP(二进制空间分区)树来提供非常快速的项目发现,因此,它可以实时可视化大型场景,即使有数百万个项目。
Graphics View在Qt 4.2中引入,取代了其前身QCanvas。
Graphics View提供了一种基于项目的模型视图编程方法。多个视图可以观察单个场景,并且该场景包含不同几何形状的项目。
QGraphicsScene 类提供了 Graphics View 场景. 他有如下职责:
场景充当QGraphicsItem对象的容器。通过调用 QGraphicsScene::addItem() 将项目添加到场景中,然后通过调用众多项目发现函数之一来检索项目。QGraphicsScene::items() 及其重载方法返所有图像项目,或者通过交互 点、矩形、多边形或通用向量路径返回所包含项。 QGraphicsScene::itemAt() 返回特定点上最顶层的项。所有项目发现功能都按降序返回项目(即,第一个返回的项目是最上面的,最后一个项目是最下面的)。
QGraphicsScene scene;
QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
QGraphicsItem *item = scene.itemAt(50, 50, QTransform());
QGraphicsScene的事件传播体系结构安排场景事件以传递到项目,还管理项目之间的传播。如果场景在某个位置接收到鼠标按下事件,则场景会将事件传递到该位置的任何项目。
QGraphicsScene还管理某些项目状态,例如项目选择和焦点。您可以通过调用 QGraphicsScene::setSelectionArea()来选择场景中的项目,参数是任意形状。此功能也用作QGraphicsView中选择的基础功能。要获取当前所有选定项目的列表,请调用 QGraphicsScene::selectedItems().。QGraphicsScene处理的另一个状态是项目是否具有键盘输入焦点。您可以通过调用QGraphicsScene::setFocusItem() or QGraphicsItem::setFocus(), 来设置项目的焦点,或者通过调用 QGraphicsScene::focusItem()来获取当前焦点项目。
最后,使用QGraphicsScene::render() 函数,可以将场景的部分渲染到绘制设备中。
QGraphicsView提供了视图小部件,它可以可视化场景的内容。可以将多个视图附着到同一场景,以便在同一数据集中提供多个视口。视图小部件是一个滚动区域,并提供滚动条用于在大型场景中导航。要启用OpenGL支持,可以通过调用QGraphicsView::setViewport()将QOpenGLWidget设置为视口。
视图接收来自键盘和鼠标的输入事件,并在将事件发送到可视化场景之前将这些事件转换为场景事件(在适当的情况下将使用的坐标转换为场景坐标)。
使用其变换矩阵 QGraphicsView::transform(),视图可以变换场景的坐标系。这允许高级导航功能,如缩放和旋转。为了方便起见,QGraphicsView还提供了在视图和场景坐标之间转换的功能: QGraphicsView::mapToScene() and QGraphicsView::mapFromScene().
QGraphicsScene scene;
myPopulateScene(&scene);
QGraphicsView view(&scene);
view.show();
QGraphicsItem是场景中图形项的基类。Graphics View 为典型的形状提供了几个典型使用项,如矩形(QGraphicsRectItem)、椭圆(QGraphicsIllipseItem)和文本项(QGraphicsTextItem),QGraphicsItem最强大的功能是可以写你自己的定制项目。
QGraphicsItem支持以下功能:
图形项目位于本地坐标系中,与QGraphicsView一样,它还提供了许多功能来映射项目和场景之间的坐标,以及从一个图形项目到另外项目的坐标。此外,与QGraphicsView一样,它可以使用矩阵转换坐标系: QGraphicsView::transform()。这对于旋转和缩放单个项目非常有用。
图形项目可以包含其他项目(子项目)。父项的转换由其所有子项继承。然而,不管一个图形项的累积转换如何,它的所有函数(例如 QGraphicsItem::contains(), QGraphicsItem::boundingRect(), QGraphicsItem::collidesWith())仍然在本地坐标中运行。
QGraphicsItem通过 QGraphicsItem::shape()函数和QGraphicsItem::collidesWith()函数支持碰撞检测,这两个函数都是虚拟函数。通过从 QGraphicsItem::shape()函数将返回本地坐标QPainterPath的图形项目,QGraphicsItem将为您处理所有碰撞检测。如果你想有自己的碰撞函数,你可以重写QGraphicsItem::collidesWith().
Graphics View基于笛卡尔坐标系;图形项目在场景中的位置和几何图形由两组数字表示:x坐标和y坐标。当使用未转换的视图观察场景时,场景中的一个单元由屏幕上的一个像素表示。
Graphics View中有三个有效的坐标系:图形项目坐标、场景坐标和视图坐标。为了简化实现,图形视图提供了方便的功能,允许您在三个坐标系之间进行映射。
渲染时,图形视图的场景坐标与QPainter的逻辑坐标相对应,视图坐标与设备坐标相同。在 Coordinate System 文档中,您可以了解逻辑坐标和设备坐标之间的关系。
图形项目位于自己的局部坐标系中。它们的坐标通常以其中心点 (0, 0)为中心,这也是所有变换的中心。项目坐标系中的几何基本图元通常被称为点、线或矩形。
创建自定义项目时,只需担心项目坐标;QGraphicsScene和QGraphicsView将为您执行所有转换。这使得实现自定义项变得非常容易。例如,如果收到鼠标按下或拖动输入事件,则事件位置以项目坐标表示。 QGraphicsItem::contains()是虚拟函数,如果某个点在项内,则返回true,否则返回false,它在项坐标中接受一个点参数。类似地,项目的边界矩形和形状位于项目坐标中。
图形项目的位置是项目的中心点在其父坐标系中的坐标;有时称为父坐标。从这个意义上讲,场景被视为所有无父项的“父项”。顶级项目的位置在场景坐标中。
子坐标是相对于父坐标的。如果子坐标未变换,则子坐标和父坐标之间的差与父坐标中项目之间的距离相同。例如:如果一个未转换的子项精确定位在其父项的中心点,那么这两个项的坐标系将是相同的。 如果子对象的位置是(10,0),则子对象的(0,10)点将与其父对象的(10,10)点相对应。
由于项的位置和变换是相对于父项的,因此子项的坐标不受父项变换的影响,尽管父项的变换隐式地变换子项。在上面的示例中,即使旋转和缩放父对象,子对象的(0,10)点仍将对应于父对象的(10,10)点。但是,相对于场景,子对象将跟随父对象的变换和位置。如果缩放父对象(2x,2x),则子对象的位置将位于场景坐标(20,0),其(10,0)点将对应于场景上的点(40,0)。
QGraphicsItem::pos()是为数不多的例外之一,QGraphicsItem的函数在项坐标中操作,而与项或其父项的任何转换无关。例如,项目的边界矩形(即 QGraphicsItem::boundingRect())总是以项目坐标给出。
场景表示其所有图形项目的基准坐标。场景坐标系描述了每个顶级父项目的位置,也构成了从视图传递到场景的所有场景事件的基础。场景中的每个项目都有一个场景位置和边界矩形 (QGraphicsItem::scenePos(), QGraphicsItem::sceneBoundingRect()),此外还有其本地项目位置和边界长方形。场景位置描述了项目在场景坐标中的位置,其场景边界矩形构成了QGraphicsScene如何确定场景中哪些区域已更改的基础。场景中的更改通过 QGraphicsScene::changed()信号进行通信,参数是场景矩形的列表。
视图坐标是小部件的坐标。视图坐标中的每个单位对应于一个像素。该坐标系的特殊之处在于,它相对于小部件或视口,不受观察到的场景的影响。QGraphicsView的视口的左上角始终为(0,0),右下角始终是(视口宽度、视口高度)。所有鼠标事件和拖放事件最初都作为视图坐标接收,您需要将这些坐标映射到场景才能与项目交互。
通常,在处理场景中的项目时,将坐标和任意形状从场景映射到项目、从项目映射到项目或从视图映射到场景是非常有用的。例如,当您在QGraphicsView的视口中单击鼠标时,可以通过调用QGraphicsView::mapToScene(),然后调用QGraphicsScene::itemAt来询问场景光标下有哪些的项目。如果您想知道项目在视口中的位置,可以对项目调QGraphicsItem::mapToScene,然后对视图调用QGraphicsView::mapFromScene()。最后,如果使用查找椭圆内的项,可以将QPainterPath传递到mapToScene(),然后将映射的路径传递到QGraphicsScene::items。
可以通过调用QGraphicsItem::mapToScene和QGraphicsItem::mapFromScene()来完成从坐标和形状的坐标映射转换 。还可以通过调用QGraphicsItem::mapToParent()和QGraphicsItem::mapFromParent()到父节点的坐标转换。所有映射函数都可以映射点、矩形、多边形和路径。
视图中提供了相同的映射函数,用于映射到场景和从场景映射。QGraphicsView::mapFromScene()和QGraphicsView::mapToScene()。若要从视图映射到项目,请先映射到场景,然后从场景映射到项目。
QGraphicsView支持通过QGraphicsView::setMatrix进行的仿射变换。通过对视图应用转换,可以轻松添加对缩放和旋转等常见导航功能的支持。
下面例子是如何在QGraphicsView的子类中实现缩放和旋转插槽的示例:
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按钮。
QGraphicsView在变换视图时保持视图中心对齐。
有关如何实现基本缩放功能的代码,请参阅Elastic Nodes示例。
Graphics View通过其渲染功能QGraphicsScene::render和 QGraphicsView::render 提供单行打印。这些函数提供相同的API:通过将QPainter传递到任一渲染函数,可以使场景或视图将其全部或部分内容渲染到任何绘制设备中。这个例子展示了如何使用QPrinter将整个场景打印成一整页。
QGraphicsScene scene;
QPrinter printer;
scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));
if (QPrintDialog(&printer).exec() == QDialog::Accepted) {
QPainter painter(&printer);
painter.setRenderHint(QPainter::Antialiasing);
scene.render(&painter);
}
场景和视图渲染函数的区别在于,一个在场景坐标中操作,另一个在视图坐标中操作。QGraphicsScene::render()通常更适合打印未转换的场景的整个片段,例如打印几何数据或打印文本文档。另一方面,QGraphicsView::render适用于截屏;其默认行为是使用提供的绘制器来渲染视口的确切内容。
QGraphicsScene scene;
scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));
QPixmap pixmap;
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
scene.render(&painter);
painter.end();
pixmap.save("scene.png");
当源区域和目标区域的大小不匹配时,将拉伸源内容以适应目标区域。通过将Qt::AspectRatioMode传递给正在使用的渲染函数,可以选择在拉伸内容时保持或忽略场景的纵横比。
因为QGraphicsView间接继承了QWidget,所以它已经提供了与QWidget相同的拖放功能。此外,为了方便起见,图形视图框架为场景以及每个项目提供了拖放支持。当视图接收到拖动时,它会将拖放事件转换为QGraphicsSceneDragDropEvent,然后将其转发到场景。场景接管此事件的日程安排,并将其发送到鼠标光标下接受放置的第一个项目。
要从项目开始拖动,请创建一个QDrag对象,将指针传递给启动拖动的小部件。多个视图可以同时观察项目,但只有一个视图可以开始拖动。在大多数情况下,拖动是由于按下或移动鼠标而启动的,因此在mousePressEvent()或mouseMoveEvent()中,您可以从事件中获取原始小部件指针。例如:
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QMimeData *data = new QMimeData;
QDrag *drag = new QDrag(event->widget());
drag->setMimeData(data);
drag->exec();
}
要拦截场景的拖放事件,请在QGraphicsItem子类中重新实现QGraphicsScene::dragEnterEvent(),再次方法下处理你所需的任何程序。您可以在QGraphicsScene的每个事件处理程序的文档中阅读有关图形视图中拖放的更多信息。
项可以通过调用QGraphicsItem::setAcceptDrops来启用拖放支持。要处理传入的拖动,请重新实现 QGraphicsItem::dragEnterEvent(), QGraphicsItem::dragMoveEvent(), QGraphicsItem::dragLeaveEvent(), and QGraphicsItem::dropEvent().
有关图形视图支持拖放操作的演示,请参见Drag and Drop Robot。
与QWidget一样,QGraphicsItem也支持游标(QGraphicsItem::setCursor)和工具提示(QGraphicsItem::setToolTip)。当鼠标光标进入项目区域时(通过调用QGraphicsItem::contains检测),QGraphicsView会激活光标和工具提示。
您也可以通过调用QGraphicsView::setCursor直接在视图上设置默认光标。
有关实现工具提示和光标形状处理的代码, 请参见Drag and Drop Robot。
图形视图支持多个级别的动画。使用“动画框架”可以轻松地组合动画。为此,您需要从QGraphicsObject继承您的项,并将QPropertyAnimation与它们相关联。QPropertyAnimation允许为任何QObject属性设置动画。
另一个选项是创建一个从QObject和QGraphicsItem继承的自定义项。该项目可以设置自己的计时器,并在QObject::timerEvent中使用增量步骤控制动画。
第三个选项主要用于与Qt 3中的QCanvas兼容,它是通过调用QGraphicsScene::advance来推进场景。
要启用OpenGL渲染,只需通过调用 QGraphicsView::setViewport将一个新的QOpenGLWidget设置为QGraphicsView的视口。如果希望OpenGL具有抗锯齿功能,则需要设置具有所需采样数的QSurfaceFormat(请参见QSurfaceFormat::setSamples)。
Example:
QGraphicsView view(&scene);
QOpenGLWidget *gl = new QOpenGLWidget();
QSurfaceFormat format;
format.setSamples(4);
gl->setFormat(format);
view.setViewport(gl);
通过使一个项成为另一个项的子项,可以实现项分组的最基本功能:项将一起移动,并且所有转换都从父项传播到子项。
此外,QGraphicsItemGroup是一个特殊的项,它将子事件处理与用于向组中添加项和从组中删除项的有用接口相结合。将一个项添加到QGraphicsItemGroup将保持该项的原始位置和转换,而通常对项进行重新排序将导致子项相对于其新父项重新定位。为了方便起见,可以通过调用QGraphicsScene::createItemGroup在场景中创建QGraphicsItemGroup。
Qt 4.4通过QGraphicsWidget引入了对几何图形和布局感知项的支持。这个特殊的基本项类似于QWidget,但与QWidget不同的是,它没有继承自QPaintDevice;而不是来自QGraphicsItem。这允许您编写包含事件、信号和插槽、大小提示和策略的完整小部件,还可以通过QGraphicsLinearLayout和QGraphicsGridLayout管理布局中的小部件几何图形
QGraphicsWidget基于QGraphicsItem的功能和精确计算占有区域,提供了两全其美的功能:从QWidget继承功能,如样式、字体、调色板、布局方向及其几何结构,以及QGraphicsItem的转换支持。因为Graphics View使用实坐标而不是整数,所以QGraphicsWidget的几何函数也对QRectF和QPointF进行操作。这也适用于框架矩形、边距和间距。例如,使用QGraphicsWidget,指定内容边距(0.5、0.5、0.5和0.5)并不罕见。您可以创建子窗口小部件和“顶级”窗口;在某些情况下,您现在可以将图形视图用于高级MDI应用程序。
支持QWidget的一些属性,包括窗口标志和属性,但不是全部。您应该参考QGraphicsWidget的类文档,以全面了解什么是支持的,什么是不支持的。例如,您可以通过将Qt::Window窗口标志传递给QGraphicsWidget的构造函数来创建装饰窗口。
QGraphicsLayout是专门为QGraphicsWidget设计的第二代布局框架的一部分。其API与QLayout的API非常相似。您可以在QGraphicsLinearLayout和QGraphicsGridLayout中管理小部件和子布局。您还可以通过自己对QGraphicsLayout进行子类化来轻松编写自己的布局,或者通过编写QGraphicsLayoutItem的适配器子类来将自己的QGraphicsItem项添加到布局中。
QAbstractGraphicsShapeItem |
Common base for all path items |
QGraphicsAnchor |
Represents an anchor between two items in a QGraphicsAnchorLayout |
QGraphicsAnchorLayout |
Layout where one can anchor widgets together in Graphics View |
QGraphicsEffect |
The base class for all graphics effects |
QGraphicsEllipseItem |
Ellipse item that you can add to a QGraphicsScene |
QGraphicsGridLayout |
Grid layout for managing widgets in Graphics View |
QGraphicsItem |
The base class for all graphical items in a QGraphicsScene |
QGraphicsItemGroup |
Container that treats a group of items as a single item |
QGraphicsLayout |
The base class for all layouts in Graphics View |
QGraphicsLayoutItem |
Can be inherited to allow your custom items to be managed by layouts |
QGraphicsLineItem |
Line item that you can add to a QGraphicsScene |
QGraphicsLinearLayout |
Horizontal or vertical layout for managing widgets in Graphics View |
QGraphicsObject |
Base class for all graphics items that require signals, slots and properties |
QGraphicsPathItem |
Path item that you can add to a QGraphicsScene |
QGraphicsPixmapItem |
Pixmap item that you can add to a QGraphicsScene |
QGraphicsPolygonItem |
Polygon item that you can add to a QGraphicsScene |
QGraphicsProxyWidget |
Proxy layer for embedding a QWidget in a QGraphicsScene |
QGraphicsRectItem |
Rectangle item that you can add to a QGraphicsScene |
QGraphicsScene |
Surface for managing a large number of 2D graphical items |
QGraphicsSceneContextMenuEvent |
Context menu events in the graphics view framework |
QGraphicsSceneDragDropEvent |
Events for drag and drop in the graphics view framework |
QGraphicsSceneEvent |
Base class for all graphics view related events |
QGraphicsSceneHelpEvent |
Events when a tooltip is requested |
QGraphicsSceneHoverEvent |
Hover events in the graphics view framework |
QGraphicsSceneMouseEvent |
Mouse events in the graphics view framework |
QGraphicsSceneMoveEvent |
Events for widget moving in the graphics view framework |
QGraphicsSceneResizeEvent |
Events for widget resizing in the graphics view framework |
QGraphicsSceneWheelEvent |
Wheel events in the graphics view framework |
QGraphicsSimpleTextItem |
Simple text path item that you can add to a QGraphicsScene |
QGraphicsSvgItem |
QGraphicsItem that can be used to render the contents of SVG files |
QGraphicsTextItem |
Text item that you can add to a QGraphicsScene to display formatted text |
QGraphicsTransform |
Abstract base class for building advanced transformations on QGraphicsItems |
QGraphicsView |
Widget for displaying the contents of a QGraphicsScene |
QGraphicsWidget |
The base class for all widget items in a QGraphicsScene |
QStyleOptionGraphicsItem |
Used to describe the parameters needed to draw a QGraphicsItem |