QGraphicsScene/QGraphicsView performance
-
Hi
I am using QGraphicsScene/QGraphicsView pair in my project
I have performance issue with this pair.
I added my custom graphics items to scene and displayed the contents with view. After that my custom graphics items paint method continuously called by scene(just like infinite loop). This makes 25% of CPU usage(approximately 400 items on scene). What may cause this behaviour?Here is one my item implementation:
@class LevelCrossingItem : public QGraphicsWidget
{
public:
LevelCrossingItem(QString _id,qreal _x,qreal _y);
~LevelCrossingItem();
QRectF boundingRect() const;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget widget / = 0 */);
void readStateBits();
bool isClosed();
bool isGateArmBroken();
bool isOpenedDuringRouteTanzimCompleted();
bool hasDataConsistencyWarning();
int type() const {return Type;}
private slots:
void setVisible(bool);
private:
enum {Type = FIELDLEVELCROSSING};
QString m_id;
QString m_source;
short m_closedState;
short m_brokenGateArmState;
short m_openedDuringRouteTanzimCompletedState;
short m_dataConsistencyWarningState;
QBitArray stateBitArray;
qreal x,y;
QSvgRenderer *renderer;
}; @@#include "levelcrossing.h"
LevelCrossingItem::LevelCrossingItem(QString _id,qreal _x,qreal _y):m_id(_id),x(_x),y(_y),stateBitArray(4)
{
m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
renderer = new QSvgRenderer;
setStateArray(stateBitArray);
setZValue(-0.5);
}LevelCrossingItem::~LevelCrossingItem()
{
delete renderer;
}void LevelCrossingItem::setVisible(bool visible)
{
QGraphicsItem::setVisible(visible);
}QRectF LevelCrossingItem::boundingRect() const
{
return QRectF(QPointF(x,y),sizeHint(Qt::PreferredSize));
}QSizeF LevelCrossingItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
return QSizeF(50,270);
}void LevelCrossingItem::readStateBits()
{
m_closedState = property("Closed").toInt();
m_brokenGateArmState = property("Broken").toInt();
m_openedDuringRouteTanzimCompletedState = property("OpenedOnRouteWarning").toInt();
m_dataConsistencyWarningState = property("DataConsistencyWarning").toInt();stateBitArray.setBit(0,qvariant_cast<bool>(m_closedState)); stateBitArray.setBit(1,qvariant_cast<bool>(m_brokenGateArmState)); stateBitArray.setBit(2,qvariant_cast<bool>(m_openedDuringRouteTanzimCompletedState)); stateBitArray.setBit(3,qvariant_cast<bool>(m_dataConsistencyWarningState)); setStateArray(stateBitArray);
}
void LevelCrossingItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
Q_UNUSED(option);
Q_UNUSED(widget);readStateBits(); m_closedState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("closed") : m_source = LEVELCROSSING_RESOURCE_PATH.arg("open"); m_brokenGateArmState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("broken") : m_source = m_source; if(m_openedDuringRouteTanzimCompletedState == Positive) { setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),true); if(stateChanged()) emit itemAlarmOccured(m_id,LevelCrossingIsOpenDuringTanzimCompleted); } else setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),false); if(m_dataConsistencyWarningState == Positive) { setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),true); if(stateChanged()) emit itemAlarmOccured(m_id,LevelCrossingDataConsistency); } else setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),false); renderer->load(m_source); renderer->render(painter,boundingRect());
}
bool LevelCrossingItem::isClosed()
{
return m_closedState == Positive;
}bool LevelCrossingItem::isGateArmBroken()
{
return m_brokenGateArmState == Positive;
}bool LevelCrossingItem::isOpenedDuringRouteTanzimCompleted()
{
return m_openedDuringRouteTanzimCompletedState == Positive;
}bool LevelCrossingItem::hasDataConsistencyWarning()
{
return m_dataConsistencyWarningState == Positive;
}@I read x and y coordinates from xml file. For this item x and y coordinates are 239,344 respectively
-
you are emitting signals during your paint method, if these are connected to the (im assuming) game logic, and trigger a redraw, you will get an infinite ish loop, possibly you should restructure you game logic to be separate form the paint methods.
that is my first thought anyway...
-
Hi,
First of all, your paint methods will always be called when the view interacts with mouse unless you ignore the mouse events.
Secondly, paint ,as it stands, should only perform painting but as far as I see you do many things beyond painting. Maybe that's why your items are slow. Plus remember that they will much faster in release mode(in case if you are working in debug mode).
Finally, what's the renderer?
-
[quote author="zgulser" date="1297760455"]Finally, what's the renderer?
[/quote]QSvgRenderer instance pointer.
-
[quote author="Jorj" date="1297696052"]you are emitting signals during your paint method, if these are connected to the (im assuming) game logic, and trigger a redraw, you will get an infinite ish loop[/quote]
I commented emit stuff but CPU usage did not change.
-
As I can see now you mess up everything with everything.
- paint method should do only painting nothing else (performance reasons)
- sizeHint is hardcoded I doubt you reale need this
- boundingRect is wrong for sure.
- you messing around with properties when it is not needed (this is needed if code supposed to manipulate objects with unknown api/structure).
Maybe explain what this should show!
[EDIT: fixed list - use "*" instead of "-" as "bullets", Volker]
-
MarekR22
How should I implement boundingRect()?
Sample code please. -
Although it won't solve your problem totally, it should be something like;
@
void Item::setBoundingRect(const QRect& pBoundingRect)
{
mBoundingRect = pBoundingRect;
}const QRect& Item::getBoundingRect()
{
return mBoundingRect;
}const QRect& Item::boundingRect()
{
return getBoundingRect();
}
@ -
[quote author="onurozcelik" date="1297780179"]MarekR22
How should I implement boundingRect()?
Sample code please.[/quote]
The joke is that you don't have to. QGraphicsWidget returns boundingRect which in most cases should be ok.
But like I said describe what you are trying to achieve then we will show you how code should look like.
Note there is a class "QGraphicsSvgItem":http://doc.trolltech.com/latest/qgraphicssvgitem.html. Maybe this is enough for you. -
implementing boundingRect correctly solved the infinite repaint loop problem.
-
[quote author="zgulser" date="1297781851"]
Although it won't solve your problem totally, it should be something like;@
void Item::setBoundingRect(const QRect& pBoundingRect)
{
mBoundingRect = pBoundingRect;
}const QRect& Item::getBoundingRect()
{
return mBoundingRect;
}const QRect& Item::boundingRect()
{
return getBoundingRect();
}
@[/quote]For performance critical code, you should just inline the stuff above.