init
This commit is contained in:
723
docs/content/38-jin-du-tiao-shi-yong-zhi-nan.md
Normal file
723
docs/content/38-jin-du-tiao-shi-yong-zhi-nan.md
Normal file
@@ -0,0 +1,723 @@
|
||||
进度条是向用户反馈长时间操作进度的关键交互组件,它能让用户清晰了解任务的执行状态,提升用户体验。本指南将系统讲解如何在 SunvStation 脚本中高效使用进度条功能,涵盖基础用法、高级技巧和最佳实践。
|
||||
|
||||
在学习本页内容后,建议按照以下路径继续深入:
|
||||
- [配置日志记录器](37-pei-zhi-ri-zhi-ji-lu-qi) — 了解日志记录的配置方法,与进度条配合使用
|
||||
- [错误处理与异常管理](39-cuo-wu-chu-li-yu-yi-chang-guan-li) — 掌握进度条操作中的错误处理
|
||||
- [批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku) — 查看进度条在实际批量操作中的应用
|
||||
|
||||
## 进度条系统架构概览
|
||||
|
||||
SunvStation 的进度条功能采用**分层架构设计**,通过 `ProgressMixin` 混入类与 SSProcessManager 集成,结合底层 C++ 封装的 `Progress` 类和进度条控制函数,形成完整的三层架构体系。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProgressAware {
|
||||
<<抽象基类>>
|
||||
+disable_progress()*
|
||||
+startProgress(title, total)*
|
||||
+stepProgress(message)*
|
||||
+closeProgress()*
|
||||
}
|
||||
|
||||
class ProgressMixin {
|
||||
+enable_progress: bool
|
||||
+progress: Progress
|
||||
+disable_progress()
|
||||
+startProgress(title, total)
|
||||
+stepProgress(message)
|
||||
+closeProgress()
|
||||
}
|
||||
|
||||
class SSProcessManager {
|
||||
+enable_progress: bool
|
||||
+progress: Progress
|
||||
+startProgress(title, total)
|
||||
+stepProgress(message)
|
||||
+closeProgress()
|
||||
}
|
||||
|
||||
class Progress {
|
||||
<<C++封装类>>
|
||||
+setSize(nSize)
|
||||
+step() boolean
|
||||
+getPos() int
|
||||
+getStep() int
|
||||
}
|
||||
|
||||
class GlobalFunctions {
|
||||
<<函数模块>>
|
||||
+startProgress(title, barCount)
|
||||
+closeProgress()
|
||||
+setProgressRange(min, max)
|
||||
+stepProgress(pos, title)
|
||||
}
|
||||
|
||||
ProgressAware <|-- ProgressMixin
|
||||
ProgressMixin <|-- SSProcessManager
|
||||
ProgressMixin ..> Progress : 使用
|
||||
ProgressMixin ..> GlobalFunctions : 调用
|
||||
```
|
||||
|
||||
这种架构设计的核心优势在于**关注点分离**:`ProgressMixin` 负责进度条的业务逻辑封装,底层函数处理进度条的创建和更新,而 `Progress` 类则提供了防抖动的智能步进机制,避免频繁更新导致的性能问题。
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L15-L80), [PySSWidget.py](PySSWidget.py#L934-L977)
|
||||
|
||||
### 核心组件说明
|
||||
|
||||
| 组件 | 类型 | 职责描述 |
|
||||
|------|------|----------|
|
||||
| `ProgressMixin` | Mixin 类 | 提供进度条的封装方法,管理 `enable_progress` 开关 |
|
||||
| `Progress` | C++ 封装类 | 智能步进控制器,将循环总数映射到 0-100 的进度范围 |
|
||||
| `enable_progress` | bool 属性 | 控制进度条是否显示的全局开关 |
|
||||
| `progress` | Progress 实例 | 当前进度条控制器实例 |
|
||||
| `startProgress()` | 全局函数 | 创建并显示进度条对话框 |
|
||||
| `stepProgress()` | 全局函数 | 更新进度条的当前位置和提示信息 |
|
||||
| `closeProgress()` | 全局函数 | 关闭进度条对话框 |
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L22-L80), [PySSWidget.py](PySSWidget.py#L500-L560)
|
||||
|
||||
## 进度条使用基本流程
|
||||
|
||||
进度条操作遵循"启动 → 更新 → 关闭"的标准生命周期管理流程。理解这个流程对于正确使用进度条至关重要,下图展示了完整的操作步骤:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始使用进度条] --> B[调用 startProgress<br/>启动进度条]
|
||||
B --> C{enable_progress<br/>是否启用?}
|
||||
C -->|是| D[创建 Progress 实例<br/>设置进度范围 0-100]
|
||||
C -->|否| E[跳过进度显示]
|
||||
D --> F[执行循环任务]
|
||||
F --> G{progress.step()<br/>是否需要更新?}
|
||||
G -->|是| H[调用 stepProgress<br/>更新进度条显示]
|
||||
G -->|否| F
|
||||
H --> F
|
||||
F --> I{任务是否完成?}
|
||||
I -->|否| F
|
||||
I -->|是| J[调用 closeProgress<br/>关闭进度条]
|
||||
J --> K[进度条使用完成]
|
||||
E --> K
|
||||
|
||||
style D fill:#e1f5ff
|
||||
style H fill:#fff4e1
|
||||
style J fill:#ffe1e1
|
||||
```
|
||||
|
||||
理解这个流程后,我们将逐步详细解析每个环节的具体实现方法。
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L32-L80)
|
||||
|
||||
## 步骤一:启动进度条
|
||||
|
||||
使用 `startProgress()` 方法启动进度条,需要指定标题和总任务数。标题将显示在进度条对话框顶部,总任务数用于计算进度的步进间隔。
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
from sunvpy import SSProcess
|
||||
|
||||
# 启动进度条,显示标题和总任务数
|
||||
SSProcess.startProgress("批量导出数据", 1000)
|
||||
```
|
||||
|
||||
### 方法参数说明
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `title` | str | 是 | 进度条对话框标题,描述当前正在执行的任务 |
|
||||
| `total` | int | 是 | 总任务数,用于计算进度步进间隔 |
|
||||
|
||||
### 实现原理
|
||||
|
||||
`startProgress()` 内部会执行以下操作:
|
||||
|
||||
1. 检查 `enable_progress` 开关是否启用
|
||||
2. 创建 `Progress(total)` 实例,自动计算步进间隔
|
||||
3. 调用全局 `startProgress(title, 1)` 创建进度条对话框
|
||||
4. 调用 `setProgressRange(0, 100)` 设置进度范围固定为 0-100
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Script as 脚本代码
|
||||
participant Mixin as ProgressMixin
|
||||
participant Progress as Progress类
|
||||
participant UI as 进度条UI
|
||||
|
||||
Script->>Mixin: startProgress("导出数据", 1000)
|
||||
activate Mixin
|
||||
Mixin->>Mixin: 检查 enable_progress
|
||||
alt enable_progress == True
|
||||
Mixin->>Progress: new Progress(1000)
|
||||
Progress-->>Mixin: 实例创建成功
|
||||
Mixin->>UI: startProgress("导出数据", 1)
|
||||
UI-->>Mixin: 对话框已显示
|
||||
Mixin->>UI: setProgressRange(0, 100)
|
||||
Mixin->>Mixin: 保存实例到 self.progress
|
||||
end
|
||||
Mixin-->>Script: 方法返回
|
||||
deactivate Mixin
|
||||
```
|
||||
|
||||
这种设计的优势在于:**将循环总数自动映射到 0-100 的标准进度范围**,避免了手动计算百分比的繁琐,同时通过 `Progress` 类的智能步进机制,减少不必要的 UI 更新次数。
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L32-L46), [PySSWidget.py](PySSWidget.py#L495-L500)
|
||||
|
||||
## 步骤二:更新进度条
|
||||
|
||||
在循环或长时间任务中,使用 `stepProgress()` 方法更新进度条显示。这个方法会自动判断是否真正需要更新 UI,避免频繁刷新导致的性能问题。
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
# 遍历选择集并更新进度
|
||||
total_count = SSProcess.getSelGeoCount()
|
||||
SSProcess.startProgress("处理选择集对象", total_count)
|
||||
|
||||
for i in range(total_count):
|
||||
# 执行业务逻辑
|
||||
SSProcess.setSelGeoValue(i, "SSObj_Name", f"对象_{i}")
|
||||
|
||||
# 更新进度条,显示当前处理的索引
|
||||
SSProcess.stepProgress(f"正在处理第 {i+1}/{total_count} 个对象")
|
||||
|
||||
# 关闭进度条
|
||||
SSProcess.closeProgress()
|
||||
```
|
||||
|
||||
### 方法参数说明
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `message` | str | 是 | 当前步骤的描述信息,将显示在进度条下方 |
|
||||
|
||||
### 智能步进机制
|
||||
|
||||
`Progress` 类的核心功能是**智能步进控制**。它会根据总任务数自动计算步进间隔,确保进度条更新不会过于频繁:
|
||||
|
||||
```python
|
||||
# Progress 内部的步进逻辑(简化示例)
|
||||
class Progress:
|
||||
def __init__(self, total):
|
||||
self.total = total
|
||||
self.current = 0
|
||||
# 自动计算步进间隔,确保在0-100范围内更新不超过100次
|
||||
self.step_size = max(1, total // 100)
|
||||
|
||||
def step(self):
|
||||
self.current += 1
|
||||
# 只有当累计步进达到阈值时才返回True,触发UI更新
|
||||
if self.current >= self.step_size:
|
||||
self.current = 0
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
这种机制的效果是:无论循环执行多少次(100次还是100000次),进度条最多只更新100次,大大提高了性能。
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L48-L60), [PySSWidget.py](PySSWidget.py#L946-L972)
|
||||
|
||||
### 更新频率对比
|
||||
|
||||
以下对比展示了智能步进机制与传统每次循环都更新的区别:
|
||||
|
||||
| 场景 | 总任务数 | 传统更新次数 | 智能步进更新次数 | 性能提升 |
|
||||
|------|----------|-------------|----------------|----------|
|
||||
| 小型任务 | 50 | 50 | 50 | 无提升 |
|
||||
| 中型任务 | 1000 | 1000 | 100 | 10倍提升 |
|
||||
| 大型任务 | 100000 | 100000 | 100 | 1000倍提升 |
|
||||
|
||||
Sources: [PySSWidget.py](PySSWidget.py#L950-L972)
|
||||
|
||||
## 步骤三:关闭进度条
|
||||
|
||||
任务完成后,必须调用 `closeProgress()` 方法关闭进度条对话框。这个方法会清理进度条资源,并确保 UI 正确更新。
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
# 任务完成后关闭进度条
|
||||
SSProcess.closeProgress()
|
||||
```
|
||||
|
||||
### 方法行为
|
||||
|
||||
`closeProgress()` 会执行以下操作:
|
||||
|
||||
1. 调用全局 `closeProgress()` 函数关闭对话框
|
||||
2. 将 `self.progress` 设置为 `None`,释放资源
|
||||
3. 通过异常处理确保即使关闭失败也不会影响程序运行
|
||||
|
||||
```python
|
||||
def closeProgress(self):
|
||||
"""关闭进度条。"""
|
||||
if self.progress is not None:
|
||||
try:
|
||||
closeProgress()
|
||||
except Exception:
|
||||
pass # 忽略关闭异常
|
||||
self.progress = None
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L62-L80), [PySSWidget.py](PySSWidget.py#L505-L510)
|
||||
|
||||
### 关闭时机的重要性
|
||||
|
||||
确保在以下所有情况下都调用 `closeProgress()`:
|
||||
|
||||
| 场景 | 说明 | 处理方式 |
|
||||
|------|------|----------|
|
||||
| 正常完成 | 循环自然结束 | 在循环结束后调用 |
|
||||
| 异常中断 | 遇到错误提前退出 | 使用 try-finally 确保调用 |
|
||||
| 用户取消 | 响应用户中断请求 | 在取消处理中调用 |
|
||||
| 条件跳过 | 不满足某些条件时退出 | 在所有退出分支中调用 |
|
||||
|
||||
### 最佳实践:使用 finally 确保关闭
|
||||
|
||||
```python
|
||||
SSProcess.startProgress("处理数据", total_count)
|
||||
|
||||
try:
|
||||
for i in range(total_count):
|
||||
# 执行业务逻辑
|
||||
process_item(i)
|
||||
|
||||
# 更新进度
|
||||
SSProcess.stepProgress(f"处理 {i+1}/{total_count}")
|
||||
|
||||
# 检查是否需要中断
|
||||
if should_cancel():
|
||||
raise KeyboardInterrupt("用户取消操作")
|
||||
|
||||
except Exception as e:
|
||||
SSProcess.logger.error(f"处理失败: {e}")
|
||||
raise
|
||||
|
||||
finally:
|
||||
# 确保进度条一定会被关闭
|
||||
SSProcess.closeProgress()
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L62-L80)
|
||||
|
||||
## 完整示例:批量导出数据
|
||||
|
||||
下面是一个完整的示例,展示在批量导出选择集对象时如何使用进度条。
|
||||
|
||||
### 代码实现
|
||||
|
||||
```python
|
||||
from sunvpy import SSProcess
|
||||
|
||||
def export_selection_to_csv(file_path):
|
||||
"""将选择集中的对象导出到CSV文件"""
|
||||
|
||||
# 获取选择集数量
|
||||
geo_count = SSProcess.getSelGeoCount()
|
||||
|
||||
if geo_count == 0:
|
||||
print("选择集为空,无需导出")
|
||||
return
|
||||
|
||||
# 启动进度条
|
||||
SSProcess.startProgress("导出选择集到CSV", geo_count)
|
||||
|
||||
try:
|
||||
# 准备CSV文件
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
# 写入CSV表头
|
||||
f.write("ID,代码,名称,类型,颜色\n")
|
||||
|
||||
# 遍历选择集并导出
|
||||
for i in range(geo_count):
|
||||
# 获取对象属性
|
||||
obj_id = SSProcess.getSelGeoValue(i, "SSObj_ID")
|
||||
obj_code = SSProcess.getSelGeoValue(i, "SSObj_Code")
|
||||
obj_name = SSProcess.getSelGeoValue(i, "SSObj_Name")
|
||||
obj_type = SSProcess.getSelGeoValue(i, "SSObj_Type")
|
||||
obj_color = SSProcess.getSelGeoValue(i, "SSObj_Color")
|
||||
|
||||
# 写入CSV行
|
||||
f.write(f"{obj_id},{obj_code},{obj_name},{obj_type},{obj_color}\n")
|
||||
|
||||
# 每处理10个对象更新一次进度
|
||||
SSProcess.stepProgress(f"正在导出第 {i+1}/{geo_count} 个对象")
|
||||
|
||||
print(f"成功导出 {geo_count} 个对象到 {file_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"导出失败: {e}")
|
||||
SSProcess.logger.error(f"导出失败: {e}")
|
||||
|
||||
finally:
|
||||
# 确保关闭进度条
|
||||
SSProcess.closeProgress()
|
||||
|
||||
# 调用示例
|
||||
export_selection_to_csv("export.csv")
|
||||
```
|
||||
|
||||
### 代码解析
|
||||
|
||||
| 代码段 | 说明 |
|
||||
|--------|------|
|
||||
| `geo_count = SSProcess.getSelGeoCount()` | 先获取总数量,用于进度条初始化 |
|
||||
| `SSProcess.startProgress(...)` | 在 try 块之前启动进度条 |
|
||||
| `SSProcess.stepProgress(...)` | 在循环内部更新进度,显示当前处理位置 |
|
||||
| `finally: SSProcess.closeProgress()` | 使用 finally 确保进度条一定被关闭 |
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L32-L80)
|
||||
|
||||
## 禁用进度条
|
||||
|
||||
在某些场景下(如自动化脚本、后台任务),可能需要临时或永久禁用进度条显示。使用 `disable_progress()` 方法可以实现这一需求。
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
# 禁用进度条
|
||||
SSProcess.disable_progress()
|
||||
|
||||
# 后续的所有进度条操作都不会显示
|
||||
SSProcess.startProgress("处理数据", 100) # 不会显示进度条
|
||||
SSProcess.stepProgress("处理中...") # 不会更新进度条
|
||||
SSProcess.closeProgress() # 不会执行任何操作
|
||||
```
|
||||
|
||||
### 方法行为
|
||||
|
||||
`disable_progress()` 会执行以下操作:
|
||||
|
||||
1. 将 `enable_progress` 设置为 `False`
|
||||
2. 如果当前有正在显示的进度条,立即关闭它
|
||||
3. 后续所有进度条方法调用都会被跳过
|
||||
|
||||
```python
|
||||
def disable_progress(self):
|
||||
"""关闭进度条显示并立即关闭正在显示的进度条。"""
|
||||
self.enable_progress = False
|
||||
if self.progress is not None:
|
||||
try:
|
||||
closeProgress()
|
||||
except Exception:
|
||||
pass
|
||||
self.progress = None
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L24-L30)
|
||||
|
||||
### 使用场景对比
|
||||
|
||||
| 场景 | 是否禁用进度条 | 原因 |
|
||||
|------|----------------|------|
|
||||
| 交互式脚本 | 否 | 用户需要看到进度反馈 |
|
||||
| 批处理自动化任务 | 是 | 无用户交互,节省资源 |
|
||||
| 后台定时任务 | 是 | 避免弹出窗口干扰 |
|
||||
| 单元测试 | 是 | 测试环境不需要UI反馈 |
|
||||
| 调试阶段 | 否 | 需要观察程序执行状态 |
|
||||
|
||||
### 条件禁用示例
|
||||
|
||||
```python
|
||||
import sys
|
||||
|
||||
def process_data():
|
||||
"""根据运行环境决定是否显示进度条"""
|
||||
|
||||
# 如果是从命令行运行且带有 --quiet 参数,则禁用进度条
|
||||
if '--quiet' in sys.argv:
|
||||
SSProcess.disable_progress()
|
||||
print("静默模式:进度条已禁用")
|
||||
|
||||
# 正常使用进度条(会根据 enable_progress 自动判断)
|
||||
SSProcess.startProgress("处理数据", 1000)
|
||||
for i in range(1000):
|
||||
process_item(i)
|
||||
SSProcess.stepProgress(f"处理 {i+1}")
|
||||
SSProcess.closeProgress()
|
||||
|
||||
# 调用示例
|
||||
# python script.py --quiet # 禁用进度条
|
||||
# python script.py # 显示进度条
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L24-L30)
|
||||
|
||||
## 进度条与日志配合使用
|
||||
|
||||
将进度条与日志系统结合使用,可以在提供视觉反馈的同时保留详细的执行记录,特别适合复杂的长时间任务。
|
||||
|
||||
### 配合模式
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[任务开始] --> B[记录日志 INFO]
|
||||
B --> C[启动进度条]
|
||||
C --> D{循环执行}
|
||||
D --> E[执行子任务]
|
||||
E --> F{子任务成功?}
|
||||
F -->|是| G[记录日志 DEBUG<br/>详细信息]
|
||||
F -->|否| H[记录日志 ERROR<br/>错误信息]
|
||||
G --> I[更新进度条]
|
||||
H --> I
|
||||
I --> J{任务完成?}
|
||||
J -->|否| D
|
||||
J -->|是| K[关闭进度条]
|
||||
K --> L[记录日志 INFO<br/>任务完成]
|
||||
|
||||
style C fill:#e1f5ff
|
||||
style I fill:#fff4e1
|
||||
style K fill:#ffe1e1
|
||||
```
|
||||
|
||||
### 完整示例
|
||||
|
||||
```python
|
||||
import logging
|
||||
from sunvpy import SSProcess
|
||||
|
||||
# 配置日志记录器
|
||||
logger = logging.getLogger('batch_process')
|
||||
logger.setLevel(logging.INFO)
|
||||
file_handler = logging.FileHandler('batch_process.log', encoding='utf-8')
|
||||
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
# 将日志注入到 SSProcess
|
||||
SSProcess.set_logger(logger)
|
||||
|
||||
def batch_process_objects():
|
||||
"""批量处理对象,配合进度条和日志"""
|
||||
|
||||
logger.info("开始批量处理任务")
|
||||
|
||||
# 获取选择集数量
|
||||
total_count = SSProcess.getSelGeoCount()
|
||||
logger.info(f"选择集对象数量: {total_count}")
|
||||
|
||||
if total_count == 0:
|
||||
logger.warning("选择集为空,跳过处理")
|
||||
return
|
||||
|
||||
# 启动进度条
|
||||
SSProcess.startProgress("批量处理对象", total_count)
|
||||
|
||||
success_count = 0
|
||||
error_count = 0
|
||||
|
||||
try:
|
||||
for i in range(total_count):
|
||||
try:
|
||||
# 执行业务逻辑
|
||||
process_single_object(i)
|
||||
|
||||
# 记录详细日志
|
||||
logger.debug(f"成功处理对象 {i+1}/{total_count}")
|
||||
success_count += 1
|
||||
|
||||
except Exception as e:
|
||||
# 记录错误日志
|
||||
logger.error(f"处理对象 {i+1} 失败: {str(e)}")
|
||||
error_count += 1
|
||||
|
||||
# 更新进度条
|
||||
SSProcess.stepProgress(f"处理进度: {i+1}/{total_count}")
|
||||
|
||||
finally:
|
||||
# 关闭进度条
|
||||
SSProcess.closeProgress()
|
||||
|
||||
# 记录汇总日志
|
||||
logger.info(f"处理完成: 成功 {success_count} 个, 失败 {error_count} 个")
|
||||
|
||||
def process_single_object(index):
|
||||
"""处理单个对象的业务逻辑"""
|
||||
# 这里实现具体的处理逻辑
|
||||
obj_name = SSProcess.getSelGeoValue(index, "SSObj_Name")
|
||||
SSProcess.setSelGeoValue(index, "SSObj_Name", f"{obj_name}_已处理")
|
||||
|
||||
# 调用示例
|
||||
batch_process_objects()
|
||||
|
||||
# 输出示例:
|
||||
# 2024-01-15 10:30:00 - INFO - 开始批量处理任务
|
||||
# 2024-01-15 10:30:00 - INFO - 选择集对象数量: 100
|
||||
# 2024-01-15 10:30:05 - INFO - 处理完成: 成功 98 个, 失败 2 个
|
||||
# 2024-01-15 10:30:05 - ERROR - 处理对象 15 失败: 无法获取属性值
|
||||
```
|
||||
|
||||
### 日志级别与进度条的配合策略
|
||||
|
||||
| 操作阶段 | 进度条操作 | 日志级别 | 说明 |
|
||||
|----------|-----------|---------|------|
|
||||
| 任务开始 | startProgress | INFO | 记录任务启动,包含总数量 |
|
||||
| 每个循环 | stepProgress | DEBUG | 记录详细信息(可关闭) |
|
||||
| 子任务成功 | - | DEBUG | 记录成功的详细步骤 |
|
||||
| 子任务失败 | - | ERROR | 记录失败的原因和堆栈 |
|
||||
| 任务结束 | closeProgress | INFO | 记录任务完成,包含统计 |
|
||||
|
||||
这种配合方式的优势在于:**进度条提供实时视觉反馈,日志提供可追溯的详细记录**,两者互为补充,满足不同场景的需求。
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L32-L80), [log_mixin.py](ssprocess_mixins/log_mixin.py#L26-L42)
|
||||
|
||||
## 常见问题与解决方案
|
||||
|
||||
### 问题一:进度条不显示
|
||||
|
||||
**现象**:调用 `startProgress()` 后进度条没有显示。
|
||||
|
||||
**可能原因及解决方案**:
|
||||
|
||||
| 原因 | 检查方法 | 解决方案 |
|
||||
|------|---------|----------|
|
||||
| 已禁用进度条 | 检查 `SSProcess.enable_progress` | 调用 `SSProcess.enable_progress = True` 重新启用 |
|
||||
| 总任务数为0 | 检查传入的 `total` 参数 | 确保传入有效的正整数 |
|
||||
| 主线程阻塞 | 检查是否有耗时操作在主线程 | 将耗时操作放到子线程中执行 |
|
||||
|
||||
```python
|
||||
# 检查进度条状态
|
||||
print(f"进度条启用状态: {SSProcess.enable_progress}")
|
||||
|
||||
# 重新启用进度条
|
||||
SSProcess.enable_progress = True
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L24-L30)
|
||||
|
||||
### 问题二:进度条卡住不动
|
||||
|
||||
**现象**:进度条显示后长时间没有更新。
|
||||
|
||||
**可能原因及解决方案**:
|
||||
|
||||
```python
|
||||
# 错误示例:步进过大导致进度条长时间不更新
|
||||
SSProcess.startProgress("处理", 100000) # 任务数过大
|
||||
for i in range(100000):
|
||||
process_item(i)
|
||||
# 每1000次才会更新一次进度,看起来像卡住
|
||||
SSProcess.stepProgress(f"处理 {i}")
|
||||
|
||||
# 正确示例:提供更有意义的进度提示
|
||||
SSProcess.startProgress("处理", 100000)
|
||||
for i in range(100000):
|
||||
process_item(i)
|
||||
# 进度条内部会智能控制更新频率,但提示信息会实时显示
|
||||
SSProcess.stepProgress(f"处理 {i+1}/{100000}")
|
||||
```
|
||||
|
||||
Sources: [PySSWidget.py](PySSWidget.py#L950-L972)
|
||||
|
||||
### 问题三:进度条关闭后程序无响应
|
||||
|
||||
**现象**:调用 `closeProgress()` 后程序似乎卡住。
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```python
|
||||
# 原因分析:进度条关闭操作在UI线程执行,可能被其他操作阻塞
|
||||
|
||||
# 解决方案1:确保在主线程中关闭
|
||||
def close_progress_safely():
|
||||
if SSProcess.progress is not None:
|
||||
try:
|
||||
closeProgress()
|
||||
except Exception as e:
|
||||
print(f"关闭进度条时出错: {e}")
|
||||
finally:
|
||||
SSProcess.progress = None
|
||||
|
||||
close_progress_safely()
|
||||
|
||||
# 解决方案2:使用超时机制
|
||||
import threading
|
||||
import time
|
||||
|
||||
def close_with_timeout(timeout=5):
|
||||
def _close():
|
||||
try:
|
||||
closeProgress()
|
||||
except:
|
||||
pass
|
||||
|
||||
thread = threading.Thread(target=_close)
|
||||
thread.start()
|
||||
thread.join(timeout=timeout)
|
||||
|
||||
if thread.is_alive():
|
||||
print("警告:进度条关闭超时")
|
||||
SSProcess.progress = None
|
||||
|
||||
close_with_timeout()
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L62-L80)
|
||||
|
||||
## 最佳实践总结
|
||||
|
||||
### 1. 进度条使用检查清单
|
||||
|
||||
在使用进度条前,请确认以下要点:
|
||||
|
||||
| 检查项 | 说明 |
|
||||
|--------|------|
|
||||
| ✓ 确认总任务数 | 使用准确的数字初始化进度条,避免0或负数 |
|
||||
| ✓ 在try前启动 | 确保进度条启动在try块之前 |
|
||||
| ✓ 在finally中关闭 | 使用try-finally确保进度条一定会被关闭 |
|
||||
| ✓ 提供有意义的提示 | `stepProgress` 的message应反映当前操作状态 |
|
||||
| ✓ 考虑禁用场景 | 自动化任务中考虑使用 `disable_progress()` |
|
||||
|
||||
### 2. 性能优化建议
|
||||
|
||||
| 优化点 | 说明 | 示例 |
|
||||
|--------|------|------|
|
||||
| 减少UI更新 | 利用 `Progress.step()` 的自动步进机制 | 不需要手动计算更新频率 |
|
||||
| 异步关闭 | 大任务完成后考虑异步关闭进度条 | 使用子线程关闭避免阻塞 |
|
||||
| 条件显示 | 根据任务时长决定是否显示进度条 | 短任务(<1秒)跳过进度条 |
|
||||
|
||||
### 3. 代码模板
|
||||
|
||||
```python
|
||||
# 标准进度条使用模板
|
||||
from sunvpy import SSProcess
|
||||
|
||||
def task_with_progress():
|
||||
"""带进度条的标准任务模板"""
|
||||
|
||||
# 1. 获取总任务数
|
||||
total = get_task_count()
|
||||
if total == 0:
|
||||
return
|
||||
|
||||
# 2. 启动进度条
|
||||
SSProcess.startProgress("任务描述", total)
|
||||
|
||||
try:
|
||||
# 3. 执行循环任务
|
||||
for i in range(total):
|
||||
# 执行业务逻辑
|
||||
do_work(i)
|
||||
|
||||
# 4. 更新进度
|
||||
SSProcess.stepProgress(f"处理 {i+1}/{total}")
|
||||
|
||||
except Exception as e:
|
||||
# 5. 错误处理
|
||||
SSProcess.logger.error(f"任务失败: {e}")
|
||||
raise
|
||||
|
||||
finally:
|
||||
# 6. 确保关闭
|
||||
SSProcess.closeProgress()
|
||||
```
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L15-L80)
|
||||
|
||||
## 下一步学习
|
||||
|
||||
掌握了进度条的基本使用后,您可以继续学习以下相关主题:
|
||||
|
||||
- [配置日志记录器](37-pei-zhi-ri-zhi-ji-lu-qi) — 了解如何将日志与进度条配合,构建完整的反馈机制
|
||||
- [错误处理与异常管理](39-cuo-wu-chu-li-yu-yi-chang-guan-li) — 学习在进度条操作中正确处理异常
|
||||
- [批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku) — 查看进度条在实际批量操作中的应用示例
|
||||
|
||||
通过这些内容的学习,您将能够构建出用户体验良好、健壮性强的 SunvStation 脚本应用。
|
||||
Reference in New Issue
Block a user