refactor: 实现第二批 Manager(LogManager/ConfigManager/DialogService/TrainingModeManager)

- log_manager.py: 日志区+进度条+清空按钮封装,内部订阅 LogMessage/ProgressUpdate

- config_manager.py: 配置读写(new/load/save/get_current_config),懒加载安全(未加载面板返回 {})

- dialog_service.py: 纯展示弹窗封装(Pipeline状态/关于/AI设置)

- training_mode_manager.py: 训练模式切换,发布 TrainingModeChanged 事件

- water_quality_gui_v2.py: 725→605 行,菜单回调全部委托给 Manager,移除 _create_log_panel/_create_progress_panel/_on_log_message/_on_progress_update
This commit is contained in:
DXC
2026-06-17 17:35:27 +08:00
parent 19c86e6e44
commit 39e8c29913
5 changed files with 517 additions and 153 deletions

View File

@ -0,0 +1,161 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
配置管理器
接管主窗口中所有配置读写逻辑:
- new_config() 清空所有面板配置
- load_config(file_path) 从 JSON 文件加载配置并回填面板
- save_config(file_path) 将当前配置保存为 JSON 文件
- get_current_config() 遍历 PanelFactory 收集配置(懒加载安全)
懒加载兼容原则:
- get_current_config() 仅遍历已加载面板,未加载面板返回空字典 {}
- 绝不为了拿配置而强行唤醒/渲染所有 Panel
- 如需全量配置(如保存),调用方应先执行 panel_factory.preload_all()
"""
import json
import os
from typing import Dict, Optional
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import QMessageBox, QFileDialog
from src.gui.core.event_bus import global_event_bus
class ConfigManager(QObject):
"""配置管理器。
用法::
cfg_mgr = ConfigManager(panel_factory, parent=self)
cfg_mgr.new_config() # 清空配置
cfg_mgr.load_config(path) # 加载 JSON
cfg_mgr.save_config(path) # 保存 JSON
config = cfg_mgr.get_current_config() # 收集当前配置
"""
def __init__(self, panel_factory, parent=None):
"""
Args:
panel_factory: PanelFactory 实例
parent: 父 QObject用于弹窗定位
"""
super().__init__(parent)
self._panel_factory = panel_factory
# ═══════════════════════════════════════════════════════════
# 公开 API
# ═══════════════════════════════════════════════════════════
def new_config(self):
"""清空所有面板配置(需用户确认)。"""
reply = QMessageBox.question(
self.parent(), "新建配置", "是否清空当前配置?",
QMessageBox.Yes | QMessageBox.No
)
if reply != QMessageBox.Yes:
return
for panel in self._panel_factory.get_loaded_panels().values():
if hasattr(panel, 'clear_config'):
panel.clear_config()
global_event_bus.publish('LogMessage', {
'message': '已清空配置',
'level': 'info',
})
def load_config(self, file_path: str = None):
"""从 JSON 文件加载配置并回填面板。
Args:
file_path: JSON 文件路径。若为 None弹出文件选择对话框。
"""
if file_path is None:
file_path, _ = QFileDialog.getOpenFileName(
self.parent(), "加载配置", "",
"JSON Files (*.json);;All Files (*.*)"
)
if not file_path:
return
try:
with open(file_path, 'r', encoding='utf-8') as f:
config = json.load(f)
except Exception as e:
QMessageBox.critical(
self.parent(), "加载失败",
f"无法读取配置文件:\n{file_path}\n\n错误: {e}"
)
return
# 回填已加载面板
loaded_count = 0
for step_id, panel in self._panel_factory.get_loaded_panels().items():
if step_id in config and hasattr(panel, 'set_config'):
try:
panel.set_config(config[step_id])
loaded_count += 1
except Exception:
pass
global_event_bus.publish('LogMessage', {
'message': f'已加载配置: {file_path}(回填 {loaded_count} 个面板)',
'level': 'info',
})
def save_config(self, file_path: str = None):
"""将当前配置保存为 JSON 文件。
注意保存前会强制加载所有面板preload_all确保配置完整。
Args:
file_path: 目标 JSON 文件路径。若为 None弹出保存对话框。
"""
if file_path is None:
file_path, _ = QFileDialog.getSaveFileName(
self.parent(), "保存配置", "config.json",
"JSON Files (*.json);;All Files (*.*)"
)
if not file_path:
return
# 保存前强制加载所有面板,确保配置完整
self._panel_factory.preload_all()
config = self.get_current_config()
try:
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
except Exception as e:
QMessageBox.critical(
self.parent(), "保存失败",
f"无法保存配置文件:\n{file_path}\n\n错误: {e}"
)
return
global_event_bus.publish('LogMessage', {
'message': f'已保存配置: {file_path}',
'level': 'info',
})
def get_current_config(self) -> Dict[str, dict]:
"""收集当前所有步骤的配置。
懒加载安全:仅遍历已加载面板,未加载面板返回空字典 {}
绝不为了拿配置而强行唤醒/渲染所有 Panel。
Returns:
{step_id: panel_config_dict}
"""
config = {}
for step_id, panel in self._panel_factory.get_loaded_panels().items():
if hasattr(panel, 'get_config'):
try:
config[step_id] = panel.get_config()
except Exception:
config[step_id] = {}
return config

View File

@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
对话框服务
封装纯展示类弹窗,从主窗口中彻底剥离 UI 对话框逻辑。
职责:
- show_pipeline_status() 显示 Pipeline 模块加载状态
- show_about() 显示"关于"对话框
- show_ai_settings() 显示 AI 引擎配置对话框
"""
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import QMessageBox
class DialogService(QObject):
"""对话框服务。
用法::
dlg_svc = DialogService(parent=self)
dlg_svc.show_about()
dlg_svc.show_pipeline_status()
dlg_svc.show_ai_settings()
"""
def __init__(self, parent=None):
super().__init__(parent)
# ═══════════════════════════════════════════════════════════
# 公开 API
# ═══════════════════════════════════════════════════════════
def show_pipeline_status(self):
"""显示 Pipeline 模块加载状态。"""
from src.gui.core.worker_thread import PIPELINE_AVAILABLE, PIPELINE_ERROR_INFO
if PIPELINE_AVAILABLE:
QMessageBox.information(
self.parent(), "Pipeline状态",
"Pipeline模块: 正常加载"
)
else:
detail = "\n".join(PIPELINE_ERROR_INFO)
QMessageBox.warning(
self.parent(), "Pipeline状态",
f"Pipeline模块: 加载失败\n\n{detail}"
)
def show_about(self):
"""显示"关于"对话框。"""
QMessageBox.about(
self.parent(), "关于",
"MegaCube-Water Quality V1.2\n\n"
"一个完整的水质参数反演工作流程工具\n\n"
"公司:北京依锐思遥感技术有限公司\n"
"地址北京市海淀区清河安宁庄东路18号5号楼二层205\n"
"电话010-51292601\n"
"邮箱hanshanlong@iris-rs.cn"
)
def show_ai_settings(self):
"""显示 AI 引擎配置对话框。"""
from src.gui.dialogs import AISettingsDialog
AISettingsDialog(self.parent()).exec_()

