pyqt QLabel 在另一个线程更新其文本时未呈现
Posted
技术标签:
【中文标题】pyqt QLabel 在另一个线程更新其文本时未呈现【英文标题】:pyqt QLabel not rendered while another thread update its text 【发布时间】:2016-10-12 18:05:54 【问题描述】:我有一个基于 PyQt5 构建的 GUI 程序,它不断接收消息。 GUI 有一个 QLabel 显示接收到的消息数量,还有一个 QThread 试图在 run() 的无限循环中接收消息并更新计数器。代码如下:
class ReceiveThread(QtCore.QThread):
def __init__(self, parent, dialog, config):
super(BufRecvThread, self).__init__(parent)
#here dialog is the QDialog which contains the QLabel showing the message counter
self.dialog=dialog
self.toStop=False
def run(self):
bufRecvCnt=0
while not self.toStop:
recv_buff=sock.recvMessage()
bufRecvCnt=bufRecvCnt+1
#self.dialog.lbBufRecvCnt is the QLabel showing the message counter
self.dialog.lbBufRecvCnt.setText(str(bufRecvCnt))
QApplication.processEvents() #this statement has no effect
但是,大多数时候,我发现 GUI 中的 QLabel 无法正确呈现计数器,例如,ReceiveThread 已收到 10000 条消息并在 sock.recvMessage() 处阻塞,QLabel 仍然显示“500”,直到我手动调整了 GUI 的大小,导致 GUI 重新呈现。
我尝试了这个线程 pyqt QtGraphicsView does not get updated within loop 的建议,并将 QApplication.processEvents() 添加到循环中,但仍然不起作用。
那么,从另一个线程直接更新 GUI 是否合适? PyQt - Modify GUI from another thread 建议发出信号。由于我不熟悉信号和插槽,我应该使用 QLabel 的预定义信号,还是可以根据需要定义任何信号,只要相应的插槽将使用 setText() 更新 QLabel 的文本。
【问题讨论】:
【参考方案1】:只有主 GUI 线程可以更新 GUI。您不应该直接与主线程之外的 GUI 对象进行交互。如果想从工作线程与主线程通信,需要使用Signals
和Slots
class Dialog(QtGui.QDialog):
def __init__(self, parent):
super(Dialog, self).__init__(parent)
...
self.thread = ReceiveThread(self)
self.thread.message_received.connect(self.handle_message)
@QtCore.pyqtSlot(str)
def handle_message(self, message):
self.lbBufRecvCnt.setText(message)
class ReceiveThread(QtCore.QThread):
message_received = QtCore.pyqtSignal(str)
def __init__(self, parent, config):
super(ReceiveThread, self).__init__(parent)
self.toStop = False
def run(self):
bufRecvCnt=0
while not self.toStop:
recv_buff = sock.recvMessage()
bufRecvCnt = bufRecvCnt + 1
self.message_received.emit(str(bufRecvCnt))
【讨论】:
以上是关于pyqt QLabel 在另一个线程更新其文本时未呈现的主要内容,如果未能解决你的问题,请参考以下文章
PyQt5常用控件大全(详尽方法 + 实例操作,持续更新中…)