scene = QGraphicsScene()
scene.addText("Hello, world!")
# 等价于 QGraphicsView(scene)
view = QGraphicsView()
view.setScene(scene)
view.show()
您可以使用滚动条或调用 centerOn()
显式滚动到场景中的任何位置。通过将一个点传递给 centerOn()
,QGraphicsView 将滚动其视口以确保该点在视图中居中。同时提供了用于滚动到 QGraphicsItem 的重载,在这种情况下,QGraphicsView 将看到项目的中心在视图中居中。如果只需要确保某个区域可见(但不必居中),则可以调用 sureVisible()
。
QGraphicsView 可用于可视化整个场景或其中的一部分。默认情况下,第一次显示视图时,会自动检测到可视化区域(通过调用 itemsBoundingRect()
)。要自己设置可视化区域矩形,可以调用 setSceneRect()
。这将适当地调整滚动条的范围。请注意,尽管场景支持几乎不受限制的大小,但滚动条的范围永远不会超出整数 (INT_MIN, INT_MAX) 的范围。
QGraphicsScene 还管理某些图元项目状态,例如图元项目选择和焦点。您可以通过调用 setSelectionArea()
传递任意形状来选择场景中的项目。此函数还用作 QGraphicsView 中橡皮筋选择的基础。要获取所有当前选定项目的列表,请调用 selectedItems()
。 QGraphicsScene 处理的另一个状态是项目是否具有键盘输入焦点。您可以通过调用 setFocusItem()
或 setFocus()
来设置焦点,或者通过调用 focusItem()
来获取当前焦点。
QGraphicsView 通过调用 render()
可视化场景。默认情况下,使用常规 QPainter 并使用默认渲染提示将项目绘制到视口上。若要更改绘画项目时 QGraphicsView 传递给 QPainter 的默认渲染提示,可以调用setRenderHints()
。
默认情况下,QGraphicsView 为视口窗口小部件提供常规 QWidget。您可以通过调用 viewport()
来访问此小部件,也可以通过调用 setViewport()
来替换它。
要使用 OpenGL 进行渲染,只需调用 setViewport
(新的 QOpenGLWidget)。QGraphicsView
拥有视口小部件的所有权。
QGraphicsView 使用 QTransform 支持仿射变换。最常见的两种转换是 scaling
,用于实现缩放(zooming)和旋转(rotation)。QGraphicsView 在转换过程中保持视图中心不变。由于场景对齐(setAligment()
),平移视图将不会产生视觉影响。您可以将矩阵传递给 setTransform()
,也可以调用便捷函数之一 rotate()
,scale()
,translate()
或 shear()
。
您可以使用鼠标和键盘与场景中的项目进行交互。QGraphicsView 将鼠标和键事件转换为场景事件(继承 QGraphicsSceneEvent 的事件),并将其转发到可视化场景。最后,处理事件并对事件做出反应的是独立项目。例如,如果单击一个可选择的项目,则该项目通常会让场景知道它已被选中,并且它还将重绘自身以显示选择矩形。类似地,如果您单击并拖动鼠标以移动可移动项,则它是处理鼠标移动并自行移动的项。默认情况下,图形项目互动处于启用状态,您可以触发调用。
您还可以通过创建 QGraphicsView 的子类并重新实现鼠标和键事件处理程序来提供自己的自定义场景交互。
为了简化您如何以编程方式与视图中的项目进行交互,QGraphicsView 提供了映射函数 mapToScene()
和 mapFromScene()
以及项目访问器 items()
和 itemAt()
。这些功能允许您在视图坐标和场景坐标之间映射点,矩形,多边形和路径,并使用视图坐标在场景中查找项目。
QtWidgets.QGraphicsView(scene[, parent=None])
:
parent
:QWidget
scene
:QGraphicsScene
1.3 The Item
QGraphicsItem 是场景中图形项的基类。Graphics View 为典型形状提供了几个标准项,例如矩形(QGraphicsRectItem),椭圆(QGraphicsEllipseItem)和文本项(QGraphicsTextItem),但时,最强大的是 QGraphicsItem 可以编写自定义项。除此之外,QGraphicsItem 支持以下功能:
鼠标按下,移动,释放和双击事件,以及鼠标悬停事件,滚轮事件和上下文菜单事件。
键盘输入焦点和按键事件
通过 parent-child 关系以及 QGraphicsItemGroup 进行分组
碰撞检测(Collision detection)
图元项目位于本地坐标系(local coordinate system)中,就像 QGraphicsView 一样,它还提供了许多功能,用于在项目与场景之间以及项目与项目之间映射坐标。而且,像 QGraphicsView 一样,它可以使用 matrix:transform()
变换其坐标系。这对于旋转和缩放单个项目很有用。
项可以包含其他项(子项)。父项的转换由其所有子项继承。不过,不管某项的累积转换如何,它的所有功能(例如,contains()
, boundingRect()
, QGraphicsItem::collidesWith()
)都仍在本地坐标下运行。
QGraphicsItem 通过 shape()
函数和 QGraphicsItem::collidesWith()
这两个虚拟函数都支持冲突检测。通过从 shape()
返回项目的形状作为局部坐标 QPainterPath,QGraphicsItem 将为您处理所有碰撞检测。但是,如果要提供自己的冲突检测,则可以重新实现 QGraphicsItem::collidesWith()
。
更多内容见:QtWidgets.QGraphicsItem。
QtWidgets.QGraphicsItem
类是 QtWidgets.QGraphicsScene
中所有图形项的基类。为了方便描述,将 QtWidgets.QGraphicsItem
实例命名为图元。QtWidgets.QGraphicsItem
为编写您自己的自定义图元项提供了一个轻量级的基础。它包括定义图元项的几何形状(geometry),碰撞检测(collision detection),且有绘画实现以及通过事件处理程序进行的图元项交互。
为方便起见,Qt为最常见的形状提供了一组标准图形项:
QGraphicsEllipseItem
:提供 ellipse item
QGraphicsLineItem
:提供 line item
QGraphicsPathItem
:提供任意 path item
QGraphicsPixmapItem
:提供 pixmap item
QGraphicsPolygonItem
:提供 polygon item
QGraphicsRectItem
:提供 rectangular item
QGraphicsSimpleTextItem
:提供简单 text label item
QGraphicsTextItem
:提供高级 text browser item
图元项目的所有几何信息均基于其本地坐标系(Local Coordinate System)。该图元项的位置 pos()
是唯一在本地坐标中不起作用的函数,因为它在父坐标中返回一个位置。
您可以通过调用 setVisible()
设置图元项目是否应可见(即绘制和接受事件)。隐藏图元项目也会隐藏其子项。同样,您可以通过调用 setEnabled()
启用或禁用图元项目。
如果禁用某个图元项目,则其所有子项也将被禁用。默认情况下,图元项目既可见又启用。若要切换是否选择图元项目,请首先通过设置 ItemIsSelectable
标志启用选择,然后调用 setSelected()
。通常,由于用户交互,场景(scene)会切换选择。
要编写自定义的图元项目,首先创建 QGraphicsItem
的子类,然后实现其两个纯虚拟公共函数:boundingRect()
返回该图元项目所绘制区域的估计值,paint()
实现实际绘图(the actual painting)。例如:
class SimpleItem(QtWidgets.QGraphicsItem):
def boundingRect(self):
penWidth = 1.0
return QtCore.QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
20 + penWidth, 20 + penWidth)
def paint(self, painter, option, widget):
painter.drawRoundedRect(-10, -10, 20, 20, 5, 5)
boundingRect()
函数有许多不同的用途。QtWidgets.QGraphicsScene
的项目索引基于 boundingRect()
,并且 QtWidgets.QGraphicsView
将其用于剔除不可见的项目以及确定绘制重叠项目时需要重新组合的区域。此外,QtWidgets.QGraphicsItem
的碰撞检测机制使用 boundingRect()
提供有效的截止点(cut-off)。collidesWithItem()
中的细粒度碰撞算法基于调用 shape()
的方法,该方法会返回图元形状的精确轮廓作为QtGui.QPainterPath
。
QtWidgets.QGraphicsScene
期望所有图元项目的 boundingRect()
和 shape()
保持不变,除非得到通知。如果您想以任何方式更改图元的几何形状,则必须首先调用 prepareGeometryChange()
以允许 QtWidgets.QGraphicsScene
更新其簿记(bookkeeping)。
碰撞检测可以通过两种方式完成:
重新实现 shape()
以为您的图元返回准确的形状,并依靠 collidesWithItem()
的默认实现进行形状与形状的交点(shape-shape intersection)。如果形状复杂,这可能代价会非常高。
重新实现 collidesWithItem()
以提供您自己的自定义图元项目和形状碰撞算法。
可以调用 contains()
函数来确定图元项目是否包含一个点。该函数也可以通过图元项重新实现。contains()
的默认行为是基于调用 shape()
的。
图元项目可以包含其他图元项目,也可以被包含在其他图元项目中。所有图元项目都可以有一个父图元项目和一列子项目。除非该图元项目没有父对象,否则它的位置是父对象的坐标(即父对象的本地坐标)。父项将其位置及其变换传播给所有子项。
QtWidgets.QGraphicsItem
除了提供其基本位置 pos()
外,还支持投影变换(projective transformations)。有几种更改图元项目变换的方法。对于简单转换,可以调用便捷函数 setRotation()
或setScale()
,也可以将任何变换矩阵传递给 setTransform()
。对于高级转换控制,您还可以通过调用 setTransformations()
来设置多个组合转换。
图元项变换从父项到子项累积,因此,如果父项和子项都旋转 90 度,则子项的总转换将为 180 度。同样,如果项目的父项缩放到其原始大小的 2 倍(2x),则其子项也将扩大两倍。图元项的变形不会影响其自身的局部几何关系( local geometry);所有几何函数(例如,contains()
,update()
和所有映射函数)仍在局部坐标(local coordinates)下运行。为方便起见,QtWidgets.QGraphicsItem
提供了一个函数 SceneTransform()
(它返回该项的总变换矩阵(包括其位置以及所有父项的位置和变换))和 scenePos()
(该函数返回其在场景坐标中的位置)。 要重置图元的矩阵,请调用 resetTransform()
。
某些转换操作根据其应用顺序产生不同的结果。例如,如果缩放转换然后旋转,则可能会得到与首先旋转转换不同的结果。但是,您在 QtWidgets.QGraphicsItem
上设置转换属性的顺序不会影响最终的转换。QtWidgets.QGraphicsItem
始终以固定的定义顺序应用属性:
The item’s base transform is applied ( transform() )
The item’s transformations list is applied in order ( transformations() )
The item is rotated relative to its transform origin point ( rotation() , transformOriginPoint() )
The item is scaled relative to its transform origin point ( scale() , transformOriginPoint() )
QtWidgets.QGraphicsView
调用 paint()
函数来绘制图元项目的内容。该图元项目没有背景或没有默认填充值;该图元项目后面的任何内容都会在此功能中未明确绘制的所有区域中 shine。您可以调用 update()
安排重新绘制,可以选择传递需要重新绘制的矩形。根据图元项目是否在视图中可见,该项目可能会或可能不会重新粉刷(repaint)。QtWidgets.QGraphicsItem
中没有等效于 repaint()
的函数。
图元项目是按视图绘制的,从父项开始,然后是子项,按升序排列。您可以通过调用 setZValue()
设置图元的堆叠顺序,并通过调用 zValue()
对其进行测试,其中,在 z 值高的图元之前先绘制 z 值低的图元。堆叠顺序适用于同级图元;父项总是在子项前被绘制。
所有图元项目均按定义的稳定顺序绘制,并且此相同的顺序决定了当您单击场景时哪些项目将首先接收鼠标输入。通常,您不必担心排序,因为项目遵循“自然顺序”,遵循场景的逻辑结构。
某个图元项目的子项堆叠在父项的顶部,而同级项则按照插入顺序(即,它们被添加到场景或添加到同一父项的顺序)堆叠。如果您添加项目 A,然后添加 B,则 B 将位于 A 的顶部。如果您添加 C,则项目的堆叠顺序将是 A,然后是 B,然后是 C。
对于高级用户,有一些方法可以更改项目的排序方式:
您可以在一个图元项目上调用 setZValue()
,以将其显式堆叠在其他同级项目之上或之下。项的默认 Z 值为 0。具有相同 Z 值的项按插入顺序堆叠。
您可以调用 stackBefore()
重新排序子级列表。这将直接修改插入顺序。
您可以设置 ItemStacksBehindParent
标志以将子项堆叠在其父项之后。
两个同级图元的堆叠顺序也计入每个图元的子代图元和后代图元。因此,如果一项在另一项之上,则其所有子项也将在另一项所有子项之上。
QtWidgets.QGraphicsItem
通过虚拟函数 sceneEvent()
从 QtWidgets.QGraphicsScene
接收事件。此函数将最常见的事件分配给一组便捷事件处理程序:
contextMenuEvent()
handles context menu events
focusInEvent()
and focusOutEvent()
handle focus in and out events
hoverEnterEvent()
, hoverMoveEvent()
, and hoverLeaveEvent()
handles hover enter, move and leave events
inputMethodEvent()
handles input events, for accessibility support
keyPressEvent()
and keyReleaseEvent()
handle key press and release events
mousePressEvent()
, mouseMoveEvent()
, mouseReleaseEvent()
, and mouseDoubleClickEvent()
handles mouse press, move, release, click and doubleclick events
您可以通过安装事件过滤器(event filters)来过滤任何其他图元项目的事件。此功能与 Qt 的常规事件过滤器(请参阅 installEventFilter()
)分开,后者仅适用于 QObject 的子类。在通过调用 installSceneEventFilter()
将项目安装为另一个项目的事件过滤器之后,虚拟函数 sceneEventFilter()
会接收到过滤后的事件。您可以通过调用 removeSceneEventFilter()
来删除项目事件过滤器。
有时,将自定义数据注册到某个图元项目(自定义图元项目或标准图元项目)很有用。您可以在任何图元项目上调用 setData()
,以使用键值对(键为整数,并且值为 QVariant
)将数据存储在其中。要从项目中获取自定义数据,请调用 data()
。Qt 本身完全没有涉及此功能。
class QGraphicsItem([parent=None])
使用给定的父项构造一个 QtWidgets.QGraphicsItem
。它不会修改 parent()
返回的父对象。
如果 parent
是 None
,你可以通过调用 addItem()
将图元项目添加到场景中。该图元项目将成为顶级图元项目(top-level item)。
QtWidgets.QGraphicsItem.GraphicsItemFlag
:枚举描述了可以在图元项目上设置的不同标志,以切换图元项目行为中的不同功能。
QGraphicsItem.ItemIsMovable
该项目支持使用鼠标进行交互式移动。通过单击该项目然后拖动,该项目将与鼠标光标一起移动。如果该项目有孩子,则所有孩子也将移动。如果项目是选择的一部分,则所有选择的项目也会移动。通过 QtWidgets.QGraphicsItem
的鼠标事件处理程序的基本实现,可以方便地提供此功能。
QGraphicsItem.ItemIsSelectable
该项目支持选择。启用此功能将使 setSelected()
可以切换图元项目的选择。通过调用 setSelectionArea()
,单击某项或在 QtWidgets.QGraphicsView
中使用橡皮筋选择,它还将使该项自动被选择。
QGraphicsItem.ItemIsFocusable
该项目支持键盘输入焦点(即它是一个输入项目)。启用此标志将允许该项目接受焦点,这再次允许将键事件传递到 keyPressEvent()
和 keyReleaseEvent()
。
QGraphicsItem.ItemClipsToShape
图元会剪裁成自己的形状。该项目无法在其形状之外绘制或接收鼠标,平板电脑,拖放或悬停事件。默认情况下禁用。此行为由 drawItems()
或 drawItems()
强制执行。这个标志是在 Qt 4.3 中引入的。
QGraphicsItem.ItemClipsChildrenToShape
该项将其所有后代的绘画剪裁成自己的形状。此项的直接或间接子项不能超出该项目的形状。默认情况下,此标志为禁用状态。孩子们可以在任何地方画画。此行为由 drawItems()
或 drawItems()
强制执行。 这个标志是在 Qt 4.3 中引入的。
更多 flags 见:QGraphicsItem。
返回 QRectF
。这个纯虚函数将图元项目的外部边界定义为矩形;所有绘画都必须限制在图元项目的边界区域内。QtWidgets.QGraphicsView
使用它来确定该图元项目是否需要重绘。尽管图元项目的形状可以是任意的,但边界矩形始终为矩形,并且不受图元项目变换的影响。
如果要更改图元项目的边界矩形,必须首先调用 prepareGeometryChange()
。这会通知场景即将发生的更改,以便可以更新其图元项目几何索引;否则,场景将不会意识到该图元的新几何形状,并且结果是不确定的(通常,渲染工件( rendering artifacts)保留在视图(view)中)。
重新实现此功能,以使 QtWidgets.QGraphicsView
决定需要重绘窗口小部件的哪些部分(如果有)。注意:对于绘制轮廓/笔触的形状,重要的是在边界矩形中包括笔宽的一半。但是,没有必要补偿抗锯齿。
def boundingRect(self):
penWidth = 1.0
return QtCore.QRectF(-radius - penWidth / 2, -radius - penWidth / 2,
diameter + penWidth, diameter + penWidth)
更多精彩参考我的另一篇博文:Qt 手册。