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. QGraphicsScene taking long to update
QtWS25 Last Chance

QGraphicsScene taking long to update

Scheduled Pinned Locked Moved Unsolved General and Desktop
qgraphicswidgetqtimerpysideqgraphicsview
7 Posts 4 Posters 3.3k Views
  • 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.
  • M Offline
    M Offline
    martinvej
    wrote on 17 Aug 2017, 11:55 last edited by martinvej
    #1

    I am trying to get a QGraphicsScene to update at a fixed rate with a timer.

    An example of what I'm trying to achieve is to animate a rectangle moving across the screen with its x position being incremented every frame (for example at 120 fps). However, when calling update() on the QGraphicsScene, it takes about 16 msec to complete (even when the scene is empty, as in the example below). This caps the frame rate at about 60, and the slowdown accumulates if there is more than one QGraphicsScene that needs to get updated.
    What is the right way to go about this?
    Thanks!

    import qt
    
    class View(qt.QGraphicsView):
        def __init__(self):
            qt.QGraphicsView.__init__(self)
            self.setScene(qt.QGraphicsScene())
            
    class Window(qt.QDialog):
        def __init__(self):
            qt.QDialog.__init__(self)
            self.setLayout(qt.QVBoxLayout())
    
            self.view = View()
            self.view.setViewportUpdateMode(qt.QGraphicsView.NoViewportUpdate)
            self.layout().addWidget(self.view)
    
            self.btn = qt.QPushButton('Start')
            self.btn.clicked.connect(self.clicked)
            self.layout().addWidget(self.btn)
    
            self.time = qt.QTime()
    
            self.timer = qt.QTimer()
            self.timer.timeout.connect(self.runUpdate)
    
            self.frame = 0
            self.dontUpdate = False
    
        def clicked(self):
            self.timer.start(1)
    
        def runUpdate(self):
            self.frame += 1
            self.time.start()
            if not self.dontUpdate:
                self.view.scene().update()
            print(self.time.elapsed(), qt.QTime.currentTime().msec(), self.frame)
    
    app = qt.QApplication([])
    window = Window()
    window.show()
    app.exec_()
    

    Note: the script above is using the following python module (qt.py),

    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtWidgets import *
    
    M 1 Reply Last reply 17 Aug 2017, 11:58
    0
    • M martinvej
      17 Aug 2017, 11:55

      I am trying to get a QGraphicsScene to update at a fixed rate with a timer.

      An example of what I'm trying to achieve is to animate a rectangle moving across the screen with its x position being incremented every frame (for example at 120 fps). However, when calling update() on the QGraphicsScene, it takes about 16 msec to complete (even when the scene is empty, as in the example below). This caps the frame rate at about 60, and the slowdown accumulates if there is more than one QGraphicsScene that needs to get updated.
      What is the right way to go about this?
      Thanks!

      import qt
      
      class View(qt.QGraphicsView):
          def __init__(self):
              qt.QGraphicsView.__init__(self)
              self.setScene(qt.QGraphicsScene())
              
      class Window(qt.QDialog):
          def __init__(self):
              qt.QDialog.__init__(self)
              self.setLayout(qt.QVBoxLayout())
      
              self.view = View()
              self.view.setViewportUpdateMode(qt.QGraphicsView.NoViewportUpdate)
              self.layout().addWidget(self.view)
      
              self.btn = qt.QPushButton('Start')
              self.btn.clicked.connect(self.clicked)
              self.layout().addWidget(self.btn)
      
              self.time = qt.QTime()
      
              self.timer = qt.QTimer()
              self.timer.timeout.connect(self.runUpdate)
      
              self.frame = 0
              self.dontUpdate = False
      
          def clicked(self):
              self.timer.start(1)
      
          def runUpdate(self):
              self.frame += 1
              self.time.start()
              if not self.dontUpdate:
                  self.view.scene().update()
              print(self.time.elapsed(), qt.QTime.currentTime().msec(), self.frame)
      
      app = qt.QApplication([])
      window = Window()
      window.show()
      app.exec_()
      

      Note: the script above is using the following python module (qt.py),

      from PySide2.QtCore import *
      from PySide2.QtGui import *
      from PySide2.QtWidgets import *
      
      M Offline
      M Offline
      m.sue
      wrote on 17 Aug 2017, 11:58 last edited by m.sue
      #2

      Hi @martinvej

      Is it WINDOWS? 16 ms ist the timer granularity on WINDOWS. That may have nothing to do with the graphics view (if it has simple enough contents).

      -Michael.

      M 1 Reply Last reply 17 Aug 2017, 12:03
      0
      • M m.sue
        17 Aug 2017, 11:58

        Hi @martinvej

        Is it WINDOWS? 16 ms ist the timer granularity on WINDOWS. That may have nothing to do with the graphics view (if it has simple enough contents).

        -Michael.

        M Offline
        M Offline
        martinvej
        wrote on 17 Aug 2017, 12:03 last edited by martinvej
        #3

        @m.sue I'm currently running this on macOS (El Capitan). My biggest concern is that if I have 3 or 4 QGraphicsScenes that are all tied to my animation, their total update time would be around 64 msec, which leaves me at < 16 fps.

        1 Reply Last reply
        0
        • M Offline
          M Offline
          martinvej
          wrote on 17 Aug 2017, 15:58 last edited by martinvej
          #4

          Figured out this wouldn't get any faster, as it is tied to the refresh rate of the monitor (60Hz) and since vsync is turned on by default, a gui update can't happen at a faster rate. Is there any way to lock/ unlock gui updates?

          M 1 Reply Last reply 17 Aug 2017, 16:24
          0
          • M martinvej
            17 Aug 2017, 15:58

            Figured out this wouldn't get any faster, as it is tied to the refresh rate of the monitor (60Hz) and since vsync is turned on by default, a gui update can't happen at a faster rate. Is there any way to lock/ unlock gui updates?

            M Offline
            M Offline
            mrjj
            Lifetime Qt Champion
            wrote on 17 Aug 2017, 16:24 last edited by
            #5

            @martinvej

            Hi most gfx card can turn off Vsync
            Not that screen can draw any faster regardless but it allows u to puch more frames.

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on 17 Aug 2017, 22:14 last edited by
              #6

              Hi,

              To get any faster you'll likely have to consider going OpenGL.

              What kind of animation do you have ? And do you really need to reach 120fps ?

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • M Offline
                M Offline
                martinvej
                wrote on 21 Aug 2017, 09:22 last edited by
                #7

                @SGaist
                Thanks for suggesting OpenGL, I think that might be a possibility at some point.
                As of now, I got it to work by locking the UI updates and batch repainting all of the windows at once:

                for(auto widget : qApp->topLevelWidgets()){
                    widget->setUpdatesEnabled(true);
                }
                qApp->processEvents();
                for(auto widget : qApp->topLevelWidgets()){
                    widget->setUpdatesEnabled(false);
                }
                

                I know this may not be the best way to achieve this, so I am all ears if there's any better way to limit UI updates to a single point in execution.
                Thanks!

                1 Reply Last reply
                0

                1/7

                17 Aug 2017, 11:55

                • Login

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