187
src/gui/core/log_manager.py Normal file
View File

@ -0,0 +1,187 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
日志与进度管理器
将主窗口中的日志区QTextEdit、进度条QProgressBar"清空日志"按钮
的 UI 创建与控制逻辑完全封装。
职责:
- create_log_panel() → 返回组装好的 QWidget日志 + 进度条)
- 内部订阅 LogMessage / ProgressUpdate 事件,自动更新 UI
- 主窗口无需再关心日志/进度的状态同步
订阅的事件:
LogMessage → {message, level} 写入日志区
ProgressUpdate → {percentage, message} 更新进度条
"""
from datetime import datetime
from PyQt5.QtCore import QObject
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout,
QGroupBox, QTextEdit, QProgressBar, QPushButton,
)
from src.gui.core.event_bus import global_event_bus
class LogManager(QObject):
"""日志与进度管理器。
用法::
log_mgr = LogManager(parent=self)
log_panel = log_mgr.create_log_panel()
layout.addWidget(log_panel)
# 之后所有日志/进度更新由 EventBus 自动驱动,无需手动操作
"""
def __init__(self, parent=None):
super().__init__(parent)
self._log_text: QTextEdit = None
self._progress_bar: QProgressBar = None
# 订阅事件
global_event_bus.subscribe('LogMessage', self._on_log_message)
global_event_bus.subscribe('ProgressUpdate', self._on_progress_update)
# ═══════════════════════════════════════════════════════════
# 公开 API
# ═══════════════════════════════════════════════════════════
def create_log_panel(self) -> QWidget:
"""创建并返回日志+进度面板的组装 Widget。
Returns:
QWidget: 包含日志区QGroupBox和进度条QGroupBox的垂直布局容器
"""
from src.gui.styles import ModernStylesheet
container = QWidget()
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(10)
# ── 日志区 ──
log_group = QGroupBox("执行日志")
log_group.setStyleSheet(f"""
QGroupBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border_light']};
border-radius: 5px; margin-top: 8px; padding-top: 15px;
padding-left: 9px; padding-right: 9px; padding-bottom: 9px;
}}
QGroupBox::title {{
subcontrol-origin: margin; subcontrol-position: top left;
padding: 0 5px; font-weight: bold;
color: {ModernStylesheet.COLORS['text_primary']};
}}
""")
log_layout = QVBoxLayout()
log_layout.setContentsMargins(5, 5, 5, 5)
self._log_text = QTextEdit()
self._log_text.setReadOnly(True)
self._log_text.setMaximumHeight(200)
self._log_text.setStyleSheet(f"""
QTextEdit {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 4px; padding: 5px;
font-family: 'Courier New', monospace; font-size: 10px;
}}
""")
log_layout.addWidget(self._log_text)
clear_btn = QPushButton("清空日志")
clear_btn.setMaximumWidth(100)
clear_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('normal'))
clear_btn.clicked.connect(self.clear_log)
btn_row = QHBoxLayout()
btn_row.addWidget(clear_btn)
btn_row.addStretch()
log_layout.addLayout(btn_row)
log_group.setLayout(log_layout)
layout.addWidget(log_group, 1)
# ── 进度条 ──
progress_group = QGroupBox("执行进度")
progress_group.setStyleSheet(f"""
QGroupBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border_light']};
border-radius: 5px; margin-top: 8px; padding-top: 10px;
padding-left: 9px; padding-right: 9px; padding-bottom: 9px;
}}
QGroupBox::title {{
subcontrol-origin: margin; subcontrol-position: top left;
padding: 0 5px; font-weight: bold;
color: {ModernStylesheet.COLORS['text_primary']};
}}
""")
progress_layout = QVBoxLayout()
progress_layout.setContentsMargins(5, 5, 5, 5)
self._progress_bar = QProgressBar()
self._progress_bar.setValue(0)
self._progress_bar.setStyleSheet(f"""
QProgressBar {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 4px; padding: 2px; text-align: center; height: 20px;
}}
QProgressBar::chunk {{
background-color: {ModernStylesheet.COLORS['success']}; border-radius: 3px;
}}
""")
progress_layout.addWidget(self._progress_bar)
progress_group.setLayout(progress_layout)
layout.addWidget(progress_group, 0)
container.setLayout(layout)
return container
def clear_log(self):
"""清空日志区。"""
if self._log_text is not None:
self._log_text.clear()
@property
def progress_bar(self) -> QProgressBar:
return self._progress_bar
@property
def log_text(self) -> QTextEdit:
return self._log_text
# ═══════════════════════════════════════════════════════════
# EventBus 订阅回调
# ═══════════════════════════════════════════════════════════
def _on_log_message(self, data: dict):
"""LogMessage 事件回调:写入日志区。"""
if self._log_text is None:
return
message = data.get('message', '')
level = data.get('level', 'info')
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
color_map = {'error': 'red', 'warning': 'orange'}
color = color_map.get(level, 'black')
formatted = f'<span style="color: {color};">[{timestamp}] {message}</span>'
self._log_text.append(formatted)
cursor = self._log_text.textCursor()
cursor.movePosition(QTextCursor.End)
self._log_text.setTextCursor(cursor)
def _on_progress_update(self, data: dict):
"""ProgressUpdate 事件回调:更新进度条。"""
if self._progress_bar is None:
return
percentage = data.get('percentage', 0)
self._progress_bar.setValue(percentage)

View File

@ -0,0 +1,68 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
训练模式管理器
管理"有训练数据模式"的勾选状态。
切换状态时通过 global_event_bus 发布 TrainingModeChanged 事件,
让需要响应的面板(如机器学习训练面板)自行订阅并刷新。
发布的事件:
TrainingModeChanged → {training_mode: bool} 面板订阅:根据模式启用/禁用控件
"""
from PyQt5.QtCore import QObject
from src.gui.core.event_bus import global_event_bus
class TrainingModeManager(QObject):
"""训练模式管理器。
用法::
mode_mgr = TrainingModeManager(parent=self)
mode_mgr.toggle(True) # 切换到有训练数据模式
mode_mgr.toggle(False) # 切换到无训练数据模式
is_training = mode_mgr.is_training_mode
"""
def __init__(self, parent=None):
super().__init__(parent)
self._training_mode: bool = True # 默认:有训练数据
# ═══════════════════════════════════════════════════════════
# 公开 API
# ═══════════════════════════════════════════════════════════
@property
def is_training_mode(self) -> bool:
return self._training_mode
def toggle(self, checked: bool):
"""切换训练模式。
Args:
checked: True=有训练数据模式, False=无训练数据模式
"""
self._training_mode = checked
global_event_bus.publish('LogMessage', {
'message': f'切换到{"有训练数据" if checked else "无训练数据"}模式',
'level': 'info',
})
global_event_bus.publish('TrainingModeChanged', {
'training_mode': checked,
})
def get_action_text(self, checked: bool) -> str:
"""返回菜单 Action 的显示文本。
Args:
checked: 当前勾选状态
Returns:
"有训练数据模式""无训练数据模式"
"""
return "有训练数据模式" if checked else "无训练数据模式"

