Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to improve QGraphicsView performance in a 2D static scene with many items? (no way to solve it?)
Forum Updated to NodeBB v4.3 + New Features

How to improve QGraphicsView performance in a 2D static scene with many items? (no way to solve it?)

Scheduled Pinned Locked Moved General and Desktop
6 Posts 5 Posters 6.4k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    jhcepas
    wrote on last edited by
    #1

    If understood correctly, QGraphicsView is supposed to handle million items efficiently.

    In my application, I only have some few thousand and the performance is already very bad. When the View is showing the whole scene, zooming, hoverEnvents and any other stuff becomes impossible.

    I have tried to create a parent-child relationship among items, and try different optimization flags, but still the same result. I really hope that I'm making some stupid mistake, but after several days looking for a way to solve the problem, I did not find any solution.

    I would really appreciate any help!

    This reproduces my problem:
    @
    import sys
    import random
    from PyQt4.QtGui import *

    NO_INDEX = False
    OPTIMAZE = False
    ITEM_COORD_CACHE = False
    ITEM_DEVICE_CACHE = False
    NESTED_ITEMS = False
    
    
    class TestItem(QGraphicsEllipseItem):
        def paint(self, painter, option, index):
            return QGraphicsEllipseItem.paint(self, painter, option, index)
    
        def hoverEnterEvent (self, e):
            self.setBrush(QBrush(QColor("orange")))
    
        def hoverLeaveEvent(self,e):
            self.setBrush(QBrush(None))
    
    if __name__ == '__main__':
        n = int(sys.argv[1]) # Number of items. With 5000 I already
                               # have performance problems
        app = QApplication(sys.argv)
        scene = QGraphicsScene()
    
        # Populates scene
        prev = None
        for i in xrange(n):
            # Random geometry and position
            r1 = random.randint(10, 100)
            r2 = random.randint(10, 100)
            x = random.randint(0, 500)
            y = random.randint(0, 500)
    
            item = TestItem(x, y, r1*2, r2*2)
            item.setAcceptsHoverEvents(True)
    
            if NESTED_ITEMS: 
                # Creates a parent child structure among items
                if not prev:
                    scene.addItem(item)
                else:
                    item.setParentItem(prev)
                prev = item
            else:
                scene.addItem(item)
    
            if ITEM_COORD_CACHE:
                item.setCacheMode(QGraphicsItem.ItemCoordinateCache)
            elif ITEM_DEVICE_CACHE:
                item.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
    
        # Creates View
        view = QGraphicsView(scene)
        # Sets basic Flags for nice rendering 
        view.setRenderHints(QPainter.Antialiasing or QPainter.SmoothPixmapTransform)
    
        if NO_INDEX:
            view.setItemIndexMethod(QGraphicsScene.NoIndex);
            
        if OPTIMAZE:
            view.setOptimizationFlags(QGraphicsView.DontAdjustForAntialiasing
                                      or QGraphicsView.DontClipPainter
                                      or QGraphicsView.DontSavePainterState)
    
        view.show()
        sys.exit(app.exec_())@
    
    • Intel(R) Xeon(R) CPU E5410 @ 2.33GHz
    • nVidia Corporation G84 [Quadro FX 1700]
    • Ubuntu 9.04 64 bits
    • qt4 4.5.3
    • python-qt4 4.6
    1 Reply Last reply
    0
    • W Offline
      W Offline
      w00t
      wrote on last edited by
      #2

      I converted your sample to C++ (see below) and ran it through a profiler. Your main bottleneck is QPainter::drawEllipse().

      The expensive parts, especially, seem to be QPainterPath::toFillPolygons() and QTesselator::tesselate().

      This isn't especially surprising, as with thousands of items, they all overlap, meaning hover and unhover triggers for all of them, which means a full redraw of that item each time.

      @#include <QApplication>
      #include <QGraphicsScene>
      #include <QGraphicsView>
      #include <QGraphicsEllipseItem>
      #include <QDebug>

      bool NO_INDEX = false;
      bool OPTIMAZE = false;
      bool ITEM_COORD_CACHE = false;
      bool ITEM_DEVICE_CACHE = false;
      bool NESTED_ITEMS = false;

      class TestItem : public QGraphicsEllipseItem
      {
      public:
      TestItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = 0) : QGraphicsEllipseItem(x, y, width, height, parent)
      {

      }
      
      void paint(QPainter *painter, const QStyleOptionGraphicsItem * option, QWidget
              *index)
      {
          return QGraphicsEllipseItem::paint(painter, option, index);
      }
      
      void hoverEnterEvent(QGraphicsSceneHoverEvent *e)
      {
          this->setBrush(QBrush(QColor("orange")));
      }
      
      void hoverLeaveEvent(QGraphicsSceneHoverEvent *e)
      {
          this->setBrush(QBrush("red"));
      }
      

      };

      int main(int argc, char **argv)
      {
      QApplication app(argc, argv);
      QGraphicsScene scene;

      // Populates scene
      QGraphicsItem *prev = NULL;
      
      int n = atoi(argv[1]);
      qDebug() << "Adding " << n << " items";
      
      for (int i = 0; i != n; ++i) {
          // Random geometry and position
          int r1 = rand() % 100 + 10;
          int r2 = rand() % 100 + 10;
          int x = rand() % 500;
          int y = rand() % 500;
      
          QGraphicsItem *item = new TestItem(x, y, r1*2, r2*2);
          item->setAcceptsHoverEvents(true);
      
          if (NESTED_ITEMS) {
              // Creates a parent child structure among items
              if (!prev)
                  scene.addItem(item);
              else
                  item->setParentItem(prev);
              prev = item;
          }
          else
              scene.addItem(item);
      
          if (ITEM_COORD_CACHE)
              item->setCacheMode(QGraphicsItem::ItemCoordinateCache);
          else if (ITEM_DEVICE_CACHE)
              item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
      }
      
      // Creates View
      QGraphicsView view;
      view.setScene(&scene);
      
      // Sets basic Flags for nice rendering 
      view.setRenderHints(QPainter::Antialiasing |
              QPainter::SmoothPixmapTransform);
      

      // if (NO_INDEX)
      // view.setItemIndexMethod(QGraphicsScene::NoIndex);

      if (OPTIMAZE)
          view.setOptimizationFlags(QGraphicsView::DontAdjustForAntialiasing
                                    | QGraphicsView::DontClipPainter
                                    | QGraphicsView::DontSavePainterState);
      
      view.show();
      return app.exec&#40;&#41;;
      

      }@

      --
      http:&#x2F;&#x2F;rburchell.com

      1 Reply Last reply
      0
      • W Offline
        W Offline
        w00t
        wrote on last edited by
        #3

        As for how to improve your specific example... I don't know. One idea might be to not immediately setBrush() on hover/unhover, but set a timer to trigger the change 50ms or so later, which would mean that the cursor might have moved to a different item.

        Stacking order is also an idea, i.e. make it only affect the topmost item, but that's probably going to be complicated.

        --
        http:&#x2F;&#x2F;rburchell.com

        1 Reply Last reply
        0
        • H Offline
          H Offline
          hvantil
          wrote on last edited by
          #4

          Robin, this may be an aside, but what profiler did you use? Any suggestions?

          1 Reply Last reply
          0
          • A Offline
            A Offline
            andre
            wrote on last edited by
            #5

            Callgrind from the valgrind suite comes to mind.

            1 Reply Last reply
            0
            • D Offline
              D Offline
              dangelog
              wrote on last edited by
              #6

              Again: please: stop necroposting. Start a brand new thread :)

              Software Engineer
              KDAB (UK) Ltd., a KDAB Group company

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved