fix: 全局UX修复与Step4交互可视化重构
=== 自动填入过于激进(幽灵路径级联)=== - 所有面板 update_from_config 移除 os.makedirs(),目录创建留给 pipeline 执行 - 输出路径仅 widget 为空时填入默认值,不覆盖用户已选 - 输入路径从上游读取后添加 os.path.exists() 检查,阻断幽灵路径级联 - panel_factory._replay_live_panel_inputs 广播前校验文件确实存在 - step10 update_from_config 添加 os.path.isfile() 存在性检查 - 清理 step8/9/11 中冗余局部 import os(修复 UnboundLocalError) === 输出目录缺失 === - step7 新增 output_file FileSelectWidget,默认路径 7_Water_Quality_Indices/ - step9 output_file 从文件模式改为目录模式 (Directories) === 空目录自动创建 === - step12 _setup_prediction_output_dirs 移除 mkdir() 调用,改为只读日志 === 过期依赖与缺失 import === - panel_registry Step10 依赖 bsq_file→sampling_csv_file(匹配 CSV 模式重构) - step7 添加缺失的 import pandas as pd(修复 NameError) === 导航与 UI 一致性 === - water_quality_gui_v2 新增 _select_first_nav_item(),启动时默认选中第一项 - step1 输出卡片对齐 step8 风格 - step8 补充缺失的样式表和统一边距 === Step4 交互式光谱探针重构 === - 左右分栏 QSplitter 布局:左侧控制区 + 右侧 Matplotlib 视图 - 1x2 子图:ax1 散点图 + ax2 光谱曲线 - Hover 悬停 Annotation 显示坐标,Click 点击高亮+绘制光谱 - NavigationToolbar2QT 工具栏(保存/缩放/平移) - 自动检测坐标列和波段列,完善异常处理
This commit is contained in:
@ -31,8 +31,9 @@ from PyQt5.QtWidgets import (
|
||||
QPushButton, QLabel, QTabWidget, QToolBar, QSizePolicy,
|
||||
QListWidget, QListWidgetItem, QGroupBox,
|
||||
QTextEdit, QProgressBar, QMessageBox, QFileDialog,
|
||||
QSpinBox, QDoubleSpinBox, QComboBox,
|
||||
)
|
||||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtCore import Qt, QTimer, QSize
|
||||
from PyQt5.QtGui import QIcon, QFont, QPixmap, QColor, QTextCursor
|
||||
|
||||
if multiprocessing.current_process().name == 'MainProcess':
|
||||
@ -104,8 +105,11 @@ class WaterQualityGUI(QMainWindow):
|
||||
self._apply_stylesheet()
|
||||
self._disable_wheel_for_all_spinboxes()
|
||||
|
||||
# 第五步:延迟启动工作目录选择
|
||||
QTimer.singleShot(100, self._workspace_initializer.run)
|
||||
# 第五步:默认选中第一个步骤(延迟执行,确保导航列表和 Tab 均已就位)
|
||||
QTimer.singleShot(120, self._select_first_nav_item)
|
||||
|
||||
# 第六步:延迟启动工作目录选择
|
||||
QTimer.singleShot(200, self._workspace_initializer.run)
|
||||
|
||||
# ================================================================
|
||||
# Manager 初始化
|
||||
@ -395,9 +399,8 @@ class WaterQualityGUI(QMainWindow):
|
||||
|
||||
# 分隔符 (不需要实体占用高度,缩小即可)
|
||||
if stage_idx < len(stage_names) - 1:
|
||||
from PyQt5.QtCore import QSize # 正确引入 QSize
|
||||
sep = QListWidgetItem("")
|
||||
sep.setSizeHint(QSize(0, 10)) # 直接使用 QSize
|
||||
sep.setSizeHint(QSize(0, 10))
|
||||
sep.setFlags(sep.flags() & ~Qt.ItemIsSelectable & ~Qt.ItemIsEnabled)
|
||||
self._step_list.addItem(sep)
|
||||
|
||||
@ -467,15 +470,26 @@ class WaterQualityGUI(QMainWindow):
|
||||
continue
|
||||
try:
|
||||
panel.update_from_config(work_dir=work_dir, pipeline=None)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
# 2026-06-30:不再静默吞异常,至少通过 EventBus 输出日志
|
||||
self._event_bus.publish('LogMessage', {
|
||||
'message': f'[警告] 面板 {step_id} 的 update_from_config 失败: {e}',
|
||||
'level': 'warning',
|
||||
})
|
||||
|
||||
# ================================================================
|
||||
# 导航 → Tab 单向路由(左侧 List 驱动右侧 Tab,Tab 头部已隐藏)
|
||||
# ================================================================
|
||||
|
||||
def _select_first_nav_item(self):
|
||||
"""默认选中左侧导航栏的第一个可导航步骤项(跳过阶段标题/分隔符)。"""
|
||||
for i in range(self._step_list.count()):
|
||||
item = self._step_list.item(i)
|
||||
if item and item.data(Qt.UserRole) not in (None, "stage_header"):
|
||||
self._step_list.setCurrentRow(i)
|
||||
return
|
||||
|
||||
def _on_step_list_changed(self, index):
|
||||
from PyQt5.QtCore import Qt
|
||||
if index < 0: return
|
||||
item = self._step_list.item(index)
|
||||
if not item: return
|
||||
@ -609,7 +623,6 @@ class WaterQualityGUI(QMainWindow):
|
||||
self.setStyleSheet(ModernStylesheet.get_main_stylesheet())
|
||||
|
||||
def _disable_wheel_for_all_spinboxes(self):
|
||||
from PyQt5.QtWidgets import QSpinBox, QDoubleSpinBox, QComboBox
|
||||
for sb in self.findChildren(QSpinBox):
|
||||
sb.setFocusPolicy(Qt.StrongFocus)
|
||||
sb.wheelEvent = lambda e, s=sb: None
|
||||
|
||||
Reference in New Issue
Block a user