这是一个基于PyQt的异步任务进度展示解决方案,主要解决在GUI应用中执行耗时任务时的。
主要解决两个问题:
核心设计包括:
优势:
适用于各类需要执行耗时操作的桌面应用场景,如文件处理、数据分析、网络请求等。
结果集设计
业务回调函数设计
方便后续统一处理结果
# 定义一个结果集
class Result:
def __init__(self, success: bool, data: Any = None, error: str = ""):
self.success = success
self.data = data
self.error = error
@classmethod
def ok(cls, data: Any = None) -> 'Result':
return cls(True, data)
@classmethod
def fail(cls, error: str) -> 'Result':
return cls(False, error=error)
# service.py
def service_function(progress_callback):
''' 执行业务,并带有进度回调函数,函数会传入两个参数,(该进度的最大值,预估时间)max_value, estimate_time '''
progress_callback(10,1000)
# 执行阶段1
# ....
progress_callback(50,5000)
# 执行阶段2
# ....
progress_callback(100,15000)
# 执行阶段3
# ....
# 成功
res=Result.ok(data)
# 失败
res=Result.fail(error_msg)
return res
在ptqy种,耗时任务可以使用Qthread去执行,需要注意的是:
worker干什么? |
---|
它在子线程执行耗时任务,利用信号与槽机制和主线程通信。 |
执行的是什么类型的任务? |
耗时,可以传回调函数(上面设计的那种),返回的结果是Result类型的。 |
worker怎么和主线程通信? |
把任务执行的结果利用信号与槽发送出去,把任务中调用回调函数开启进度条的信号也发送出去。 |
class Worker(QThread):
success = pyqtSignal()
error = pyqtSignal(str) # 错误信号
start_progress = pyqtSignal(int, int) # 开始进度条信号(一个是max值,一个是预计时间)
def __init__(self, function):
super().__init__()
self.function = function
def run(self):
try:
# 开始执行-------------
res = self.function(self.progress_callback)
if res.success:
# 结束:------------
self.success.emit() # 发生结束信号
else:
self.error.emit(res.error)
except Exception as e:
# 统一异常处理 .....
# 定义回调函数,直接把信号发出去,让主线程去处理
def progress_callback(self, max_value, estimated_time):
"""
max_value: 当前阶段的最大占比 例子:10(最多是100)
estimated_time: 这个阶段的预计时间 例子:1000ms
"""
self.start_progress.emit(max_value, estimated_time) # 发送信号到外头
代码如下:
# MyWindow - init方法
# 设置定时器用于更新进度条
self.timer_progress = QTimer(self)
self.timer_progress.timeout.connect(self.update_progress_ui)
self._progress_max_value = 0 # 记录进度条的最大值
# MyWindow.py
def update_progress_ui(self):
"""更新进度条UI"""
try:
current_value = self.customProgressBar.value()
next_value = min(current_value + 1, self._progress_max_value -1)
self.customProgressBar.setValue(next_value)
# 检查是否需要停止定时器
if next_value >= self._progress_max_value - 1:
self.timer_progress.stop()
except Exception as e:
self.logger.error(f"更新进度条失败: {e}")
self.timer_progress.stop()
# MyWindow.py
def start_progress_from_current_progress(self, max_value, estimated_time):
"""启动进度定时器"""
try:
current_value = self.customProgressBar.value()
if current_value >= max_value:
return
# 停止现有定时器
if self.timer_progress.isActive():
self.timer_progress.stop()
# 设置进度参数
self._progress_max_value = max_value
remaining_progress = max_value - current_value
if remaining_progress <= 0:
return
# 计算间隔时间
interval_time = max(1, int(estimated_time / remaining_progress))
# 启动定时器
self.timer_progress.setInterval(interval_time)
self.timer_progress.start()
except Exception as e:
self.logger.error(f"启动进度定时器失败: {e}")
self.show_error_ui("Progress timer error")
# MyWindow.py
def init_progress_ui(self):
# 其他 ui 操作....
self.customProgressBar.setValue(0)
# MyWindow.py
def success_progress_ui(self):
self.timer_progress.stop()
self.customProgressBar.setValue(100)
# MyWindow.py
def stop_progress_ui(self):
self.timer_progress.stop()
页面按钮绑定任务执行
运行方法:
代码如下:
# MyWindow - init方法
self.btn.clicked.connect(self.run_function)
# MyWindow.py
def run_function(self):
# 任务执行前处理
self.pre_process()
# 创建worker !!这里的任务是后端业务来的!!
worker = Worker(service_function)
# 连接worker信号
worker.success.connect(self.worker_success_handle)
worker.error.connect(lambda msg: self.worker_error_handle(msg))
worker.start_progress.connect(self.start_progress_from_current_progress)
# 开始执行业务
worker.start()
# MyWindow.py
def worker_success_handle(self):
try:
# 进度条成功
self.success_progress_ui()
# 清理工作
self.post_process()
except Exception as e:
self.show_error_ui(str(e))
# MyWindow.py
def worker_error_handle(self, error_message):
try:
# 显示错误
self.show_error_ui(error_message)
# 进度条停止
self.stop_progress()
# 清理工作
self.post_process()
except Exception as e:
# 确保最基本的错误提示能显示
print(f"Error handling failed: {str(e)}")
# MyWindow.py
def pre_process(self):
# 禁用按钮
self.disable_buttons()
# 进度条初始话
self.init_progress_ui()
# 其他...
# MyWindow.py
def post_process(self):
# 停止计时器
if self.timer_progress.isActive():
self.timer_progress.stop()
# 启用按钮
self.enable_buttons()
# 其他...
整个框架设计的核心思想:
希望能帮助到大家!!!!