QGraphicsScene类提供了一个用于管理大量2D图形项的表面。
该类充当QGraphicsItems的容器。它与QGraphicsView一起用于在2D表面上可视化图形项,如线条、矩形、文本,甚至自定义项。QGraphicsScene是图形视图框架的一部分。
QGraphicsScene还提供了一些功能,可以让您有效地确定项目的位置,并确定在场景的任意区域内哪些项目是可见的。使用QGraphicsView小部件,您可以可视化整个场景,也可以放大并仅查看场景的一部分。
该类继承自QObject,于Qt4.2版本引入
使用:#include
- 1
请注意,QGraphicsScene本身没有可视外观,它只管理item。您需要创建一个QGraphicsView小部件来可视化场景。
要向场景添加item,首先构造一个QGraphicsScene对象。然后,您有两个选项:通过调用addItem()添加现有的QGraphicsItem对象,或者可以调用方便函数addEllipse()、addLine()、addPath()、addPixmap()、addPolygon()、addRect()或addText(),它们都返回一个指向新添加项的指针。使用这些函数添加的项的尺寸相对于项的坐标系统,并且项的位置在场景中初始化为(0,0)。
然后,您可以使用QGraphicsView可视化场景。当场景发生变化时(例如,当item移动或转换时),QGraphicsScene发出changed()信号。要删除一个item,调用removeItem()。
QGraphicsScene使用索引算法来高效地管理item的位置。默认情况下,使用BSP(二进制空间分区)树;这是一种适用于大场景的算法,其中大多数item保持静态(即不移动)。您可以通过调用setItemIndexMethod()选择禁用此索引。有关可用的索引算法的更多信息,请参见itemIndexMethod属性。
通过调用setSceneRect()来设置场景的边界矩形。item可以放置在场景上的任何位置,默认情况下,场景的大小是无限的。场景矩形仅用于内部记账,维护场景的item索引。如果未设置场景矩形,QGraphicsScene将使用所有item的边界区域(由itemsBoundingRect()返回)作为场景矩形。然而,itemsBoundingRect()是一个相对耗时的函数,因为它通过收集场景上每个item的位置信息来操作。因此,在操作大场景时,您应始终设置场景矩形。
QGraphicsScene最大的优势之一是其能够高效地确定item的位置。即使场景上有数百万个item,items()函数也可以在几毫秒内确定item的位置。items()有几个重载版本:一个在特定位置找到item的函数,一个在多边形或矩形内或相交的函数等等。返回的item列表按堆叠顺序排序,最上面的item在列表中排在第一个。为了方便起见,还有一个itemAt()函数,它返回给定位置的最上面的item。
QGraphicsScene维护场景的选择信息。要选择item,请调用setSelectionArea(),要清除当前选择,请调用clearSelection()。调用selectedItems()以获取所有选中的item的列表。
事件处理和传播
QGraphicsScene的另一个职责是传播来自QGraphicsView的事件。要将事件发送到场景,需要构造一个继承QEvent的事件,然后使用(例如QApplication::sendEvent())发送它。Event()负责将事件分派给各个项目。一些常见事件由便利事件处理程序处理。例如,按键事件由keyPressEvent()处理,鼠标按键事件由mousePressEvent()处理。
将关键事件传递给焦点项。要设置焦点项,您可以调用setFocusItem(),传递一个接受焦点的项,或者项目本身可以调用QGraphicsItem::setFocus()。调用focusItem()来获取当前的焦点项。为了与小部件兼容,场景还维护自己的焦点信息。默认情况下,场景没有焦点,所有关键事件都被丢弃。如果调用setFocus(),或者场景上的一个项目获得焦点,则场景自动获得焦点。如果场景有焦点,hasFocus()将返回true,关键事件将被转发到焦点项(如果有的话)。如果场景失去焦点,(例如,有人调用clearFocus())当一个项目有焦点时,场景将保持它的项目焦点信息,一旦场景恢复焦点,它将确保最后一个焦点项目恢复焦点。
对于鼠标悬停效果,QGraphicsScene调度悬停事件。如果一个项目接受悬停事件(参见QGraphicsItem::acceptHoverEvents()),当鼠标进入其区域时,它将接收GraphicsSceneHoverEnter事件。当鼠标继续在项目区域内移动时,QGraphicsScene将向它发送GraphicsSceneHoverMove事件。当鼠标离开项目所在区域时,该项目将接收一个GraphicsSceneHoverLeave事件。
所有鼠标事件都传递给当前的鼠标抓取项。如果一个项目接受鼠标事件(参见QGraphicsItem::acceptedMouseButtons()),并且接收到鼠标按下,它就会成为场景的鼠标抓取器。在没有按下其他鼠标按钮时,它将保持鼠标抓取器状态,直到收到鼠标释放。您可以调用mouseGrabberItem()来确定当前正在抓取鼠标的项目。
示例:
QGraphicsScene scene;
scene.addText("Hello, world!");
QGraphicsView view(&scene);
view.show();
backgroundBrush: QBrush
该属性保存场景的背景画刷。
通过设置该属性,可以将场景的背景更改为不同的颜色、渐变或纹理。默认的背景画刷是Qt::NoBrush
。背景在物品之前(背后)绘制。
示例:
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
// 一个蓝色的背景
scene.setBackgroundBrush(Qt::blue);
// 一个渐变背景
QRadialGradient gradient(0, 0, 10);
gradient.setSpread(QGradient::RepeatSpread);
scene.setBackgroundBrush(gradient);
QGraphicsScene::render() 调用 drawBackground() 来绘制场景的背景。为了更详细地控制背景的绘制,可以在 QGraphicsScene 的子类中重新实现 drawBackground()。
关联函数:
QBrush backgroundBrush() const
void setBackgroundBrush(const QBrush &brush)
bspTreeDepth: int
该属性保存 QGraphicsScene 的BSP索引树的深度。
当使用 NoIndex 时,该属性无效。
该值决定了 QGraphicsScene 的BSP树的深度。深度直接影响 QGraphicsScene 的性能和内存使用情况;后者随着树的深度呈指数增长。通过一个合理的树深度,QGraphicsScene 可以立即确定item的位置,即使对于包含数千个或数百万个item的场景。这也极大地提高了渲染性能。
默认值是0,此时 Qt 会根据场景中的item的大小、位置和数量猜测一个合理的默认深度。然而,如果这些参数经常变化,您可能会遇到减速,因为 QGraphicsScene 在内部重新调整深度。您可以通过设置该属性来避免潜在的减速。
树的深度和场景矩形的大小决定了场景划分的粒度。每个场景段的大小由以下算法确定:
QSizeF segmentSize = sceneRect().size() / pow(2, depth - 1);
当每个段包含0到10个item时,BSP树的大小最优。
关联函数:
int bspTreeDepth() const
void setBspTreeDepth(int depth)
font: QFont
该属性保存场景的默认字体。
该属性提供了场景的字体。场景字体默认为 QApplication::font 的值。
如果场景的字体发生变化,无论是通过 setFont() 直接还是通过应用程序字体的更改间接方式,QGraphicsScene 首先发送 FontChange 事件给自己,然后发送 FontChange 事件给场景中的所有顶级小部件项。这些项通过解析其自己的字体到场景中来做出响应,然后它们通知它们的子项,子项再通知它们的子项,以此类推,直到所有小部件项都更新了它们的字体。
如果更改了场景的字体(通过 setFont() 直接或通过 QApplication::setFont() 间接),将自动安排重新绘制整个场景。
关联函数:
QFont font() const
void setFont(const QFont &font)
foregroundBrush: QBrush
该属性保存场景的前景画刷。
更改该属性以将场景的前景设置为不同的颜色、渐变或纹理。
前景在物品之后(顶部)绘制。默认的前景画刷是Qt::NoBrush(即不绘制前景)。
示例:
QGraphicsScene scene;
QGraphicsView view(&scene);
view.show();
// 一个白色半透明的前景
scene.setForegroundBrush(QColor(255, 255, 255, 127));
// 一个网格前景
scene.setForegroundBrush(QBrush(Qt::lightGray, Qt::CrossPattern));
QGraphicsScene::render() 调用 drawForeground() 来绘制场景的前景。为了更详细地控制前景的绘制,可以在 QGraphicsScene 的子类中重新实现 drawForeground()。
关联函数:
QBrush
foregroundBrush() const
void
setForegroundBrush(const QBrush &brush)
itemIndexMethod: ItemIndexMethod
该属性保存物品索引方法。
QGraphicsScene 对场景应用索引算法,以加速物品的查找函数(如 items() 和 itemAt())。索引对于静态场景(即物品不会移动)最有效。对于动态场景或包含许多动画物品的场景,索引的维护可能会超过快速查找的效果。
对于常见情况,默认的索引方法 BspTreeIndex 可以很好地工作。如果您的场景使用了许多动画,并且遇到了性能问题,可以通过调用 setItemIndexMethod(NoIndex) 来禁用索引。
关联函数:
ItemIndexMethod
itemIndexMethod() const
void
setItemIndexMethod(ItemIndexMethod method)
minimumRenderSize: qreal
该属性存储了一个项目必须具备的最小视图转换尺寸,以便绘制。
当场景被渲染时,任何宽度或高度在目标视图中经过变换后小于minimumRenderSize()的项目将不会被渲染。如果一个项目没有被渲染,并且它裁剪了其子项目,它们也将不被渲染。将这个值设置为加快渲染具有许多对象的缩小视图的场景非常有用。
默认值为0。如果未设置或设置为0或负值,所有项目将始终被渲染。
例如,如果一个场景由多个视图渲染,其中一个视图作为总览视图,始终显示所有项目,那么设置此属性将特别有用。在具有许多项目的场景中,这样的视图将使用较高的缩放系数,以便显示所有项目。由于缩放,较小的项目只对最终渲染场景做出微不足道的贡献。为了避免绘制这些项目并减少渲染场景所需的时间,可以使用非负值调用setMinimumRenderSize()。
注意:作为太小而未绘制的项目仍然会被方法(如items()和itemAt())返回,并参与碰撞检测和交互。建议您将minimumRenderSize()设置为小于或等于1的值,以避免大型未渲染的交互式项目。
此属性在Qt 5.4中引入。
关联函数:
qreal minimumRenderSize() const
void setMinimumRenderSize(qreal minSize)
palette: QPalette
该属性存储了场景的默认调色板
此属性提供了场景的调色板。场景调色板默认为并且从QApplication::palette解析所有条目。
如果场景调色板发生更改,无论是通过setPalette()直接更改还是通过应用程序调色板更改间接更改,QGraphicsScene首先发送一个PaletteChange事件给自己,然后发送PaletteChange事件给场景中的所有顶级小部件项目。这些项目通过将自己的调色板解析到场景上来响应,然后通知它们的子项,它们又通知他们的子项,直到所有小部件项目都更新了它们的调色板。
更改场景调色板(直接或间接通过QApplication::setPalette())会自动安排重绘整个场景。
sceneRect: QRectF
该属性存储了场景矩形;场景的边界矩形
场景矩形定义了场景的范围。它主要由QGraphicsView用于确定视图的默认可滚动区域,并由QGraphicsScene用于管理项目索引。
如果未设置或设置为null QRectF,sceneRect()将返回自从创建场景以来场景上所有项目的最大边界矩形(即,当项目被添加到场景中或移动时,矩形会增长,但永远不会缩小)。
stickyFocus: bool
该属性指示是否在单击场景背景时清除焦点
在stickyFocus设置为true的QGraphicsScene中,当用户单击场景背景或不能接受焦点的项目时,焦点将保持不变。否则,焦点将被清除。
默认情况下,此属性为false。
焦点在响应鼠标按下时更改。您可以在QGraphicsScene的子类中重新实现mousePressEvent(),以根据用户的点击位置切换此属性。
QGraphicsItem *QGraphicsScene::activePanel() const
返回当前活动的面板,如果当前没有活动面板则返回0。
可参阅QGraphicsScene::setActivePanel()。
QGraphicsWidget *QGraphicsScene::activeWindow() const
返回当前活动的窗口,如果当前没有活动窗口则返回0。
可参阅QGraphicsScene::setActiveWindow()。
QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect,
const QPen &pen = QPen(), const QBrush &brush = QBrush())
创建并将椭圆项添加到场景中,并返回项指针。椭圆的几何形状由rect定义,其钢笔和画刷被初始化为pen和brush。
请注意,项的几何形状是在项坐标中提供的,其位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
可参阅addLine()
、addPath()
、addPixmap()
、addRect()
、addText()
、addItem()
和addWidget()
。
QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y,
qreal w, qreal h, const QPen &pen = QPen(), const QBrush &brush =
QBrush())
该便利函数等效于调用addEllipse(QRectF(x, y, w, h), pen, brush)。
void QGraphicsScene::addItem(QGraphicsItem *item)
将项及其所有子项添加或移动到此场景中。该场景接管该项。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
如果项已经在不同的场景中,它将首先从其旧的场景中移除,然后作为顶级项添加到此场景中。
在项添加到场景时,QGraphicsScene将向项发送ItemSceneChange通知。如果项当前不属于场景,只发送一次通知。如果它已经属于场景(即它被移动到此场景),QGraphicsScene将在项从其先前的场景中被移除时发送一个附加通知。
如果项是一个面板,场景是活动的,并且场景中没有活动的面板,则该项将被激活。
可参阅removeItem()、addEllipse()、addLine()、addPath()、addPixmap()、addRect()、addText()、addWidget()和排序。
QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const
QPen &pen = QPen())
创建并将线条项添加到场景中,并返回项指针。线条的几何形状由line定义,其钢笔被初始化为pen。
请注意,项的几何形状是在项坐标中提供的,其位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
可参阅addEllipse()、addPath()、addPixmap()、addRect()、addText()、addItem()和addWidget()。
QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal
x2, qreal y2, const QPen &pen = QPen())
该便利函数等效于调用addLine(QLineF(x1, y1, x2, y2), pen)。
QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path,
const QPen &pen = QPen(), const QBrush &brush = QBrush())
创建并将路径项添加到场景中,并返回项指针。路径的几何形状由path定义,其钢笔和画刷被初始化为pen和brush。
请注意,项的几何形状是在项坐标中提供的,其位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
可参阅addEllipse()、addLine()、addPixmap()、addRect()、addText()、addItem()和addWidget()。
QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
创建并将像素图项添加到场景中,并返回项指针。像素图由pixmap定义。
请注意,项的几何形状是在项坐标中提供的,其位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
可参阅addEllipse()、addLine()、addPath()、addRect()、addText()、addItem()和addWidget()。
QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF
&polygon, const QPen &pen = QPen(), const QBrush &brush = QBrush())
创建并将多边形项添加到场景中,并返回项指针。多边形由polygon定义,其钢笔和画刷被初始化为pen和brush。
请注意,项的几何形状是在项坐标中提供的,其位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
可参阅addEllipse()、addLine()、addPath()、addRect()、addText()、addItem()和addWidget()。
QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const
QPen &pen = QPen(), const QBrush &brush = QBrush())
创建并将矩形项添加到场景中,并返回项指针。矩形的几何形状由rect定义,其钢笔和画刷被初始化为pen和brush。
请注意,项的几何形状是在项坐标中提供的,其位置初始化为(0,0)。例如,如果添加一个QRect(50,50,100,100),它的左上角相对于项坐标系中的原点将为(50,50)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
可参阅addEllipse()、addLine()、addPixmap()、addPixmap()、addText()、addItem()和addWidget()。
QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w,
qreal h, const QPen &pen = QPen(), const QBrush &brush = QBrush())
该便利函数等效于调用addRect(QRectF(x, y, w, h), pen, brush)。
QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString
&text, const QFont &font = QFont())
创建并将QGraphicsSimpleTextItem添加到场景中,并返回项指针。文本字符串初始化为text,其字体初始化为font。
项的位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const
QFont &font = QFont())
创建并将文本项添加到场景中,并返回项指针。文本字符串初始化为text,其字体初始化为font。项的位置初始化为(0,0)。
如果项可见(即QGraphicsItem::isVisible()返回true),当控制返回事件循环时,QGraphicsScene将发出changed()信号。
QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags =
Qt::WindowFlags())
函数用于创建一个新的QGraphicsProxyWidget,并将其添加到场景中,然后返回指向代理的指针。wFlags参数设置嵌入的代理窗口的默认窗口标志。该项的位置初始化为(0,0)。
如果该项可见(即QGraphicsItem::isVisible()返回true),那么当控制返回到事件循环时,QGraphicsScene将会发出changed()信号。
请注意,不支持具有设置了Qt::WA_PaintOnScreen小部件属性和包装外部应用程序或控制器的小部件。例如QGLWidget和QAxWidget。
QList
QGraphicsScene::selectedItems() const
返回当前所有被选中项的列表。这些项按照特定顺序返回。
可参考setSelectionArea()。
QPainterPath QGraphicsScene::selectionArea() const
返回之前使用setSelectionArea()设置的选择区域,如果没有设置选择区域,则返回一个空的QPainterPath。
可参考setSelectionArea()
。
void advance()
推进函数,用于在场景中推进所有可推进的项。
void clear()
清除函数,用于清除场景中的所有项。
void clearSelection()
清除选择函数,用于清除场景中的所有选择项。
void invalidate(const QRectF &rect = QRectF(), SceneLayers layers =
AllLayers)
失效函数,用于标记指定区域的图形项为失效状态,并通知场景进行更新。
使场景中矩形rect所对应的图层失效,并安排重新绘制。所有图层中的缓存内容将被无条件地使无效并重新绘制。
您可以使用此函数重载来通知QGraphicsScene场景背景或前景的变化。当QGraphicsView启用CacheBackground时,此函数通常用于具有基于瓦片的背景的场景。
例如:
QRectF TileScene::rectForTile(int x, int y) const
{
// 返回位置(x, y)的瓦片的矩形
return QRectF(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
}
void TileScene::setTile(int x, int y, const QPixmap &pixmap)
{
// 使用pixmap设置或替换位置(x, y)的瓦片
if (x >= 0 && x < numTilesH && y >= 0 && y < numTilesV) {
tiles[y][x] = pixmap;
invalidate(rectForTile(x, y), BackgroundLayer);
}
}
void TileScene::drawBackground(QPainter *painter, const QRectF &exposed)
{
// 绘制与裸露区域相交的所有瓦片
for (int y = 0; y < numTilesV; ++y) {
for (int x = 0; x < numTilesH; ++x) {
QRectF rect = rectForTile(x, y);
if (exposed.intersects(rect))
painter->drawPixmap(rect.topLeft(), tiles[y][x]);
}
}
}
请注意,QGraphicsView目前仅支持背景缓存(请参见QGraphicsView::CacheBackground)。如果传递除了BackgroundLayer之外的任何图层,此函数等效于调用update()。
可参考QGraphicsView::resetCachedContent()。
void update(const QRectF &rect = QRectF())
更新函数,用于更新指定区域内的图形项。
void changed(const QList ®ion)
改变信号,当场景发生变化时触发,参数为发生变化的区域列表。
void focusItemChanged(QGraphicsItem *newFocusItem, QGraphicsItem
*oldFocusItem, Qt::FocusReason reason)
焦点项改变信号,当焦点项在场景中改变时触发,参数为新的焦点项、旧的焦点项和触发改变的原因。
void sceneRectChanged(const QRectF &rect)
场景矩形改变信号,当场景矩形发生变化时触发,参数为新的场景矩形。
void selectionChanged()
选择项改变信号,当选择项在场景中改变时触发。
[virtual protected] void
QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
这个事件处理程序可以在子类中重新实现,用于接收场景的拖拽进入事件。
默认实现接受该事件,并准备场景接受拖拽移动事件。
可参考QGraphicsItem::dragEnterEvent()
、dragMoveEvent()
、dragLeaveEvent()
和dropEvent()
。
[virtual protected] void
QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
这个事件处理程序可以在子类中重新实现,用于接收场景的拖拽离开事件。
[virtual protected] void
QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
这个事件处理程序可以在子类中重新实现,用于接收场景的拖拽移动事件。
注意:请参见items()以了解此函数认为哪些项是可见的。
[virtual protected] void QGraphicsScene::drawBackground(QPainter
*painter, const QRectF &rect)
使用painter绘制场景的背景,先于任何项和前景绘制之前。重新实现此函数可以为场景提供自定义的背景。
所有绘制都在场景坐标中进行。rect参数是裸露的矩形。
如果你只想为背景定义颜色、纹理或渐变,可以调用setBackgroundBrush()。
可参考drawForeground()
和drawItems()
。
[virtual protected] void QGraphicsScene::drawForeground(QPainter
*painter, const QRectF &rect)
使用painter绘制场景的前景,绘制完背景和所有项之后再进行。重新实现此函数可以为场景提供自定义的前景。
所有绘制都在场景坐标中进行。rect参数是裸露的矩形。
如果你只想为前景定义颜色、纹理或渐变,可以调用setForegroundBrush()。
[virtual protected] void
QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
这个事件处理程序可以在子类中重新实现,用于接收场景的拖拽放下事件。
[virtual protected] bool QGraphicsScene::event(QEvent *event)
从QObject::event()重新实现。
处理事件event,并将其分发给相应的事件处理程序。
除了调用方便的事件处理程序之外,该函数还负责将鼠标移动事件转换为悬停事件,当没有鼠标抓取器项时。悬停事件直接传递给项;没有专门的功能。
与QWidget不同,QGraphicsScene没有enterEvent()和leaveEvent()的便利函数。请使用此函数获取这些事件。
可参考contextMenuEvent()
、keyPressEvent()
、keyReleaseEvent()
、mousePressEvent()
、mouseMoveEvent()
、mouseReleaseEvent()
、mouseDoubleClickEvent()
、focusInEvent()
和focusOutEvent()
。
[virtual protected] bool QGraphicsScene::eventFilter(QObject *watched,
QEvent *event)
从QObject::eventFilter()重新实现。
QGraphicsScene过滤QApplication的事件以检测调色板和字体的更改。
[virtual protected] void QGraphicsScene::focusInEvent(QFocusEvent
*focusEvent)
这个事件处理程序可以在子类中重新实现,用于接收焦点进入事件。
默认实现在场景上设置焦点,然后在最后一个焦点项上设置焦点。
可参考QGraphicsItem::focusOutEvent()
。