简体   繁体   中英

QGraphicsView slow with lots of QGraphicsPixmapItem

I've made a small code to test QGraphicsView capabilities using QtCreator.

The code is quite simple, just created a class thats inherited from QGraphicsView that has a QGraphicsScene on it. Fill the scene with lots of QGraphicsPixmapItem (in this case 2000) scaled to 100x100 and randomly place them into the scene.

Then inside the custom class and using a QTimer move a bit all the elements of the scene.

(Added a second QTimer to see the how many times per second the first QTimer is called).

It work great with a few hundred elements but if the elements numbers increase, the performance drops.

Could someone give me a hint on how to increase the performance? Maybe the access to the elements using a QList is slow ... or the use of a QTimer for this simple animation is a very bad idea ... or just a few optimization flags must be added somewhere ... maybe forget QGraphicsView and try QtQuick and QML ...

The final application should draw lots of images in screen and animate some of them using png images as source.

test.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = test
TEMPLATE = app


SOURCES += main.cpp \
    c_view.cpp

HEADERS  += \
    c_view.h

FORMS    +=

RESOURCES += \
    res.qrc

C_View.h

#ifndef C_VIEW_H
#define C_VIEW_H

#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QTimer>

class C_View : public QGraphicsView
{
    Q_OBJECT

public:
    C_View();

    QGraphicsScene *scene;

    QGraphicsTextItem *label_fps;

    QTimer timer;
    QTimer timer_fps;
    int interval=0;
    int fps=0;
private slots:
    void random_move();
    void show_fps();
};

#endif // C_VIEW_H

C_View.cpp

#include "c_view.h"

C_View::C_View()
{
    this->scene = new QGraphicsScene();
    this->setScene(this->scene);

    // Label to see how many times per seconds the random_move function gets called
    this->label_fps=new QGraphicsTextItem();
    this->label_fps->setDefaultTextColor(Qt::black);
    this->label_fps->setFont(QFont("times",16));
    this->label_fps->setPos(10,10);
    this->scene->addItem(this->label_fps);

    // Qtimer to enter random_move function
    connect(&this->timer,SIGNAL(timeout()),this,SLOT(random_move()));
    //this->interval=10; // 100 FPS?
    this->interval=25; // 40 FPS?
    //this->interval=50; // 20 FPS?
    //this->interval=100; // 10 FPS?
    this->timer.setInterval(this->interval);
    this->timer.start();

    // QTimer to update the FPS label
    connect(&this->timer_fps,SIGNAL(timeout()),this,SLOT(show_fps()));
    this->timer_fps.setInterval(1000); // Once a second
    this->timer_fps.start();

}

// Funcion that moves a bit all the items of the scene
void C_View::random_move()
{
    QList <QGraphicsItem*> l = this->items();
    int ini=0;
    for(int i=ini;i<l.size();i++)
    {
        l[i]->setPos(l[i]->x()+(rand()%3)-1,l[i]->y()+(rand()%3)-1);
    }

    this->fps++;
}

// Just show how many times random_move function gets call, since last time
void C_View::show_fps()
{
    this->label_fps->setPlainText("FPS "+QString::number(this->fps));
    this->label_fps->setZValue(1);
    this->fps=0;
}

main.cpp

#include <QApplication>

#include "c_view.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    C_View *view = new C_View();

    // Fill the QGraphicsView with lots of images
    for(int i=0;i<2000;i++)
    {
        QGraphicsPixmapItem *item=new QGraphicsPixmapItem();
        item->setPixmap(QPixmap(":/images/p.png").scaled(100,100));
        item->setPos(rand()%view->width(),rand()%view->height());
        view->scene->addItem(item);
    }

    view->show();

    return a.exec();
}

The suggestion to give up Qt is a bit fatalistic and premature, in my opinion. Our application uses QGraphicsScene with many tens of thousands of items and we have good performance. Most of them aren't images, however, and we don't move thousands of them at a time. Switching to something else may end up being the case, but it's worth some additional experimentation first.

A profiler, if you have one, can certainly help you. We use Visual Studio and the profiler works well there, but I don't know if Qt Creator has any profiling ability. Your sample application is very simple, and I don't see anything obvious to change, but profiling is often very revealing.

Since you're moving things around the scene, experiment with the options for QGraphicsScene::setItemIndexMethod and QGraphicsScene::setBspTreeDepth. The recommended settings for those vary depending on how you tend to use the scene.

Moving 2000 items every second seems like a lot in my opinion. You say that your final application with have lots of images but with only some of them moving. Do you expect that 2000 of them will move?

Also, what version of Qt are you using? Later versions make better decisions about the rendering engine to use and our experience is that it's pretty good about that.

Start your timer after your view shows up (in the main function for instance). That should fix that strange behaviour. Edit: No that will change nothing. Try

setViewportUpdateMode(BoundingRectViewportUpdate);
//setCacheMode(QGraphicsView::CacheBackground);

instead. Here are the docs: setViewportUpdateMode | setCacheMode . Don't forget to read about those functions argument types.

On the other hand, you normally do not need to handle a pointer to a QGraphicsScene inside a QGraphicsView since this class provides you with a scene() function. If your code do require this pointer, I think naming your attribute m_scene (or whatever except the scene() function name) would be more convenient.

Edit2

Another way to improve rendering speed is to lower your scene item' bounding rectangle. To do so, you can scale your pixmap items to 50*50 (for instance) instead of 100*100. Indeed the fewer scene items collide, the faster Qt rendering process will be. Furthermore, here is an article issuing some optimization tricks when using customized QGraphicsItem inside QGraphicsView: Qt: Improving QGraphicsView Performance . You aren't currently using customized items but reading that article would be benefic I think.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM