如何在不阻塞UI的情况下在QGraphicsScene中移动1000个项目
How to move around 1000 items in a QGraphicsScene without blocking the UI
我的QGraphicsScene
中有大约1000个图形项目。我想把这1000件商品全部搬到新的位置。新职位之间没有关联,所有职位都应该同时完成
一种方法是迭代这1000个项目,并为每个项目调用setPos
!我认为这会阻塞用户界面。另一种方法是在另一个线程中绘制图像,并在QGraphicsScene中设置此图像作为结果
也许你还有别的想法。我很期待听到这个消息!
Qt绘图可以非常快速,如果你了解它的工作原理,即使你想画1000条鱼,它们都独立移动。
在有大量项目的情况下,最糟糕的处理方法是为每个项目创建一个单独的QGraphicsItem/QGraphicsObject,并尝试单独移动和绘制它们。这里人们没有意识到的一个主要问题是,当调用paint(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对象;所有的图形渲染都必须在主线程上完成。
这种方法实际上只是将鱼群视为一个粒子系统。在以这种方式设计系统后,如果需要,我希望进行的最后一次优化将转移到OpenGl。然而,请注意,您实际上可以获得标准的Qt绘制调用,以使用OpenGl作为QWidget状态的文档
要使用OpenGL进行渲染,只需调用setViewport(新的QGLWidget)。QGraphicsView拥有视口小部件的所有权。
对于在Qt中绘制大量项目,转移到较低级别的绘图界面可能会更好。例如,OpenGL可以在QWindow上实现(可以锚定在主窗口中),请参见http://qt-project.org/doc/qt-5.0/qtgui/openglwindow.html.OpenGL可能有点麻烦,但你不必担心阻塞,我目前的项目正是这样做的,在大约100毫秒内渲染出300000个彩色正方形。
动态场景中setPos()
的显著加速可以通过实现
QGraphicsScene scene;
scene.setItemIndexMethod(QGraphicsScene.NoIndex);
这比动态场景的默认QGraphicsScene.BspTreeIndex
快得多,但这是有代价的,因为需要查询QGraphicsScene
的事件现在会慢得多(例如悬停事件)。
另一种加快速度的方法是减少对象的总数。如果场景使用了大量的QGraphicsItemGroup
,可以尝试用普通的QGraphicsItem
替换它们,并覆盖它的paint()
方法,而不是使用子对象。
也就是说,即使有了这些优化,我发现一旦超过几百个对象,QGraphicsScene的性能仍然非常糟糕。QtQuick似乎能更好地处理大型对象集合。
- QGraphicsItems not showing up QGraphicsScene
- Qt QGraphicsProxyWidget 与 QGraphicsScene 的交互
- Qt将许多QGraphicsPixmapItem添加到QGraphicsScene中
- QGraphicsScene 中的 QPushButton 需要双击而不是单击
- 在 QWidget 中的 QGraphicsScene 中绘制
- 在 QGraphicsScene 中组织项目
- QGraphicsItem::p aint(): 如何检查 QGraphicsScene 是否已打印
- 子类QGraphicsScene的错误
- QGraphicsScene项目在两次(x2)位置绘制
- 图形项目的QgraphicsScene中的可拖动像素
- Qt中是否有QLabel::setScaledContent等效函数用于QGraphicsScene?
- 无法读取 QGraphicsScene 的内容
- 围绕QgraphicsScene移动QGraphicsView
- 有没有办法停止QGraphicsScene
- 如何在QGraphicsScene上绘制填充多边形
- Qt QGraphicsScene::setSceneRect() 实际上并没有设置场景 rect
- Qt Application with QTabWidget, QGraphicsScene and QPushButt
- Qt - QGraphicsScene 和 QGraphicsView 不更新更改?
- 为什么不能从 QVector 将 Item 添加到 QGraphicsScene <QGraphicsItem>中?
- 将QGraphicsScene嵌入QML中