PyQt5 - 从字符串列表中重复更新状态栏而不阻塞 gui
PyQt5 - repeatedly update status-bar from a list of strings without blocking the gui
我可以使用 QStatusBar
通过输入一个字符串来显示消息,例如:
self.statusBar().showMessage("My message here, also show it for 1 sec", 1000)
在我的事件循环中,上述消息将在状态栏上显示整整 1000 毫秒。但是说,我有一个字符串列表,而不是字符串 "My message here"
,我想一次显示一个。我可以通过 time.sleep(1)
给它一个延迟来通过循环来做到这一点——但不幸的是,这会阻塞 gui,直到循环结束,我不希望这样。我可以把主事件循环和状态栏更新的过程分开吗,如果可以,怎么做?
下面的示例代码有一个按钮,按下该按钮会生成存储在列表中的三个不同消息。然后它们显示在状态栏中,一次一个,并且在循环结束之前不能按下按钮。我想要的行为是该按钮是可点击的(gui 未被阻止),如果在显示之前的消息时点击它,则显示中断并显示新消息。
---下面的示例代码---
import sys
import time
from PyQt5 import QtWidgets
class Window(QtWidgets.QMainWindow):
"""Main Window."""
MSG_ID = 1
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
#stuff
self.messages = []
self.setWindowTitle('Main Window')
self.setStatusBar(QtWidgets.QStatusBar())
self.statusBar().showMessage("My message first time")
self.button = QtWidgets.QPushButton("Test",self)
self.button.clicked.connect(self.handleButton)
def handleButton(self):
self.messages = [f"message_num {msg_id}" for msg_id in range(Window.MSG_ID,Window.MSG_ID+3)]
Window.MSG_ID+=3
self.updateStatus()
print(self.messages)
def updateStatus(self):
self.statusBar().clearMessage()
for item in self.messages:
self.statusBar().showMessage(item,1000)
time.sleep(1.2)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
上面的代码创建了一个消息列表
不需要为此使用计时器或睡眠,因为状态栏会在每次临时消息更改(包括删除时)时发送 messageChanged signal。这可用于创建一个简单的回调循环来执行您想要的操作:
class Window(QtWidgets.QMainWindow):
...
def __init__(self, parent=None):
...
self.statusBar().messageChanged.connect(self.updateStatus)
def handleButton(self):
self.messages = [f"message_num {msg_id}" for msg_id in range(Window.MSG_ID,Window.MSG_ID+3)]
Window.MSG_ID+=3
self.updateStatus()
def updateStatus(self, message=None):
print('update-status:', (message, self.messages))
if not message and self.messages:
self.statusBar().showMessage(self.messages.pop(0), 1000)
这不会阻止 gui,并允许通过单击按钮随时重新启动消息序列。
我可以使用 QStatusBar
通过输入一个字符串来显示消息,例如:
self.statusBar().showMessage("My message here, also show it for 1 sec", 1000)
在我的事件循环中,上述消息将在状态栏上显示整整 1000 毫秒。但是说,我有一个字符串列表,而不是字符串 "My message here"
,我想一次显示一个。我可以通过 time.sleep(1)
给它一个延迟来通过循环来做到这一点——但不幸的是,这会阻塞 gui,直到循环结束,我不希望这样。我可以把主事件循环和状态栏更新的过程分开吗,如果可以,怎么做?
下面的示例代码有一个按钮,按下该按钮会生成存储在列表中的三个不同消息。然后它们显示在状态栏中,一次一个,并且在循环结束之前不能按下按钮。我想要的行为是该按钮是可点击的(gui 未被阻止),如果在显示之前的消息时点击它,则显示中断并显示新消息。
---下面的示例代码---
import sys
import time
from PyQt5 import QtWidgets
class Window(QtWidgets.QMainWindow):
"""Main Window."""
MSG_ID = 1
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
#stuff
self.messages = []
self.setWindowTitle('Main Window')
self.setStatusBar(QtWidgets.QStatusBar())
self.statusBar().showMessage("My message first time")
self.button = QtWidgets.QPushButton("Test",self)
self.button.clicked.connect(self.handleButton)
def handleButton(self):
self.messages = [f"message_num {msg_id}" for msg_id in range(Window.MSG_ID,Window.MSG_ID+3)]
Window.MSG_ID+=3
self.updateStatus()
print(self.messages)
def updateStatus(self):
self.statusBar().clearMessage()
for item in self.messages:
self.statusBar().showMessage(item,1000)
time.sleep(1.2)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
上面的代码创建了一个消息列表
不需要为此使用计时器或睡眠,因为状态栏会在每次临时消息更改(包括删除时)时发送 messageChanged signal。这可用于创建一个简单的回调循环来执行您想要的操作:
class Window(QtWidgets.QMainWindow):
...
def __init__(self, parent=None):
...
self.statusBar().messageChanged.connect(self.updateStatus)
def handleButton(self):
self.messages = [f"message_num {msg_id}" for msg_id in range(Window.MSG_ID,Window.MSG_ID+3)]
Window.MSG_ID+=3
self.updateStatus()
def updateStatus(self, message=None):
print('update-status:', (message, self.messages))
if not message and self.messages:
self.statusBar().showMessage(self.messages.pop(0), 1000)
这不会阻止 gui,并允许通过单击按钮随时重新启动消息序列。