Pyqt5实现新线程更新窗口UI

Pyqt5实现线程内更新窗口UI

我们用pyqt5开发窗口应用时,应用会执行一些耗时的操作,如复制大量文件,下载大量数据等。一般情况下,在这些操作没有完成时,窗口的UI处于“假死”状态,不会更新,只有所有操作完成后,窗口的状态才会更新。这样对用户使用非常不友好。
使用多线程技术,在新线程内进行那些耗时的操作,同时根据操作进度向主线程返回操作进度,根据进度更新窗口UI,可以实现更好的用户体验。

下面是用一个简单的例子说明实现过程。

一、程序界面:

程序界面如下:
Pyqt5实现新线程更新窗口UI_第1张图片

本例中,窗口有一个按钮和一个多行文本框。点击按钮后开启新线程,进行耗时操作。在点击后修改按钮的状态为不可用,可以防止用户重复点击,新线程将完成进度返回给主线程,根据完成进度,更新文本框的内容用于显示完成进度。待操作全部完成后,新线程返回“全部完成”,主线程恢复按钮的状态为可用。

二、实现代码:

'''
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


class Thread_do(QThread):  # 定义线程类
    _signal =pyqtSignal(str)#定义带参数一个信号
    def __init__(self):
        super().__init__()

    def run(self):#线程的执行方法
        for i in range(20):
            retInfo=f"开始处理第{i+1}个..."
            time.sleep(0.5)#这个用休眠0.5秒代替我们需要执行的耗进代码
            retInfo+="处理完成"
            self._signal.emit(retInfo)#返回进度
        self._signal.emit("全部完成")#循环结束后返回全部完成

class MyWin(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)  # 把垂直布局器添加到窗口
    def btn_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()

    #定义收到信号的处理方法
    def set_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_())

三、运行效果:

点击后,按钮不可用,并修改按钮文本为“正在处理…”。同时新线程不断向主线程返回进度,并更新文本框中的进度信息。
Pyqt5实现新线程更新窗口UI_第2张图片

全部操作执行完毕后,新线程向主线程返回“全部完成”,主线程收到信息后,将按钮状态变为可用,并将按钮的文本改回“开始处理”
Pyqt5实现新线程更新窗口UI_第3张图片

你可能感兴趣的:(python,qt,ui,开发语言,python)