Python+PyQT5多线程实现UI更新的原理和实现步骤:
为什么需要使用多线程进行UI更新
在 PyQT5 中,所有的UI操作都在主线程中执行,如果在主线程中进行耗时操作,就会导致UI界面的卡顿,甚至出现假死的情况,给用户的使用带来不好的体验。因此,我们需要在不阻塞UI界面的情况下,进行耗时操作,使用多线程的方式,将耗时操作放在子线程中执行。
实现步骤
- 创建线程类,在其中编写耗时操作。需要注意的是,在耗时操作执行完之后,需要通过信号(signal)告诉主线程需要更新UI。
示例代码:
from PyQt5.QtCore import QThread, pyqtSignal
class WorkThread(QThread):
update_signal = pyqtSignal(str)
def __init__(self):
super(WorkThread, self).__init__()
def run(self):
name = self.get_name()
self.update_signal.emit(name)
def get_name(self):
# 模拟耗时操作
import time
time.sleep(3)
return 'Jack'
- 在主线程中创建一个子线程对象,并连接子线程的信号和槽。
示例代码:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.work_thread = WorkThread()
self.work_thread.update_signal.connect(self.update_name_label)
def update_name_label(self, name):
self.ui.name_label.setText(name)
- 启动子线程。
示例代码:
self.work_thread.start()
- 在连接子线程信号和槽的函数中,更新UI。注意在更新UI时要使用
QMetaObject
的invokeMethod
方法,将更新UI的函数加入到主线程消息队列中,从而在主线程执行更新操作。
示例代码:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 省略部分代码
self.move_button.clicked.connect(self.start_update_name_thread)
self.work_thread.update_signal.connect(self.update_name_label)
def start_update_name_thread(self):
self.work_thread.start()
def update_name_label(self, name):
# 将更新label的函数加入到主线程的消息队列中,由主线程执行
QMetaObject.invokeMethod(self.ui.name_label, 'setText', Qt.QueuedConnection, Q_ARG(str, name))
示例说明
示例一: 在子线程中执行一个函数,并将结果通过信号传递到主线程更新UI。
以下示例代码创建一个WorkThread
线程类,其中的get_name
函数模拟一个耗时操作,在其中休眠3秒,并返回一个字符串。当子线程执行完毕时,通过信号将获取到的字符串传递给主线程,在主线程中更新UI。
from PyQt5.QtCore import QThread, pyqtSignal, QMetaObject
class WorkThread(QThread):
update_signal = pyqtSignal(str)
def __init__(self):
super(WorkThread, self).__init__()
def run(self):
name = self.get_name()
self.update_signal.emit(name)
def get_name(self):
# 模拟耗时操作
import time
time.sleep(3)
return 'Jack'
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 省略部分代码
# 创建子线程对象
self.work_thread = WorkThread()
# 连接信号和槽
self.work_thread.update_signal.connect(self.update_name_label)
def start_update_name_thread(self):
'''
按钮点击事件,启动子线程
'''
self.work_thread.start()
def update_name_label(self, name):
'''
更新UI函数
'''
# 将更新label的函数加入到主线程的消息队列中,由主线程执行
QMetaObject.invokeMethod(self.ui.name_label, 'setText', Qt.QueuedConnection, Q_ARG(str, name))
示例二: 在子线程中执行多个函数,并将最终结果通过信号传递到主线程更新UI。
以下示例代码创建一个WorkThread
线程类,其中的get_name
函数模拟一个耗时操作,在其中休眠3秒,并返回一个字符串。当子线程执行完毕时,通过信号将获取到的字符串传递给主线程,在主线程中更新UI。
from PyQt5.QtCore import QThread, pyqtSignal, QMetaObject
class WorkThread(QThread):
update_signal = pyqtSignal(str)
def __init__(self):
super(WorkThread, self).__init__()
def run(self):
name = self.get_name()
age = self.get_age()
# 将结果组合成一个字符串
result_str = f"姓名:{name};年龄:{age}"
self.update_signal.emit(result_str)
def get_name(self):
# 模拟耗时操作
import time
time.sleep(3)
return 'Jack'
def get_age(self):
# 模拟耗时操作
import time
time.sleep(2)
return '18'
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 省略部分代码
# 创建子线程对象
self.work_thread = WorkThread()
# 连接信号和槽
self.work_thread.update_signal.connect(self.update_info_label)
def start_update_info_thread(self):
'''
按钮点击事件,启动子线程
'''
self.work_thread.start()
def update_info_label(self, info):
'''
更新UI函数
'''
# 将更新label的函数加入到主线程的消息队列中,由主线程执行
QMetaObject.invokeMethod(self.ui.info_label, 'setText', Qt.QueuedConnection, Q_ARG(str, info))
以上为Python+PyQT5的子线程更新UI界面的实例的详细讲解,希望能够帮到你。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python+PyQT5的子线程更新UI界面的实例 - Python技术站