如何在QGraphicsScene中移动1000个项目而不阻止UI

时间:2013-08-23 07:52:23

标签: c++ qt qgraphicsscene

我的QGraphicsScene中有大约1000个图形项目。我想把所有这1000件物品都搬到新的位置。新职位彼此无关,所有职位应同时完成  一种方法是遍历这1000个项目并为每个项目调用setPos!我认为这将阻止用户界面。另一种方法是在另一个线程中绘制图像,并在QGraphicsScene中设置此图像!
愿你有另一个想法。我很期待听到这个消息!

3 个答案:

答案 0 :(得分:8)

如果您了解Qt绘图是如何工作的,那么Qt绘图可以非常快速,即使您想要绘制,例如,1000条鱼都可以独立移动。

在大量项目的情况下,处理此问题的最糟糕方式是为每个项目创建单独的QGraphicsItem / QGraphicsObject,并尝试独立移动和绘制它们。人们在这里没有意识到的一个主要问题是,当调用油漆(QPainter * painter ...)功能时,他们会在画家上设置笔和画笔。通常情况下,这没关系,但在内部进行这样的开销,图形管道将停滞不前。对于1000件商品来说,这真的会减慢速度。

相反,如果我们将鱼设计成鱼群而只创建一个QGraphicsItem,我们可以在内部跟踪它们的位置并且只调用一次绘制函数。

class SchoolOfFish : QGraphicsObject // QGraphicsObject for signals / slots
{
    Q_OBJECT

    public:
        void UpdateFish();

    protected:
        void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); // overloaded paint function      

    private:
        QList<QPoint> m_fishPositionList;
};

请注意,鱼的所有位置都保存在QPoint对象的QList中。有几种优化可以在这里完成。首先,我经常看到人们在绘画功能中更新项目位置,导致性能不佳;只有绘图功能才能在绘画中完成。

最初可以在计时器上更新鱼位,也许可以达到每秒30帧。如果这太慢了,那么我们可以创建一个单独的线程来更新所有鱼位置并将列表发送回SchoolOfFish对象;所有图形渲染必须在主线程上完成。

这种方法实际上只是将鱼群视为particle system。以这种方式设计系统后,如果需要,我想要进行的最后一次优化将转移到OpenGl。但是,请注意,您实际上可以获得标准的Qt绘制调用以使用OpenGl作为QWidget状态的文档

  

要使用OpenGL渲染,只需调用setViewport(new QGLWidget)即可。   QGraphicsView获得视口小部件的所有权。

答案 1 :(得分:2)

要在Qt中绘制大量项目,可以通过移动到较低级别的绘图界面来获得更好的服务。例如,OpenGL可以在QWindow上实现(可以锚定在主窗口中),参见http://qt-project.org/doc/qt-5.0/qtgui/openglwindow.html。 OpenGL可能会有点痛苦,但你不必担心阻塞,我当前的项目就是在大约100毫秒内渲染300,000个彩色方块。

答案 2 :(得分:0)

动态场景中setPos()的大幅加速可以通过以下方式实现:

QGraphicsScene scene;
scene.setItemIndexMethod(QGraphicsScene.NoIndex);

这比动态场景的默认QGraphicsScene.BspTreeIndex快得多,但需要付出代价,因为需要查询QGraphicsScene的事件现在会慢得多(例如悬停事件)。

加快速度的另一种方法是减少对象的总数。如果场景使用了大量QGraphicsItemGroup,则可以尝试使用普通QGraphicsItem替换它们,并覆盖它的paint()方法,而不是使用子对象。

尽管如此,即使有了这种优化,我发现QGraphicsScene的性能在超过几百个对象时仍然非常悲惨。 QtQuick似乎更好地处理大型对象集合。