pyqt5处理多线程主要有三种方法:
- 使用计时器模块QTimer
- 使用多线程模块QThread
- 使用事件处理功能
QTimer相当于一个定时器,每当定时器时间溢出后,会执行相关的函数。这个时候程序会从主线程界面跳到QTimer函数中,如果QTimer函数中有延时或者处理时间较长,就会出现界面失去响应,造成界面卡顿的现象。
QThread等于新开一个线程专门处理耗时间的程序,UI主线程显示界面,当子线程处理好数据后通过自定义的信号与槽,将数据交给主线程刷新界面。由于UI主线程一直运行,子线程的延时,耗时程序与主线程无关,所以不会有卡顿的现象。
事件处理功能:相当于在耗时的程序中,主动刷新界面,使人觉得流畅。
使用QThread能够很好得完成UI与数据处理之间的关系。
通过QThread实现多线程
1.新建类Timer_thread(),继承QThread
2.自定义槽信号sinout(可以定义槽函数中接收参数类型,数字,文本,list等等)
3.重写run()函数,将线程需要执行的函数放在里面
4.在UI类中将Timer_thread实例化
5.通过.start()方法使线程执行,当线程数据处理完成后,通过信号与槽将数据发到槽函数中,槽函数处理数据并显示到界面中.
通过QTimer实现多线程
- 首先要实例化一个定时器QTimer
- 将定时器的timeout信号连接到对应的槽函数
- 最后通过.start()方法进行启动。
通过事件处理功能
这种方法不常用,主要原理是:在卡顿的地方使用:QtWidgets.QApplication.processEvents()去刷
新一下界面
'''
Description:
Version: 2.0
Autor: zxm
Date: 2021-11-16 00:57:57
LastEditors: zxm
LastEditTime: 2021-11-17 01:22:01
'''
"""
导入界面相关的模块和包
"""
from PyQt5 import QtCore, QtGui, QtWidgets
from test import Ui_MainWindow
import sys
from PyQt5.QtCore import QThread, QObject, QTimer, pyqtSignal, pyqtSlot
import datetime
import time
"""
新建一个类,并且继承QtWidgets.QMainWindow,以及
Ui文件中自动生成的类Ui_MainWindow
"""
class Test_win(QtWidgets.QMainWindow,Ui_MainWindow):
def __init__(self):
super(Test_win,self).__init__() # 父类初始化
self.setupUi(self) # 界面控件生成及布局
self.timethread = Time_thread()
self.timethread.sinout.connect(self.Refresh_label)
self.test_pushButton.clicked.connect(self.thread_start)
self.test_pushButton.clicked.connect(self.count_start)
self.countTimer = QTimer(self) # 实例化一个计时器
self.countTimer.timeout.connect(self.timeout_fun) # 将timeout与槽函数相连,计时器溢出时执行槽函数刷新界面
self.times = 0
def timeout_fun(self):
self.times += 1
# time.sleep(1) # 本质上QTimer的槽函数还是运行在界面UI主线程中,如果出现延时函数会出现卡顿现象,尽量不要在主线程中使用延时函数
self.count_label.setText(str(self.times)) # 刷新界面
def count_start(self):
self.countTimer.start(1000) # 开始计时,定时1s执行一次
def thread_start(self):
self.timethread.start()
def func(self): # 类的方法
print('hellow pyqt5!')
def Refresh_label(self,now_time):
self.test_label.setText(now_time)
class Time_thread(QThread):
sinout = pyqtSignal(str)
def __init__(self):
super(Time_thread,self).__init__()
print('Time_thread Start...')
def run(self):
while(True):
now = datetime.datetime.now()
str_time = str(now.hour) + ":" + str(now.minute) + ":" + str(now.second)
self.sinout.emit(str_time)
time.sleep(1)
def __del__(self):
print('Time_thread Over...')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Test_win() # 实例化一个类
win.show() # 类的方法,将界面显示出来
win.func() # 自定义类方法的调用
sys.exit(app.exec_())
最终实现点击按键后:
左边显示实时时间,1s中刷新一次,这个延时是在子线程中完成的,因此不会造成卡顿;
右边通过QTimer,1s钟刷新一次,延时是通过计时器来做的,但是在timeout连接到的槽函数不要使用延时函数,或者说在UI主线程中的代码不要有延时函数,否者会造成界面无响应卡顿。
界面代码
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.test_label = QtWidgets.QLabel(self.centralwidget)
self.test_label.setGeometry(QtCore.QRect(300, 210, 54, 12))
self.test_label.setObjectName("test_label")
self.test_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.test_pushButton.setGeometry(QtCore.QRect(350, 270, 75, 23))
self.test_pushButton.setObjectName("test_pushButton")
self.count_label = QtWidgets.QLabel(self.centralwidget)
self.count_label.setGeometry(QtCore.QRect(460, 210, 54, 12))
self.count_label.setObjectName("count_label")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 23))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.test_label.setText(_translate("MainWindow", "TIME"))
self.test_pushButton.setText(_translate("MainWindow", "TEST"))
self.count_label.setText(_translate("MainWindow", "计数"))
Ui文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="test_label">
<property name="geometry">
<rect>
<x>300</x>
<y>210</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>TIME</string>
</property>
</widget>
<widget class="QPushButton" name="test_pushButton">
<property name="geometry">
<rect>
<x>350</x>
<y>270</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>TEST</string>
</property>
</widget>
<widget class="QLabel" name="count_label">
<property name="geometry">
<rect>
<x>460</x>
<y>210</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>计数</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>