【问题标题】:QGraphicsScene/QGraphicsView performanceQGraphicsScene/QGraphicsView 性能
【发布时间】:2011-06-26 18:48:42
【问题描述】:

我在我的项目中使用 QGraphicsScene/QGraphicsView 对 我对这对有性能问题。 我将我的自定义图形项添加到场景中并用视图显示内容。之后,我的自定义图形项绘制方法被场景连续调用(就像无限循环一样)。这使得 %25 的 CPU 使用率(场景中大约 400 个项目)。什么可能导致这种行为?

这是我的一个项目实现:

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;
}

我从 xml 文件中读取 x 和 y 坐标。该项目的 x 和 y 坐标分别为 239,344

【问题讨论】:

  • 没有“State/emit”的东西你有同样的问题吗?
  • 我评论了 state/emit 的东西,但 CPU 使用率没有改变。
  • 渲染器->load(m_source);在油漆事件中也是个坏主意。

标签: performance qt qgraphicsview


【解决方案1】:

您的图形项目很可能在实现中存在错误。我有类似的行为,但我无法弄清楚究竟是什么原因造成的。我怀疑当您在边界矩形之外绘制时会发生这种情况。这会触发一些清理程序,这反过来会导致项目重绘,然后进入循环。最终,我通过仔细检查自定义图形项的实现并确保:

  1. 这些不是MyGraphicsItem::boundingRect 之外的绘画。使用painter-&gt;setClipRect(boundingRect())
  2. MyGraphicsItem::shape 不与 MyGraphicsItem::boundingRect 交叉。
  3. 如果您覆盖任何其他 QGraphicsItem 函数,请确保您的实现是正确的。

希望这会有所帮助。随意贴出你的图形项的源代码,这样会更容易找到问题。

【讨论】:

  • @onurozcelik 为什么继承自 QGraphicsWidget?我无法运行您的示例,我没有 SVG 源,因此很难调试它。但尝试这样做:painter-&gt;setClipRect(boundingRect()) 在渲染 SVG 项目之前。
  • @onurozcelik 同样,QGraphicsItem 对象应明确定位在场景中。最好调用setPos(x, y),返回一个相对的boundingRect()
  • @onurozcelik 最后,您在paint 方法中发出所有这些,这不是很好。即使场景中没有任何变化,也可能会调用 Paint。您没有提供所有代码,但这些信号不是触发重绘项目的情况吗?
  • @ak 你提到返回相对 boundingRect()。我应该如何实现boundingRect()?你能发布示例代码吗?
  • @ak 实现 boundingRect 正确解决了无限重绘循环问题。谢谢你
猜你喜欢
  • 2017-02-16
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 2013-11-19
  • 2013-10-26
  • 2012-10-03
  • 2014-02-18
  • 1970-01-01
相关资源
最近更新 更多