Pyqt5实现线程内更新窗口UI
我们用pyqt5开发窗口应用时,应用会执行一些耗时的操作,如复制大量文件,下载大量数据等。一般情况下,在这些操作没有完成时,窗口的UI处于“假死”状态,不会更新,只有所有操作完成后,窗口的状态才会更新。这样对用户使用非常不友好。
使用多线程技术,在新线程内进行那些耗时的操作,同时根据操作进度向主线程返回操作进度,根据进度更新窗口UI,可以实现更好的用户体验。
下面是用一个简单的例子说明实现过程。
一、程序界面:
程序界面如下:
本例中,窗口有一个按钮和一个多行文本框。点击按钮后开启新线程,进行耗时操作。在点击后修改按钮的状态为不可用,可以防止用户重复点击,新线程将完成进度返回给主线程,根据完成进度,更新文本框的内容用于显示完成进度。待操作全部完成后,新线程返回“全部完成”,主线程恢复按钮的状态为可用。
二、实现代码:
'''
code writing:hnkkfan
本例用于演示Pyqt5 在线程中更新UI控件
窗口中使用一个多行文本框QTextEdit,用于显示更新的处理线程进度
一个按钮QPushButton,点击开始后开始在新线程中处理耗时比较长的工作
为防止重复操作,在点击按钮后的处理过程中,按钮的状态变为不可用,
处理完成后,恢复状态为可用。
'''from PyQt5.Qt import(QApplication, QWidget, QPushButton,QThread,pyqtSignal)import sys
import time
from PyQt5.QtWidgets import QTextEdit, QHBoxLayout, QVBoxLayout
classThread_do(QThread):# 定义线程类
_signal =pyqtSignal(str)#定义带参数一个信号def__init__(self):super().__init__()defrun(self):#线程的执行方法for i inrange(20):
retInfo=f"开始处理第{i+1}个..."
time.sleep(0.5)#这个用休眠0.5秒代替我们需要执行的耗进代码
retInfo+="处理完成"
self._signal.emit(retInfo)#返回进度
self._signal.emit("全部完成")#循环结束后返回全部完成classMyWin(QWidget):def__init__(self):super().__init__()
self.txt_PressInfo = QTextEdit()# 定义一个处理信息文本框
self.btn_do = QPushButton('开始处理', self)#定义一个按钮
self.btn_do.clicked.connect(self.btn_click)# 绑定槽函数#定义两个水平布局,用于放置文本框和按钮
hbox_line1 = QHBoxLayout()
hbox_line1.addWidget(self.txt_PressInfo)
hbox_line2 = QHBoxLayout()
hbox_line2.addWidget(self.btn_do)#定义一个垂直布局用于放置两个水平布局
vbox = QVBoxLayout()
vbox.addLayout(hbox_line1)
vbox.addLayout(hbox_line2)# 添加上面的水平布局器
self.setLayout(vbox)# 把垂直布局器添加到窗口defbtn_click(self):#按钮的点击事件#点击后让按钮不可用,防止重复点击,并改变按钮文本为正在处理...
self.btn_do.setEnabled(False)
self.btn_do.setText("正在处理...")#定义线程实例
self.thread_do = Thread_do()# 信号连接,如果收到信号,就执行对应的函数
self.thread_do._signal.connect(self.set_btn_resig)#启动线程实例
self.thread_do.start()#定义收到信号的处理方法defset_btn_resig(self,_info):if _info=="全部完成":#如果返回值为全部完成则恢复按钮的状态和文本
self.btn_do.setEnabled(True)
self.btn_do.setText("开始处理")else:#否则在文本框中显示进度
self.txt_PressInfo.append(_info)if __name__ =="__main__":
app = QApplication(sys.argv)
myshow = MyWin()
myshow.setWindowTitle("多线程更新UI演示")
myshow.setMinimumHeight(480)
myshow.setMinimumWidth(640)
myshow.show()
sys.exit(app.exec_())
三、运行效果:
点击后,按钮不可用,并修改按钮文本为“正在处理…”。同时新线程不断向主线程返回进度,并更新文本框中的进度信息。
全部操作执行完毕后,新线程向主线程返回“全部完成”,主线程收到信息后,将按钮状态变为可用,并将按钮的文本改回“开始处理”
版权归原作者 hnkkfan 所有, 如有侵权,请联系我们删除。