python-3.xpyqtpyqt5sleepqstatusbar

QStatusBar.showMessage() not updating consistently


MY APOLOGIES:

THIS APPEARS TO BE A DUPLICATE OF: PyQt - running a loop inside GUI

WHICH HAS A GOOD SOLUTION AND TUTORIAL LINK.

My Setup:

OS: Windows 10 ver1903

Python: 3.7.4

PyQt5: 5.13.0

My Problem:

PyQt5 is not updating the statusBar consistently. I'm seeing this problem in a larger application. I wrote this debug app to try to identify the problem more clearly, and it has reproduced:

import sys, time
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class statusdemo(QMainWindow):
   def __init__(self, parent = None):
      super(statusdemo, self).__init__(parent)

      qpb = QPushButton("Debug")
      qpb.clicked.connect(self.debug)
      self.setCentralWidget(qpb)

      self.statusBar = QStatusBar()
      self.setWindowTitle("QStatusBar Debug")
      self.setStatusBar(self.statusBar)

   def wait(self, duration=2.0):
      print(f"waiting for {duration}")
      tstart = time.time()
      while(True):
         if duration < (time.time() - tstart):
            break

   def debug(self):
      # self.statusBar.showMessage("Checkpoint 001", 2000)
      self.statusBar.showMessage("Checkpoint 001")
      # time.sleep(2)
      self.wait()
      # self.statusBar.showMessage("Checkpoint 002", 2000)
      self.statusBar.showMessage("Checkpoint 002")
      # time.sleep(2)
      self.wait()
      # self.statusBar.showMessage("Checkpoint 003", 2000)
      self.statusBar.showMessage("Checkpoint 003")
      # time.sleep(2)
      self.wait()
      # self.statusBar.showMessage("Completed debug()", 2000)
      self.statusBar.showMessage("Completed debug()")


def main():
   app = QApplication(sys.argv)
   ex = statusdemo()
   ex.show()
   sys.exit(app.exec_())


if __name__ == '__main__':
   main()

EXPECTED: Click "Debug" button and see "Checkpoint ###" printed in the status bar for 2 seconds periodically, ending with an indefinite status bar display of "Completed debug()".

ACTUAL: Click the "Debug" button, see the print statements from wait() in cmd, but I see none of the "Checkpoint ###" updates until "Completed debug()".

I'm at the point where it seems the next step is to try to leverage the "statusBar.messageChanged" signal, but that feels like too much for something that is supposed to be built in. I figure I'm missing something obvious but can't see it.


Solution

  • Your example doesn't work because the while-loop in the wait function will block the gui and prevent the status-bar updating. There are several different ways to deal with this problem. If the status-bar updates happen at fixed intervals, you could use a timer and connect a slot to its timeout signal. However, if the slot does some heavy calculations, this could still block the gui - in which case, you should move the calculations into a worker thread, and send the updates back to the main thread via signal (see here for a simple example). Then again, if you only need a quick and dirty method for debugging, you could temporarily force gui updates using process-events. For example, the wait function in your example could be made to work like this:

       def wait(self, duration=2.0):
          qApp.processEvents() # clear current event queue
          time.sleep(duration) # this will block gui updates