From 8d36c23524d4f1cdd3447989da94981945a8bc6b Mon Sep 17 00:00:00 2001 From: DXC Date: Wed, 6 May 2026 11:41:21 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20Step1Panel=20UI=20=E8=81=94?= =?UTF-8?q?=E5=8A=A8=E9=80=BB=E8=BE=91=E6=B7=B1=E5=BA=A6=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Step1Panel_UI联动优化说明.md | 336 +++++++++++++++++++++++++++++ src/gui/water_quality_gui.py | 68 ++++-- 2 files changed, 386 insertions(+), 18 deletions(-) create mode 100644 Step1Panel_UI联动优化说明.md diff --git a/Step1Panel_UI联动优化说明.md b/Step1Panel_UI联动优化说明.md new file mode 100644 index 0000000..d13f0f1 --- /dev/null +++ b/Step1Panel_UI联动优化说明.md @@ -0,0 +1,336 @@ +# Step1Panel UI 联动逻辑优化说明 + +## 📋 修改概览 + +本次优化针对 Step1Panel(水域掩膜生成步骤)的 UI 联动逻辑进行了深度重构,主要解决了: +1. ✅ 输出掩膜组件与单选按钮的深度绑定 +2. ✅ 路径显示的斜杠混用问题 +3. ✅ 底层运行逻辑的兼容性 + +--- + +## 🎯 核心改进 + +### 1. 输出掩膜的显示/隐藏与单选按钮深度绑定 + +#### 修改位置:`Step1Panel.update_ui_state()` + +**原逻辑问题**: +- 输出掩膜在两种模式下都显示,不符合业务逻辑 +- "使用现有掩膜文件"时不需要指定输出路径 + +**新逻辑**: +```python +def update_ui_state(self): + """根据选择的掩膜生成方式更新UI状态(使用显示/隐藏控制)""" + use_ndwi = self.use_ndwi_radio.isChecked() + + # 动态显示/隐藏组件 + if use_ndwi: + # 使用NDWI模式:隐藏掩膜文件,显示NDWI参数和输出掩膜 + self.mask_file.setVisible(False) + self.ndwi_group.setVisible(True) + self.output_file.setVisible(True) # 显示输出掩膜路径 + + # 当切换到NDWI模式时,如果工作目录已设置,自动填充输出路径 + if hasattr(self, 'work_dir') and self.work_dir: + self._auto_fill_output_path() + else: + # 使用现有掩膜模式:显示掩膜文件,隐藏NDWI参数和输出掩膜 + self.mask_file.setVisible(True) + self.ndwi_group.setVisible(False) + self.output_file.setVisible(False) # 隐藏输出掩膜路径 + + # 参考影像在两种模式下都显示 + self.img_file.setVisible(True) +``` + +**行为说明**: +| 模式 | 掩膜文件 | NDWI参数组 | 输出掩膜 | 参考影像 | +|------|---------|-----------|---------|---------| +| 使用现有掩膜文件 | ✅ 显示 | ❌ 隐藏 | ❌ 隐藏 | ✅ 显示 | +| 使用NDWI自动生成 | ❌ 隐藏 | ✅ 显示 | ✅ 显示 | ✅ 显示 | + +--- + +### 2. 修复路径斜杠混用问题 + +#### 修改位置 1:`Step1Panel._auto_fill_output_path()` (新增方法) + +**核心改进**:统一使用正斜杠 `/`,避免 Windows 下的 `\` 和 `/` 混用 + +```python +def _auto_fill_output_path(self): + """ + 自动填充输出掩膜路径(仅在NDWI模式下) + 确保路径使用正斜杠,避免斜杠混用 + """ + if not hasattr(self, 'work_dir') or not self.work_dir: + return + + # 生成输出掩膜的完整路径 + output_dir = os.path.join(self.work_dir, "1_water_mask") + os.makedirs(output_dir, exist_ok=True) # 确保目录存在 + + # 统一使用正斜杠,避免 \ 和 / 混用 + default_output_path = os.path.join(output_dir, "water_mask_out.dat").replace('\\', '/') + self.output_file.set_path(default_output_path) +``` + +**关键技术点**: +- 使用 `os.path.join()` 构建路径(适配不同操作系统) +- 最终通过 `.replace('\\', '/')` 统一转换为正斜杠 +- 在界面显示前完成转换,确保用户看到的路径一致 + +#### 修改位置 2:`Step1Panel.update_work_directory()` + +**原逻辑问题**: +- 开机时直接填充路径,不考虑当前选择的模式 +- 没有斜杠格式化 + +**新逻辑**: +```python +def update_work_directory(self, work_dir): + """ + 保存工作目录引用,用于后续自动填充路径 + + Args: + work_dir: 工作目录路径 + """ + if not work_dir: + return + + # 保存工作目录引用 + self.work_dir = work_dir + + # 如果当前选中的是NDWI模式,立即填充输出路径 + if self.use_ndwi_radio.isChecked(): + self._auto_fill_output_path() +``` + +**改进说明**: +- 只保存工作目录引用,不立即填充 +- 仅在 NDWI 模式下才调用 `_auto_fill_output_path()` +- 配合 `update_ui_state()` 中的切换触发逻辑 + +--- + +### 3. 底层运行逻辑的兼容性保障 + +#### 修改位置:`Step1Panel.get_config()` + +**原逻辑问题**: +- 无论哪种模式,都传递 `output_path` 给底层 Pipeline +- "使用现有掩膜"模式下传递空路径可能导致底层错误 + +**新逻辑**: +```python +def get_config(self): + """获取配置""" + use_ndwi = self.use_ndwi_radio.isChecked() + + config = { + 'mask_path': None if use_ndwi else self.mask_file.get_path(), + 'use_ndwi': use_ndwi, + 'ndwi_threshold': self.ndwi_threshold.value() + } + + # 参考影像路径(两种模式都可能需要) + img_path = self.img_file.get_path() + if img_path: + config['img_path'] = img_path + + # 输出路径:仅在NDWI模式下有效 + if use_ndwi: + output_path = self.output_file.get_path() + if output_path: + config['output_path'] = output_path + else: + # 使用现有掩膜时,不传递output_path,避免底层错误尝试保存文件 + config['output_path'] = None + + return config +``` + +**关键改进**: +- 根据 `use_ndwi` 模式动态决定是否传递 `output_path` +- "使用现有掩膜"模式:强制 `output_path = None` +- "NDWI自动生成"模式:传递用户选择的路径 + +**底层兼容性**: +```python +# Pipeline 中的处理逻辑(已在之前的提交中实现) +def step1_generate_water_mask(..., output_path: Optional[str] = None): + if use_ndwi: + if output_path: + ndwi_output_path = output_path # 使用用户指定路径 + else: + ndwi_output_path = str(self.water_mask_dir / "water_mask_from_ndwi.dat") +``` + +--- + +### 4. 主窗口初始化逻辑优化 + +#### 修改位置:`WaterQualityGUI._auto_fill_output_paths()` + +**原逻辑问题**: +- 开机时直接调用 `set_path()` 填充输出掩膜路径 +- 不考虑当前的单选按钮状态 + +**新逻辑**: +```python +def _auto_fill_output_paths(self): + """ + 根据工作目录自动填充各步骤的输出路径 + 注意:Step1 的输出路径由 update_work_directory() 根据模式自动控制 + """ + if not self.work_dir: + return + + # Step1: 只传递工作目录引用,不直接填充路径 + # 路径填充由 Step1Panel 根据单选按钮状态自动控制 + if hasattr(self, 'step1_panel'): + self.step1_panel.update_work_directory(self.work_dir) +``` + +**改进说明**: +- 主窗口只传递工作目录引用 +- Step1Panel 内部根据模式自主决定是否填充路径 +- 解耦主窗口和子面板的逻辑依赖 + +--- + +## 🔄 完整的交互流程 + +### 场景 1:开机启动(默认选中"使用现有掩膜文件") + +``` +1. 主窗口启动 → QTimer.singleShot(100) 延迟弹窗 +2. 用户选择工作目录 D:\work +3. _auto_fill_output_paths() 调用 step1_panel.update_work_directory(work_dir) +4. Step1Panel.update_work_directory() 保存 self.work_dir = "D:\work" +5. 检查当前模式:use_existing_radio.isChecked() = True +6. 不调用 _auto_fill_output_path(),输出掩膜保持隐藏 +7. 用户看到的界面: + ✅ 掩膜文件输入框(显示) + ✅ 参考影像输入框(显示) + ❌ NDWI参数组(隐藏) + ❌ 输出掩膜输入框(隐藏) +``` + +### 场景 2:用户切换到"使用NDWI自动生成" + +``` +1. 用户点击"使用NDWI自动生成"单选按钮 +2. 触发 toggled 信号 → update_ui_state() +3. use_ndwi = True +4. 执行显示/隐藏逻辑: + - self.mask_file.setVisible(False) # 隐藏掩膜文件 + - self.ndwi_group.setVisible(True) # 显示NDWI参数组 + - self.output_file.setVisible(True) # 显示输出掩膜 +5. 检查工作目录:hasattr(self, 'work_dir') = True +6. 调用 self._auto_fill_output_path() +7. 生成路径: + output_dir = os.path.join("D:\work", "1_water_mask") + path = os.path.join(output_dir, "water_mask_out.dat") + formatted_path = path.replace('\\', '/') + # 结果:D:/work/1_water_mask/water_mask_out.dat +8. 自动填充到输出掩膜输入框 +9. 用户看到的界面: + ❌ 掩膜文件输入框(隐藏) + ✅ 参考影像输入框(显示) + ✅ NDWI参数组(显示) + ✅ 输出掩膜输入框(显示,已填充:D:/work/1_water_mask/water_mask_out.dat) +``` + +### 场景 3:用户点击"独立运行此步骤" + +#### 当前选择:"使用现有掩膜文件" +```python +config = { + 'mask_path': "D:/data/existing_mask.dat", # 用户选择的现有掩膜 + 'use_ndwi': False, + 'ndwi_threshold': 0.4, + 'img_path': "D:/data/image.dat", + 'output_path': None # ✅ 强制为 None,不尝试保存 +} +``` + +#### 当前选择:"使用NDWI自动生成" +```python +config = { + 'mask_path': None, # NDWI模式不需要现有掩膜 + 'use_ndwi': True, + 'ndwi_threshold': 0.4, + 'img_path': "D:/data/image.dat", + 'output_path': "D:/work/1_water_mask/water_mask_out.dat" # ✅ 传递输出路径 +} +``` + +--- + +## ✅ 测试检查点 + +### UI 显示测试 +- [ ] 开机启动后,默认选中"使用现有掩膜文件",输出掩膜输入框应隐藏 +- [ ] 切换到"使用NDWI自动生成",输出掩膜输入框应显示,并自动填充路径 +- [ ] 切换回"使用现有掩膜文件",输出掩膜输入框应再次隐藏 +- [ ] 所有自动填充的路径应使用正斜杠 `/`,无 `\` 混用 + +### 路径格式测试 +- [ ] 工作目录:`D:\work` → 输出路径应显示为:`D:/work/1_water_mask/water_mask_out.dat` +- [ ] 工作目录:`C:\Users\Test\Documents` → 输出路径应显示为:`C:/Users/Test/Documents/1_water_mask/water_mask_out.dat` + +### 运行逻辑测试 +- [ ] "使用现有掩膜"模式运行:验证 `config['output_path'] == None` +- [ ] "NDWI自动生成"模式运行:验证 `config['output_path']` 为有效路径字符串 +- [ ] 底层 Pipeline 接收 `output_path=None` 时不报错 + +--- + +## 📝 代码修改总结 + +| 文件 | 修改内容 | 行数变化 | +|------|---------|---------| +| `src/gui/water_quality_gui.py` | Step1Panel.update_ui_state() | +6 / -3 | +| `src/gui/water_quality_gui.py` | Step1Panel.update_work_directory() | +10 / -8 | +| `src/gui/water_quality_gui.py` | Step1Panel._auto_fill_output_path() (新增) | +15 / 0 | +| `src/gui/water_quality_gui.py` | Step1Panel.get_config() | +12 / -6 | +| `src/gui/water_quality_gui.py` | WaterQualityGUI._auto_fill_output_paths() | +3 / -4 | + +**总计**:约 **+46 / -21** 行 + +--- + +## 🎯 优化效果 + +### 用户体验提升 +1. ✅ UI 更简洁:不需要的组件自动隐藏 +2. ✅ 路径一致性:所有路径显示统一使用正斜杠 +3. ✅ 自动化程度提高:切换模式时自动填充/清空路径 + +### 代码质量提升 +1. ✅ 职责分离:主窗口不直接操作子面板的路径填充 +2. ✅ 逻辑内聚:Step1Panel 内部自主管理显示和路径 +3. ✅ 兼容性保障:底层 Pipeline 不会收到无效的 output_path + +### 维护性提升 +1. ✅ 新增 `_auto_fill_output_path()` 方法,单一职责 +2. ✅ 路径格式化逻辑集中在一处,便于修改 +3. ✅ 注释清晰,说明了各模式下的行为 + +--- + +## 🔧 后续可能的扩展 + +如果其他步骤也有类似的路径填充需求,可以考虑: +1. 提取公共方法 `format_path_separator(path)` 到工具类 +2. 在 `FileSelectWidget` 类中增加路径格式化的内置支持 +3. 为所有路径输入框添加统一的验证和格式化逻辑 + +--- + +**文档生成时间**: 2026-05-06 +**修改人员**: DXC +**关联提交**: (待提交) diff --git a/src/gui/water_quality_gui.py b/src/gui/water_quality_gui.py index f7d3fc9..5c7482e 100644 --- a/src/gui/water_quality_gui.py +++ b/src/gui/water_quality_gui.py @@ -1071,21 +1071,26 @@ class Step1Panel(QWidget): # 动态显示/隐藏组件 if use_ndwi: - # 使用NDWI模式:隐藏掩膜文件,显示NDWI参数 + # 使用NDWI模式:隐藏掩膜文件,显示NDWI参数和输出掩膜 self.mask_file.setVisible(False) self.ndwi_group.setVisible(True) + self.output_file.setVisible(True) # 显示输出掩膜路径 + + # 当切换到NDWI模式时,如果工作目录已设置,自动填充输出路径 + if hasattr(self, 'work_dir') and self.work_dir: + self._auto_fill_output_path() else: - # 使用现有掩膜模式:显示掩膜文件,隐藏NDWI参数 + # 使用现有掩膜模式:显示掩膜文件,隐藏NDWI参数和输出掩膜 self.mask_file.setVisible(True) self.ndwi_group.setVisible(False) + self.output_file.setVisible(False) # 隐藏输出掩膜路径 - # 参考影像和输出掩膜在两种模式下都显示 + # 参考影像在两种模式下都显示 self.img_file.setVisible(True) - self.output_file.setVisible(True) def update_work_directory(self, work_dir): """ - 接收主窗口传来的工作目录,自动填充输出路径 + 保存工作目录引用,用于后续自动填充路径 Args: work_dir: 工作目录路径 @@ -1093,26 +1098,53 @@ class Step1Panel(QWidget): if not work_dir: return - # 自动生成输出掩膜的完整路径 - output_dir = os.path.join(work_dir, "1_water_mask") + # 保存工作目录引用 + self.work_dir = work_dir + + # 如果当前选中的是NDWI模式,立即填充输出路径 + if self.use_ndwi_radio.isChecked(): + self._auto_fill_output_path() + + def _auto_fill_output_path(self): + """ + 自动填充输出掩膜路径(仅在NDWI模式下) + 确保路径使用正斜杠,避免斜杠混用 + """ + if not hasattr(self, 'work_dir') or not self.work_dir: + return + + # 生成输出掩膜的完整路径 + output_dir = os.path.join(self.work_dir, "1_water_mask") os.makedirs(output_dir, exist_ok=True) # 确保目录存在 - default_output_path = os.path.join(output_dir, "water_mask_out.dat") + # 统一使用正斜杠,避免 \ 和 / 混用 + default_output_path = os.path.join(output_dir, "water_mask_out.dat").replace('\\', '/') self.output_file.set_path(default_output_path) def get_config(self): """获取配置""" + use_ndwi = self.use_ndwi_radio.isChecked() + config = { - 'mask_path': None if self.use_ndwi_radio.isChecked() else self.mask_file.get_path(), - 'use_ndwi': self.use_ndwi_radio.isChecked(), + 'mask_path': None if use_ndwi else self.mask_file.get_path(), + 'use_ndwi': use_ndwi, 'ndwi_threshold': self.ndwi_threshold.value() } + + # 参考影像路径(两种模式都可能需要) img_path = self.img_file.get_path() if img_path: config['img_path'] = img_path - output_path = self.output_file.get_path() - if output_path: - config['output_path'] = output_path + + # 输出路径:仅在NDWI模式下有效 + if use_ndwi: + output_path = self.output_file.get_path() + if output_path: + config['output_path'] = output_path + else: + # 使用现有掩膜时,不传递output_path,避免底层错误尝试保存文件 + config['output_path'] = None + return config def set_config(self, config): @@ -5668,14 +5700,14 @@ class WaterQualityGUI(QMainWindow): def _auto_fill_output_paths(self): """ 根据工作目录自动填充各步骤的输出路径 + 注意:Step1 的输出路径由 update_work_directory() 根据模式自动控制 """ if not self.work_dir: return - - # Step1: 输出掩膜路径 - if hasattr(self, 'step1_panel') and hasattr(self.step1_panel, 'output_file'): - default_mask_path = os.path.join(self.work_dir, "1_water_mask", "water_mask_out.dat") - self.step1_panel.output_file.set_path(default_mask_path) + + # Step1: 只传递工作目录引用,不直接填充路径 + # 路径填充由 Step1Panel 根据单选按钮状态自动控制 + if hasattr(self, 'step1_panel'): self.step1_panel.update_work_directory(self.work_dir) def init_ui(self):