【问题标题】:QStatusBar.showMessage() not updating consistentlyQStatusBar.showMessage() 没有持续更新
【发布时间】:2019-08-13 22:34:19
【问题描述】:

我的道歉:

这似乎与以下内容重复: PyQt - running a loop inside GUI

有很好的解决方案和教程链接。

我的设置:

操作系统:Windows 10 版本 1903

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

预期:点击“Debug”按钮,看到"Checkpoint ###"周期性地在状态栏中打印2秒,最后状态栏无限期显示“Completed debug()”。

实际:单击“调试”按钮,在 cmd 中查看来自wait() 的打印语句,但在"Completed debug()" 之前我看不到任何"Checkpoint ###" 更新。

  • 我尝试过使用内置的持续时间参数 statusBar.showMessage() 天真地。
  • 我已尝试使用 time.sleep(2)。
  • 我已尝试创建自己的等待方法,它不应像 sleep 那样暂停进程(以防碍事)。

我的下一步似乎是尝试利用“statusBar.messageChanged”信号,但这对于应该内置的东西来说感觉太多了。我想我错过了很明显但看不到的东西。

【问题讨论】:

  • 感谢@ekhumoro,我相信你是 100% 正确的。我也是在睡了一觉并和朋友讨论之后才意识到这一点的。感谢大家的有益回复!如果您将其列为答案,我可以将其标记为回答我的问题。

标签: python-3.x pyqt pyqt5 sleep qstatusbar


【解决方案1】:

您的示例不起作用,因为 wait 函数中的 while 循环将阻止 gui 并阻止状态栏更新。有几种不同的方法来处理这个问题。如果状态栏更新以固定间隔发生,您可以使用timer 并将插槽连接到其timeout signal。但是,如果插槽进行了一些繁重的计算,这仍然可能会阻塞 gui - 在这种情况下,您应该将计算移到工作线程中,并通过信号将更新发送回主线程(参见 here 一个简单的例子)。再说一次,如果您只需要一种快速而肮脏的调试方法,您可以使用process-events 临时强制进行 gui 更新。例如,您示例中的 wait 函数可以这样工作:

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

【讨论】:

  • GUI 不会更新,直到您从单击的函数返回。在您从 debug() 方法返回之前,不会发生 statusBar 更新。然后它一次处理所有statusBar.showMessage() 组件,每个组件都覆盖最后一个剩余时间,因此它只显示最后一条消息。我正在努力将多处理模块合并到一个更好的解决方案中。 :)
  • 嘿,对不起。我把你的答案和另一个人的答案搞混了。此外,看起来我在没有意识到的情况下就很糟糕地问了我的问题。我使用等待/睡眠函数作为运行时间较长的函数的替代。如果我希望我的程序不会停止,似乎我需要利用一个单独的进程,最好的情况是利用 PyQt 的 Signals & Slots。我最终试图更新 StatusBar 让用户知道事情正在发生,而不仅仅是在它发生时冻结 GUI。我将其重新标记为解决方案,再次感谢您的回复!
  • 想提一下,您实际上可以在self.statusBar.showMessage() 之后使用self.statusBar.repaint() 按钮单击后调用的任何函数内多次更新statusBar
【解决方案2】:

试试看:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-28
    • 2015-07-22
    • 2015-07-25
    • 2020-07-17
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    相关资源
    最近更新 更多