Performance 如何优化基于QGraphicsView的应用程序的性能?
我有一个基于Qt图形视图框架的应用程序。Performance 如何优化基于QGraphicsView的应用程序的性能?,performance,qt,opengl,qt4,qgraphicsview,Performance,Qt,Opengl,Qt4,Qgraphicsview,我有一个基于Qt图形视图框架的应用程序。 这是一款拼图游戏,基本上是将一个pixmap切割成更小的pixmap(拼图块),并在QGraphicsView中将它们显示为QGraphicsItems。我希望此应用程序在智能手机和平板电脑上运行。(它已经在诺基亚N900和一些Symbian手机上运行。尚未针对Symbian ^3进行优化。) 消息来源是 这些项继承QGraphicsItem和QObject,并具有QGraphicsItem的pos()和rotation()的Q\u属性宏,以便使用Qt动
这是一款拼图游戏,基本上是将一个pixmap切割成更小的pixmap(拼图块),并在
QGraphicsView
中将它们显示为QGraphicsItem
s。我希望此应用程序在智能手机和平板电脑上运行。(它已经在诺基亚N900和一些Symbian手机上运行。尚未针对Symbian ^3进行优化。)消息来源是 这些项继承
QGraphicsItem
和QObject
,并具有QGraphicsItem
的pos()
和rotation()
的Q\u属性
宏,以便使用Qt动画框架对它们进行动画制作。我对项目执行转换,例如缩放和旋转(后者仅在开发中的多点触控分支中),我还对它们使用
QGraphicsDropShadowEffect
我使用QGLWidget
作为QGraphicsView
的视口,以便为应用程序启用OpenGL加速
问题是,尽管OpenGL加速了,但应用程序一点也不流畅。(尤其是动画,尤其是在我将旋转变换添加到多点触控分支之后。)显示的图形项目不多,也没有3D操作或任何严重的操作,只有2D绘图。我根本不是一个图形专家,所以我不知道为什么这个应用程序运行缓慢。我见过其他效果更复杂的游戏比这更流畅
秘密是什么?如何优化此应用程序?尤其是当场景中有移动项目时,其索引可能需要一些时间来更新其索引,从而降低性能。您可以使用调整索引。如果您不依赖或,这可能有助于提高性能
然而,这是一个漫长的过程。如果场景中只有很少的项目,则性能改进可能很小。通常最好将Graphicssystem设置为“光栅”(最终输出仍然是OpenGL,因为GL小部件作为视口)。您没有提到它,但是如果在命令行中添加“-graphicssystem raster”会带来任何改进,您可以很容易地尝试。根据我自己的经验,QGraphicsItem中的图形效果确实占用了大量内存和计算量。如果在动画过渡期间使用它们,可能就是问题所在。你应该把它们取下来,看看它有多平滑,然后试着实现你自己的效果。好的,我等了这么久才找到解决方案 与此同时,我已经用QML重写了应用程序的UI,令我惊讶的是,性能要好得多,应用程序现在非常流畅 一些结论:
- 在全屏模式下运行时,OpenGL加速效果最佳。将整个UI放在QDeclarativeView中,并将其视口设置为QGLWidget,并以全屏显示,这使得这成为可能
- QWidgets的开销似乎比我们想象的要大得多
- QML的性能比预期的要好得多
- QGraphicsDropShadow效果的影响很小,但我删除了它,现在我使用了笔划效果。在未来,我可能会考虑使用QML着色器效果。
- 为QDeclarativeView设置各种优化标志是值得的
- 使用alpha透明度绘制项目的效果要比不使用alpha透明度绘制项目的效果差得多。尽可能避免alpha透明
- 将QGraphicsItem子类重写为QDeclarativeItem子类非常简单,值得付出努力
我的答案适用于那些像我一样在
GraphicsItem::paint()方法中实现渲染模式逻辑的人。
例如:
GraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem*, QWidget*)
{
QPen _pen ;
const qreal normalPenWidthF = 1.5 ;
if(isSelected()) {
_pen.setColor(Settings::s_selectionColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
}
else
if(isHovered()) {
_pen.setColor(Settings::s_hoveredColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
}
else
if(someOtherLogic()) {
_pen.setColor(Settings::s_otherColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
else {
_pen.setColor(TSPSettings::s_defaultColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
//
painter->setPen(_pen) ;
painter->setBrush(Qt::NoBrush) ;
painter->drawEllipse(m_rect) ;
}
下面是我如何获得良好的QGraphicsView性能,即使是涉及多个层的大型场景。它甚至可以支持层间形状的动态剪裁
自定义GraphicsSitem应继承QAbstractGraphicsShapeItem,
因此,您有setPen()和setBrush()支持
公开一个接口来更新画笔和画笔,并使用一些逻辑来
仅在需要时触发更新
h
.cpp
然后您的GraphicsItem
(继承了AbstractGraphicsItem
)变成:
void GraphicsItem::updatePenAndBrush()
{
QPen _pen ;
if(isSelected()) {
_pen.setColor(Settings::s_selectionColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
} else
if(isHovered()) {
_pen.setColor(Settings::s_hoveredColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
} else
if(someOtherLogic()) {
_pen.setColor(Settings::s_otherColor) ;
_pen.setWidthF(normalPenWidthF) ;
} else {
_pen.setColor(Settings::s_defaultColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
_pen.setCosmetic(true) ;
setPen(_pen) ;
}
void GraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget *)
{
painter->setPen(pen()) ;
painter->setBrush(brush()) ;
painter->drawEllipse(s_rect) ;
}
旧的GraphicsItem::paint()
方法的内容现在位于GraphicsItem::updatepenadbrush()
中,并且偶尔调用,但不是每次调用paint时都调用。在另一方面,绘制方法可以触及基础。
显然,您必须自己调用updatepenadbrush()
,但对我来说并不难。
这不是我为提高绩效所做的唯一一件事。我搜索了很多,对于图形视图系统有很多可能的调整,但是有了这个,我的应用程序从几乎不可用变成了实时(最终!)项目的数量取决于用户可设置的拼图大小。在大多数情况下,它低于30。(在小屏幕上可能太难了。)setItemIndexMethod(NoIndex)代码>似乎不会对我的应用程序的性能造成任何可见的影响。测试这一点非常简单。只需执行一个scene.setItemIndexMethod(QGraphicscene::NoIndex)代码>直接在场景构建之后。至少在那个实验之后,你知道索引是否是你的瓶颈。默认行为是创建(和更新)BspTreeIndex。好的,看来索引不是您的问题。对不起(我将setItemIndexMethod(NoIndex);
直接添加到我的qgraphicscene
子类的构造函数中。似乎没有任何效果。:(但仍然感谢你的回答。:)你能量化性能a)和b)而不设置属性动画吗?@genphault-删除的目的是什么“提前谢谢你的回答”@spraff-我不能真正量化,我能说的是动画很慢,特别是当我在游戏开始时一次为所有项目设置动画,以及当我
AbstractGraphicsItem::AbstractGraphicsItem()
: QAbstractGraphicsShapeItem()
, m_hovered(false)
{
}
AbstractGraphicsItem::~AbstractGraphicsItem()
{
}
void AbstractGraphicsItem::setHovered(bool state)
{
if (h!=isHovered()) {
m_hovered = h ;
updatePenAndBrush() ;
update() ;
}
}
void AbstractGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
{
setHovered(true) ;
}
void AbstractGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
{
setHovered(false) ;
}
QVariant AbstractGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch(change) {
case ItemSelectedHasChanged :
updatePenAndBrush() ;
break ;
}
return QAbstractGraphicsShapeItem::itemChange(change, value);
}
void GraphicsItem::updatePenAndBrush()
{
QPen _pen ;
if(isSelected()) {
_pen.setColor(Settings::s_selectionColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
} else
if(isHovered()) {
_pen.setColor(Settings::s_hoveredColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
} else
if(someOtherLogic()) {
_pen.setColor(Settings::s_otherColor) ;
_pen.setWidthF(normalPenWidthF) ;
} else {
_pen.setColor(Settings::s_defaultColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
_pen.setCosmetic(true) ;
setPen(_pen) ;
}
void GraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget *)
{
painter->setPen(pen()) ;
painter->setBrush(brush()) ;
painter->drawEllipse(s_rect) ;
}