View File

@ -10,12 +10,10 @@ WaterQualityGUI 只负责窗口框架标题栏、菜单栏、状态栏、QTab
- PanelFactory → 面板懒加载与生命周期
- PipelineExecutor → Pipeline 执行/停止/回调(通过 EventBus 发布状态)
- WorkspaceInitializer → 工作目录选择 + 自动回填(通过 EventBus 广播)
待实现的 Manager下一批
- ConfigManager → 配置读写
- LogManager → 日志 + 进度条
- TrainingModeManager → 训练模式切换
- DialogService → 各类对话框
- LogManager → 日志区 + 进度条(内部订阅 LogMessage/ProgressUpdate
- ConfigManager → 配置读写new/load/save/get_current_config
- DialogService → 纯展示类弹窗Pipeline状态/关于/AI设置
- TrainingModeManager → 训练模式切换(发布 TrainingModeChanged 事件)
"""
import osgeo # noqa: F401
@ -118,6 +116,10 @@ class WaterQualityGUI(QMainWindow):
from src.gui.core.panel_registry import PANEL_REGISTRY
from src.gui.core.workspace_initializer import WorkspaceInitializer
from src.gui.core.pipeline_executor import PipelineExecutor
from src.gui.core.log_manager import LogManager
from src.gui.core.config_manager import ConfigManager
from src.gui.core.dialog_service import DialogService
from src.gui.core.training_mode_manager import TrainingModeManager
from src.gui.core.event_bus import global_event_bus
self._panel_factory = PanelFactory(
@ -137,6 +139,17 @@ class WaterQualityGUI(QMainWindow):
parent=self,
)
self._log_manager = LogManager(parent=self)
self._config_manager = ConfigManager(
panel_factory=self._panel_factory,
parent=self,
)
self._dialog_service = DialogService(parent=self)
self._training_mode_manager = TrainingModeManager(parent=self)
self._event_bus = global_event_bus
# ================================================================
@ -283,8 +296,7 @@ class WaterQualityGUI(QMainWindow):
self._tab_widget.currentChanged.connect(self._on_tab_changed)
right_layout.addWidget(self._tab_widget, 3)
right_layout.addWidget(self._create_log_panel(), 1)
right_layout.addWidget(self._create_progress_panel(), 0)
right_layout.addWidget(self._log_manager.create_log_panel(), 1)
right_widget.setLayout(right_layout)
main_layout.addWidget(right_widget, 4)
@ -365,89 +377,6 @@ class WaterQualityGUI(QMainWindow):
)
return nav_widget
def _create_log_panel(self):
from src.gui.styles import ModernStylesheet
log_group = QGroupBox("执行日志")
log_group.setStyleSheet(f"""
QGroupBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border_light']};
border-radius: 5px; margin-top: 8px; padding-top: 15px;
padding-left: 9px; padding-right: 9px; padding-bottom: 9px;
}}
QGroupBox::title {{
subcontrol-origin: margin; subcontrol-position: top left;
padding: 0 5px; font-weight: bold;
color: {ModernStylesheet.COLORS['text_primary']};
}}
""")
log_layout = QVBoxLayout()
log_layout.setContentsMargins(5, 5, 5, 5)
self._log_text = QTextEdit()
self._log_text.setReadOnly(True)
self._log_text.setMaximumHeight(200)
self._log_text.setStyleSheet(f"""
QTextEdit {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
color: {ModernStylesheet.COLORS['text_primary']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 4px; padding: 5px;
font-family: 'Courier New', monospace; font-size: 10px;
}}
""")
log_layout.addWidget(self._log_text)
clear_btn = QPushButton("清空日志")
clear_btn.setMaximumWidth(100)
clear_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('normal'))
clear_btn.clicked.connect(self._log_text.clear)
btn_row = QHBoxLayout()
btn_row.addWidget(clear_btn)
btn_row.addStretch()
log_layout.addLayout(btn_row)
log_group.setLayout(log_layout)
return log_group
def _create_progress_panel(self):
from src.gui.styles import ModernStylesheet
progress_group = QGroupBox("执行进度")
progress_group.setStyleSheet(f"""
QGroupBox {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border_light']};
border-radius: 5px; margin-top: 8px; padding-top: 10px;
padding-left: 9px; padding-right: 9px; padding-bottom: 9px;
}}
QGroupBox::title {{
subcontrol-origin: margin; subcontrol-position: top left;
padding: 0 5px; font-weight: bold;
color: {ModernStylesheet.COLORS['text_primary']};
}}
""")
progress_layout = QVBoxLayout()
progress_layout.setContentsMargins(5, 5, 5, 5)
self._progress_bar = QProgressBar()
self._progress_bar.setValue(0)
self._progress_bar.setStyleSheet(f"""
QProgressBar {{
background-color: {ModernStylesheet.COLORS['panel_bg']};
border: 1px solid {ModernStylesheet.COLORS['border']};
border-radius: 4px; padding: 2px; text-align: center; height: 20px;
}}
QProgressBar::chunk {{
background-color: {ModernStylesheet.COLORS['success']}; border-radius: 3px;
}}
""")
progress_layout.addWidget(self._progress_bar)
progress_group.setLayout(progress_layout)
return progress_group
# ================================================================
# EventBus 连线UI 状态由事件驱动)
# ================================================================
@ -456,15 +385,13 @@ class WaterQualityGUI(QMainWindow):
self._event_bus.subscribe('PipelineStarted', self._on_pipeline_started)
self._event_bus.subscribe('PipelineFinished', self._on_pipeline_finished)
self._event_bus.subscribe('PipelineStopped', self._on_pipeline_stopped)
self._event_bus.subscribe('LogMessage', self._on_log_message)
self._event_bus.subscribe('ProgressUpdate', self._on_progress_update)
self._event_bus.subscribe('NavigateToTab', self._on_navigate_to_tab)
self._event_bus.subscribe('WorkspaceChanged', self._on_workspace_changed)
def _on_pipeline_started(self, data):
self._run_all_btn.setEnabled(False)
self._stop_btn.setEnabled(True)
self._progress_bar.setValue(0)
self._log_manager.progress_bar.setValue(0)
def _on_pipeline_finished(self, data):
self._run_all_btn.setEnabled(True)
@ -472,7 +399,7 @@ class WaterQualityGUI(QMainWindow):
success = data.get('success', False)
message = data.get('message', '')
if success:
self._progress_bar.setValue(100)
self._log_manager.progress_bar.setValue(100)
QMessageBox.information(self, "完成", "流程执行成功!\n\n请查看工作目录中的结果文件。")
else:
QMessageBox.critical(self, "失败", f"流程执行失败:\n\n{message[:200]}")
@ -481,24 +408,6 @@ class WaterQualityGUI(QMainWindow):
self._run_all_btn.setEnabled(True)
self._stop_btn.setEnabled(False)
def _on_log_message(self, data):
message = data.get('message', '')
level = data.get('level', 'info')
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
color_map = {'error': 'red', 'warning': 'orange'}
color = color_map.get(level, 'black')
formatted = f'<span style="color: {color};">[{timestamp}] {message}</span>'
self._log_text.append(formatted)
cursor = self._log_text.textCursor()
cursor.movePosition(QTextCursor.End)
self._log_text.setTextCursor(cursor)
def _on_progress_update(self, data):
percentage = data.get('percentage', 0)
message = data.get('message', '')
self._progress_bar.setValue(percentage)
self.statusBar().showMessage(message)
def _on_navigate_to_tab(self, data):
tab_index = data.get('tab_index', 0)
if 0 <= tab_index < self._tab_widget.count():
@ -593,56 +502,32 @@ class WaterQualityGUI(QMainWindow):
cb.wheelEvent = lambda e, c=cb: None
# ================================================================
# 菜单回调(待提取到对应 Manager 的临时占位
# 菜单回调(全部委托给对应 Manager
# ================================================================
def _on_new_config(self):
reply = QMessageBox.question(self, "新建配置", "是否清空当前配置?",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
self._event_bus.publish('LogMessage', {'message': '已清空配置', 'level': 'info'})
self._config_manager.new_config()
def _on_load_config(self):
file_path, _ = QFileDialog.getOpenFileName(
self, "加载配置", "", "JSON Files (*.json);;All Files (*.*)")
if file_path:
self._event_bus.publish('LogMessage',
{'message': f'已加载配置: {file_path}', 'level': 'info'})
self._config_manager.load_config()
def _on_save_config(self):
file_path, _ = QFileDialog.getSaveFileName(
self, "保存配置", "config.json", "JSON Files (*.json);;All Files (*.*)")
if file_path:
self._event_bus.publish('LogMessage',
{'message': f'已保存配置: {file_path}', 'level': 'info'})
self._config_manager.save_config()
def _on_ai_settings(self):
from src.gui.dialogs import AISettingsDialog
AISettingsDialog(self).exec_()
self._dialog_service.show_ai_settings()
def _on_toggle_training_mode(self, checked):
self._event_bus.publish('LogMessage', {
'message': f'切换到{"有训练数据" if checked else "无训练数据"}模式',
'level': 'info',
})
self._training_mode_action.setText("有训练数据模式" if checked else "无训练数据模式")
self._training_mode_manager.toggle(checked)
self._training_mode_action.setText(
self._training_mode_manager.get_action_text(checked)
)
def _on_show_pipeline_status(self):
from src.gui.core.worker_thread import PIPELINE_AVAILABLE, PIPELINE_ERROR_INFO
if PIPELINE_AVAILABLE:
QMessageBox.information(self, "Pipeline状态", "Pipeline模块: 正常加载")
else:
detail = "\n".join(PIPELINE_ERROR_INFO)
QMessageBox.warning(self, "Pipeline状态", f"Pipeline模块无法加载\n\n{detail}")
self._dialog_service.show_pipeline_status()
def _on_show_about(self):
QMessageBox.about(self, "关于",
"MegaCube-Water Quality V1.2\n\n"
"一个完整的水质参数反演工作流程工具\n\n"
"公司:北京依锐思遥感技术有限公司\n"
"地址北京市海淀区清河安宁庄东路18号5号楼二层205\n"
"电话010-51292601\n"
"邮箱hanshanlong@iris-rs.cn")
self._dialog_service.show_about()
# ================================================================
# 向后兼容属性
@ -675,11 +560,7 @@ class WaterQualityGUI(QMainWindow):
self._event_bus.publish('ProgressUpdate', {'percentage': percentage, 'message': message})
def get_current_config(self):
config = {}
for step_id, panel in self._panel_factory.get_loaded_panels().items():
if hasattr(panel, 'get_config'):
config[step_id] = panel.get_config()
return config
return self._config_manager.get_current_config()
# ============================================================