当前位置 主页 > 网站技术 > 代码类 >

    浅谈PyQt5中异步刷新UI和Python多线程总结

    栏目:代码类 时间:2019-12-13 18:07

    目前任务需要做一个界面程序,PyQt是非常方便的选择,QT丰富的控件以及python方便的编程。近期遇到界面中执行一些后台任务时界面卡死的情况,解决了在这里记录下。

    PyQt

    PyQt简介

    PyQt是Qt的python接口,PyQt的文档较少,但接口和函数可以完全参照Qt,继承了Qt中大量的控件以及信号机制,十分方便。以下简介一个基本的PyQt程序。

    - 需要导入的类主要来自三个包

    - from PyQt5.QtWidgets import 常用的控件

    - PyQt5.QtCore 核心功能类,如QT,QThread,pyqtSignal

    - PyQt5.QtGui UI类,如QFont

    - 基础的程序结构:

    class Example(QWidget):
     def __init__(self):
      super()__init__()
      self.setupUI()
    
     def setupUI():
      self.show()
      pass
      # 设置UI
    if __name__ == '__main__':
     app = QApplication(sys.argv) # 启动app
     ex = Example() # 实例化一个自己派生的
     # 也可以实例化库中的控件
     # q = QPushButton()
     # q.show()
     sys.exit(app.exec_())
    

    总体来说:

    1. 首先实例化APP

    2. 实例化预定义控件或者自己派生自库中的控件,记得调用show()函数

    3. 执行并安全退出

    Python中的多线程

    python中的多线程使用较为方便,主要使用threading.Thread类:

    1. 线程启动使用start()函数

    2. 如果需要等待线程执行使用join,这样主线程会阻塞

    实现方式一

    直接传入函数,启动线程,可以传入参数

    import time, threading
    def threadFunction():
     while True:
      print(11111)
      time.sleep()
    # 用于命名,可以通过threading.current_thread().name获得
    t = threading.Thread(target=threadFunction, name='funciton')
    # 如果线程有参数
    t = threading.Thread(target=threadFunction, args=(), name='funciton')
    t.start()

    实现方式二

    继承Thread,重写run方法

    from threading import Thread
    import time
    
    class Example(Thread):
     def __init__(self):
      super().__init__()
    
     def run(self):
      while True:
       time.sleep(1)
       print(11111111)
    
    if __name__ == '__main__':
     a = Example()
     a.start()
     a.join()
     print(222222222)
    

    注意:

    1. 使用join方法会让主线程阻塞在这里,等待子线程结束,在里面可以设置阻塞的时间

    2. a.setDaemon(True)在start前设置,可以保证在主线程终止时,子线程也终止

    信号机制

    QT中的信号机制能够方便的编写回调。

    1. 很多控件都有预定的信号如clicked,直接使用clicked.connect连接槽函数即可。

    2. 继承自Qt的类,然后自定义一个signal类变量,在实例连接信号就可以了

    class Example(QWidget):
     signal = pyqtSignal() # 括号里填写信号传递的参数
     # 发射信号
     def func(self):
      self.signal.emit()
    
    # 使用信号
    a = Example()
    a.signal.connect(callback)
    
    # 槽函数
    def callback():
     pass
    

    UI刷新

    在界面中,通常用会有一些按钮,点击后触发事件,比如去下载一个文件或者做一些操作,这些操作会耗时,如果不能及时结束,主线程将会阻塞,这样界面就会出现未响应的状态,因此必须使用多线程来解决这个问题。

    注意:

    1. PyQt5不能在子线程中刷新线程,这样会造成界面卡死,因此不能使用常规的多线程刷新UI。