Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move around 1000 items in a QGraphicsScene without blocking the UI

I have around 1000 graphics item in my QGraphicsScene. I want to move all of these 1000 items to new position. New positions don't relate to each other and all of them should be done at the same time.
One way is to iterate through these 1000 items and call setPos for each one ! I think this will block user interface. Another way is to draw an image in another thread and to set this image as a result in QGraphicsScene!
May you have another idea.I'm looking forward to hearing that !

like image 787
s4eed Avatar asked Dec 26 '22 22:12

s4eed


1 Answers

Qt drawing can be very quick if you understand how it works, even if you want to draw, for example, 1000 fish all moving independently.

In the case of a large number of items, the worst way to handle this is to create a separate QGraphicsItem / QGraphicsObject for each item and try to move and draw them all independently. One major issue people don't realise here is that when the paint(QPainter * painter...) function is called, they set the pen and brush on the painter. Normally, that's ok, but there is an overhead doing this as internally, the graphics pipeline will be stalled. For 1000 items, that's really going to slow things down.

Instead, if we design the fish as a school of fish and create just one QGraphicsItem, we can keep track of their positions internally and have the paint function called just once.

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

Note that all the positions of the fish are kept in a QList of QPoint objects. There are several optimisations that can be done here. Firstly, I often see people updating item positions in the paint function, which causes poor performance; Only drawing functionality should be done in paint.

Updating the fish positions can initially be done on a timer, perhaps aiming for 30 frames per second. If this is too slow, then we could create a separate thread that updates all the fish positions and emits the list back to the SchoolOfFish object; all graphics rendering must be done on the main thread.

This method is actually just treating the school of fish as a particle system. After designing the system this way, if required, the last optimisation I'd look to make would be moving to OpenGl. However, note that you can actually get the standard Qt paint calls to use OpenGl as the docs of QWidget state

To render using OpenGL, simply call setViewport(new QGLWidget). QGraphicsView takes ownership of the viewport widget.

like image 134
TheDarkKnight Avatar answered Dec 29 '22 06:12

TheDarkKnight