QThread的要点讲解
在PyQt5中,
QThread
类提供了一种方便的方式来实现多线程。多线程允许我们在应用程序中执行一些耗时的任务,而不会阻塞主线程,从而保持用户界面的响应性。下面是关于PyQt5中多线程QThread
的一些要点:
创建子类: 通常,我们会创建一个继承自QThread
的子类,该子类将包含我们希望在独立线程中执行的任务。这个子类可以包含信号,以便在线程中定期发送消息或结果给主线程。
from PyQt5.QtCore import QThread, pyqtSignal
class WorkerThread(QThread):
update_signal = pyqtSignal(str)
def run(self):
# 在这里执行耗时任务
self.update_signal.emit("任务完成")
-
重写
run
方法: 在QThread
的子类中,我们需要重写run
方法。run
方法包含了在线程中实际执行的任务。在这个例子中,我们发射了一个信号来通知任务完成。 -
使用信号和槽进行通信: 由于线程不能直接访问GUI元素,我们需要使用信号和槽机制来进行线程间通信。在上面的例子中,
update_signal
信号用于在工作线程中发射消息,而在主线程中我们可以连接这个信号到一个槽函数,以处理这个消息。
worker = WorkerThread()
worker.update_signal.connect(main_window.handle_update)
启动和管理线程: 一旦创建了QThread
的子类实例,我们可以通过调用start
方法来启动线程。通常,我们会在主线程中创建线程实例,并在需要时启动它们。线程的生命周期应该由我们负责管理,包括在适当的时机停止线程。
移动到线程中:
thread = QThread()
my_object = MyObject() # 自定义的类,可能包含一些耗时任务
my_object.moveToThread(thread)
thread.started.connect(my_object.run)
thread.start()
moveToThread
方法用于将一个对象移到特定的线程中。started
信号表示线程已经启动,连接到需要在线程中执行的方法。
安全终止线程: 在终止线程时,最好使用一种安全的方式。在上述例子中,我们使用了terminate
方法,但这不是最佳实践。更好的方式是通过设置一个标志位,在线程的run
方法中检查这个标志位,并在需要时退出线程。
QThread
为我们提供了一个方便的方式来在PyQt5中处理多线程,通过信号和槽机制,可以实现主线程和工作线程之间的通信,从而有效地管理应用程序中的异步任务。在使用多线程时,确保遵循最佳实践,以避免潜在的线程安全问题。
多进度条案例详解
Worker类详解
class Worker(QObject):
update_progress_signal = pyqtSignal(int)
def __init__(self, index):
super().__init__()
self.index = index
self.progress_value = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_progress)
def start_progress(self):
self.timer.start(100)
def pause_progress(self):
self.timer.stop()
def update_progress(self):
self.progress_value += 1
if self.progress_value > 100:
self.progress_value = 0
self.update_progress_signal.emit(self.progress_value)
-
class Worker(QObject):
:定义一个名为Worker
的类,继承自QObject
。这是一个用于执行工作的类,通过多线程运行。 -
update_progress_signal = pyqtSignal(int)
:在Worker
类中创建一个信号,用于在工作线程中发送更新的进度值给主线程。 -
def __init__(self, index):
:Worker
类的构造函数,接收一个参数index
,表示工作线程的索引。 -
super().__init__()
:调用父类的构造函数。 -
self.index = index
:将传入的索引保存在实例变量self.index
中,以便在工作线程中使用。 -
self.progress_value = 0
:初始化一个实例变量self.progress_value
用于存储进度值,初始值为0。 -
self.timer = QTimer(self)
:创建一个QTimer
对象,用于定期触发timeout
信号,以便更新进度。 -
self.timer.timeout.connect(self.update_progress)
:将timeout
信号连接到update_progress
方法,表示每次定时器超时时都会执行update_progress
方法。 -
def start_progress(self):
:开始进度的方法。调用该方法会启动定时器,使其每100毫秒触发一次timeout
信号。 -
def pause_progress(self):
:暂停进度的方法。调用该方法会停止定时器,使其不再触发timeout
信号。 -
def update_progress(self):
:更新进度的方法,由定时器触发。每次调用该方法,进度值加1,如果超过100,则重置为0,并通过发射信号update_progress_signal
将更新后的进度值发送给主线程。 -
self.update_progress_signal.emit(self.progress_value)
:通过emit
方法发射update_progress_signal
信号,将当前的进度值发送给主线程。 -
ProgressBarExample类详解
-
class ProgressBarExample(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.progress_bars = [QProgressBar(self), QProgressBar(self), QProgressBar(self)] self.start_buttons = [QPushButton('开始', self), QPushButton('开始', self), QPushButton('开始', self)] self.pause_buttons = [QPushButton('暂停', self), QPushButton('暂停', self), QPushButton('暂停', self)] self.layout = QVBoxLayout() for progress_bar, start_button, pause_button in zip(self.progress_bars, self.start_buttons, self.pause_buttons): self.layout.addWidget(progress_bar) self.layout.addWidget(start_button) self.layout.addWidget(pause_button) self.setLayout(self.layout) self.threads = [QThread() for _ in range(3)] self.workers = [Worker(i) for i in range(3)] for thread, worker, start_button, pause_button, progress_bar in zip( self.threads, self.workers, self.start_buttons, self.pause_buttons, self.progress_bars): worker.moveToThread(thread) start_button.clicked.connect(worker.start_progress) pause_button.clicked.connect(worker.pause_progress) worker.update_progress_signal.connect(lambda value, pb=progress_bar: self.update_progress(pb, value)) thread.start() self.setGeometry(300, 300, 300, 300) self.setWindowTitle('多线程进度条示例') self.show() def update_progress(self, progress_bar, value): progress_bar.setValue(value)
-
class ProgressBarExample(QWidget):
:定义一个名为ProgressBarExample
的类,继承自QWidget
,表示主窗口。 -
def __init__(self):
:ProgressBarExample
类的构造函数。 -
super().__init__()
:调用父类的构造函数,确保正确初始化窗口。 -
self.initUI()
:调用initUI
方法,用于初始化用户界面。 -
def initUI(self):
:ProgressBarExample
类的初始化用户界面方法。 -
self.progress_bars = [QProgressBar(self), QProgressBar(self), QProgressBar(self)]
:创建一个包含3个QProgressBar
控件的列表,表示3个进度条。 -
self.start_buttons = [QPushButton('开始', self), QPushButton('开始', self), QPushButton('开始', self)]
:创建一个包含3个QPushButton
控件的列表,表示3个开始按钮。 -
self.pause_buttons = [QPushButton('暂停', self), QPushButton('暂停', self), QPushButton('暂停', self)]
:创建一个包含3个QPushButton
控件的列表,表示3个暂停按钮。 -
self.layout = QVBoxLayout()
:创建一个垂直布局管理器。 -
for progress_bar, start_button, pause_button in zip(self.progress_bars, self.start_buttons, self.pause_buttons):
:使用zip
函数将进度条、开始按钮和暂停按钮进行配对。 -
self.layout.addWidget(progress_bar)
:将进度条添加到垂直布局中。 -
self.layout.addWidget(start_button)
:将开始按钮添加到垂直布局中。 -
self.layout.addWidget(pause_button)
:将暂停按钮添加到垂直布局中。 -
self.setLayout(self.layout)
:将垂直布局设置为窗口的主布局。 -
self.threads = [QThread() for _ in range(3)]
:创建一个包含3个QThread
的列表,用于处理多线程操作。 -
self.workers = [Worker(i) for i in range(3)]
:创建一个包含3个Worker
的列表,每个Worker
代表一个工作线程。 -
for thread, worker, start_button, pause_button, progress_bar in zip(self.threads, self.workers, self.start_buttons, self.pause_buttons, self.progress_bars):
:通过zip
函数将线程、工作线程、开始按钮、暂停按钮和进度条进行配对。 -
worker.moveToThread(thread)
:将每个Worker
移动到相应的线程中。 -
start_button.clicked.connect(worker.start_progress)
:连接开始按钮的点击信号到相应Worker
的开始进度方法。 -
pause_button.clicked.connect(worker.pause_progress)
:连接暂停按钮的点击信号到相应Worker
的暂停进度方法。 -
worker.update_progress_signal.connect(lambda value, pb=progress_bar: self.update_progress(pb, value))
:连接工作线程的更新进度信号到主窗口的update_progress
方法,以更新相应的进度条。 -
thread.start()
:启动每个线程。 -
self.setGeometry(300, 300, 300, 300)
:设置窗口的位置和大小。 -
self.setWindowTitle('多线程进度条示例')
:设置窗口的标题。 -
self.show()
:显示窗口。 -
def update_progress(self, progress_bar, value):
:主窗口中用于更新进度条的方法。接收进度条和新的值,并将新值设置到相应的进度条上。 -
progress_bar.setValue(value)
:设置进度条的当前值。 -
完整代码
-
import sys from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal, QObject from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QProgressBar class Worker(QObject): update_progress_signal = pyqtSignal(int) def __init__(self, index): super().__init__() self.index = index self.progress_value = 0 self.timer = QTimer(self) self.timer.timeout.connect(self.update_progress) def start_progress(self): self.timer.start(100) def pause_progress(self): self.timer.stop() def update_progress(self): self.progress_value += 1 if self.progress_value > 100: self.progress_value = 0 self.update_progress_signal.emit(self.progress_value) class ProgressBarExample(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.progress_bars = [QProgressBar(self), QProgressBar(self), QProgressBar(self)] self.start_buttons = [QPushButton('开始', self), QPushButton('开始', self), QPushButton('开始', self)] self.pause_buttons = [QPushButton('暂停', self), QPushButton('暂停', self), QPushButton('暂停', self)] self.layout = QVBoxLayout() for progress_bar, start_button, pause_button in zip(self.progress_bars, self.start_buttons, self.pause_buttons): self.layout.addWidget(progress_bar) self.layout.addWidget(start_button) self.layout.addWidget(pause_button) self.setLayout(self.layout) self.threads = [QThread() for _ in range(3)] self.workers = [Worker(i) for i in range(3)] for thread, worker, start_button, pause_button, progress_bar in zip( self.threads, self.workers, self.start_buttons, self.pause_buttons, self.progress_bars): worker.moveToThread(thread) start_button.clicked.connect(worker.start_progress) pause_button.clicked.connect(worker.pause_progress) worker.update_progress_signal.connect(lambda value, pb=progress_bar: self.update_progress(pb, value)) thread.start() self.setGeometry(300, 300, 300, 300) self.setWindowTitle('多线程进度条示例') self.show() def update_progress(self, progress_bar, value): progress_bar.setValue(value) if __name__ == '__main__': app = QApplication(sys.argv) ex = ProgressBarExample() sys.exit(app.exec_())
本期的PyQt的程序案例就分享到这了!后期会更新更多PyQt的程序!感谢支持!有什么想看的程序在评论区留言!