QStatusBar.showMessage() не обновляется последовательно

МОИ ИЗВЕНЕНИЯ:

Это кажется дубликатом: PyQt - запуск цикла внутри GUI

У которого есть хорошее решение и учебная ссылка.

Моя настройка:

ОС: Windows 10 ver1903

Python: 3.7.4

PyQt5: 5.13.0

Моя проблема:

PyQt5 не обновляет строку состояния последовательно. Я вижу эту проблему в большем приложении. Я написал это приложение для отладки, чтобы попытаться определить проблему более четко, и оно воспроизвело:

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()

ОЖИДАЕМЫЙ: Нажмите кнопку "Отладка" и увидите "Checkpoint ###" Периодически печатается в строке состояния в течение 2 секунд, заканчиваясь неопределенным отображением строки состояния "Completed debug()".

АКТУАЛЬНО: Нажмите кнопку "Отладка", см. Операторы печати из wait() в CMD, но я не вижу ни одного из "Checkpoint ###" обновления до "Completed debug()",

  • Я попытался с помощью встроенного аргумента длительности statusBar.showMessage() наивно.
  • Я пытался использовать time.sleep(2).
  • Я попытался создать свой собственный метод ожидания, который не должен приостанавливать процесс, как сон (в случае, если это мешает).

Я нахожусь в точке, где, кажется, следующим шагом является попытка использовать сигнал "statusBar.messageChanged", но это кажется слишком большим для чего-то, что должно быть встроено. Я полагаю, что упускаю что-то очевидное, но не могу видеть это.

2 ответа

Решение

Ваш пример не работает, потому что цикл while в wait Функция заблокирует графический интерфейс и предотвратит обновление строки состояния. Есть несколько разных способов решения этой проблемы. Если обновления строки состояния происходят через фиксированные интервалы, вы можете использовать таймер и подключить слот к его сигналу тайм-аута. Однако, если слот выполняет некоторые тяжелые вычисления, это все равно может заблокировать графический интерфейс - в этом случае вы должны переместить вычисления в рабочий поток и отправить обновления обратно в основной поток через сигнал (см. Простой пример здесь), Опять же, если вам нужен только быстрый и грязный метод для отладки, вы можете временно принудительно обновлять графический интерфейс, используя события процесса. Например, wait Функцию в вашем примере можно заставить работать так:

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

Попробуй:

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)

        self.msgs = ["Checkpoint 001", "Checkpoint 002", "Checkpoint 003", "Completed debug()"] # +
        self.n = len(self.msgs)                                                                 # +
        self.i = 0                                                                              # +

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

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

        self.timer = QTimer(self)                                                               # +
        self.timer.setInterval(2000)                             
        self.timer.timeout.connect(self.show_message)

    def show_message(self):
        self.statusBar.showMessage(self.msgs[self.i])
        self.i += 1
        if self.i == self.n: 
            self.timer.stop()
            self.i = 0

    def debug(self):
        self.timer.start()


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


if __name__ == '__main__':
    main()

Другие вопросы по тегам