This commit is contained in:
duxin
2026-07-06 10:01:55 +08:00
parent 34ed062c77
commit f3aca09df4
6 changed files with 52 additions and 1641 deletions

View File

@ -67,8 +67,7 @@ docs = [
]
[project.scripts]
water-quality-gui = "gui.water_quality_gui:main"
water-quality-pipeline = "core.water_quality_inversion_pipeline:main"
water-quality-gui = "src.gui.water_quality_gui_v2:main"
[project.urls]
Homepage = "https://github.com/waterquality/water-quality-inversion"

View File

@ -2,12 +2,12 @@
chcp 65001 >nul
echo.
echo ================================================
echo 水质参数反演分析系统 - 打包工具
echo 水质参数反演分析系统 - 打包工具 (V2)
echo ================================================
echo.
:: 检查是否在正确目录
if not exist "src\gui\water_quality_gui.py" (
:: 检查是否在正确目录 (V2 入口)
if not exist "src\gui\water_quality_gui_v2.py" (
echo [错误] 请在项目根目录下运行此脚本!
pause
exit /b 1
@ -22,19 +22,14 @@ python -m pip install -r requirements.txt --quiet
python -m pip install pyinstaller --quiet
echo [3/4] 开始打包(首次可能需要 5-15 分钟,请耐心等待)...
pyinstaller --clean scripts/water_quality_gui.spec
echo.
echo [打包提示] 如果仍然出现 "No module named 'styles'",请检查:
echo 1. dist\water_quality_gui\styles.py 是否存在
echo 2. 是否需要添加 --collect-all styles 参数
pyinstaller --clean water_quality_app.spec
echo.
echo [4/4] 打包完成!
echo.
echo 输出位置:
echo dist\water_quality_gui\water_quality_gui.exe
echo dist\water_quality_gui\_internal\
echo dist\MegaWater\MegaWater.exe
echo dist\MegaWater\_internal\
echo.
echo 建议:
echo 1. 将 dist 文件夹整个复制给用户(包含所有依赖)

View File

@ -68,7 +68,7 @@ setup(
},
entry_points={
"console_scripts": [
"water-quality-gui=gui.water_quality_gui:main",
"water-quality-gui=src.gui.water_quality_gui_v2:main",
"water-quality-pipeline=core.water_quality_inversion_pipeline:main",
],
},

View File

@ -266,6 +266,13 @@ class PanelFactory:
# ★ 重新禁用滚轮update_from_config 可能动态创建了新的 SpinBox/ComboBox
_disable_wheel_for_widget(panel)
def replay_live_panel_inputs(self):
"""公开方法:重播所有已加载面板的输入值(供主窗口切页时调用)。
内部委托给 _replay_live_panel_inputs。
"""
self._replay_live_panel_inputs()
def _replay_live_panel_inputs(self):
"""遍历 PANEL_REGISTRY 依赖声明,从已加载面板实时读取属性值并强制广播。

File diff suppressed because it is too large Load Diff

View File

@ -16,9 +16,6 @@ WaterQualityGUI 只负责窗口框架标题栏、菜单栏、状态栏、QTab
- TrainingModeManager → 训练模式切换(发布 TrainingModeChanged 事件)
"""
import osgeo # noqa: F401
from osgeo import gdal, ogr # noqa: F401
import os
import sys
import ctypes
@ -450,7 +447,9 @@ class WaterQualityGUI(QMainWindow):
self._log_manager.progress_bar.setValue(100)
QMessageBox.information(self, "完成", "流程执行成功!\n\n请查看工作目录中的结果文件。")
else:
QMessageBox.critical(self, "失败", f"流程执行失败:\n\n{message[:200]}")
QMessageBox.critical(self, "失败",
f"流程执行失败:\n\n{message[:600]}"
+ ("\n...(已截断)" if len(message) > 600 else ""))
def _on_pipeline_stopped(self, data):
self._stop_btn.setEnabled(False)
@ -464,18 +463,20 @@ class WaterQualityGUI(QMainWindow):
work_dir = data.get('work_dir', '')
self.statusBar().showMessage(f"工作目录: {work_dir}")
# 遍历已加载面板,调用 update_from_config 重建内存级参数和默认输出路径
for step_id, panel in self._panel_factory.get_loaded_panels().items():
if not hasattr(panel, 'update_from_config'):
continue
try:
panel.update_from_config(work_dir=work_dir, pipeline=None)
except Exception as e:
# 2026-06-30不再静默吞异常至少通过 EventBus 输出日志
self._event_bus.publish('LogMessage', {
'message': f'[警告] 面板 {step_id} 的 update_from_config 失败: {e}',
'level': 'warning',
})
# 让当前激活的 Tab 立即基于新目录重算默认路径,覆盖掉旧值,绕过非空保护
from src.gui.core.panel_registry import PANEL_REGISTRY
active_idx = self._tab_widget.currentIndex()
if 0 <= active_idx < len(PANEL_REGISTRY):
active_step_id = PANEL_REGISTRY[active_idx]['step_id']
panel = self._panel_factory.get_panel(active_step_id)
if panel is not None and hasattr(panel, 'update_from_config'):
try:
panel.update_from_config(
work_dir=self._workspace_initializer.work_dir,
pipeline=None
)
except Exception:
pass
# ================================================================
# 导航 → Tab 单向路由(左侧 List 驱动右侧 TabTab 头部已隐藏)
@ -528,21 +529,16 @@ class WaterQualityGUI(QMainWindow):
"如果当前有流程正在运行,请勿修改此页面的参数。"
)
# 【新增修复】:在跳之前,再核实一遍要去的 tab_index 和 item_data 的 step_id 是否吻合!
# 如果因为删除了死文件导致索引错位,这里强行用真实 step_id 再找一遍!
# 【防御】:用已加载 panel 实例反查真实 Tab 索引,防止索引错位
try:
self._panel_factory.get_panel(item_data)
# 遍历右侧所有已加载的 Tab找到属于当前 step_id 的那个正确的 Tab 索引
for i in range(self._tab_widget.count()):
scroll_area = self._tab_widget.widget(i)
if scroll_area and hasattr(scroll_area, 'widget'):
real_panel = scroll_area.widget()
# 如果这个 panel 就是我们要找的 panel强制更新 tab_index
if real_panel == self._panel_factory.get_panel(item_data):
if scroll_area.widget() == panel:
tab_index = i
break
except Exception as e:
self._log_manager.error(f"页面实例化失败: {str(e)}")
self._log_manager.error(f"页面索引校验失败: {str(e)}")
return
# 2. 强制使用注册表的固定索引进行跳转
@ -551,7 +547,7 @@ class WaterQualityGUI(QMainWindow):
# 【新增修复】:每次切页时,强制重播所有面板的输入值!
# 原理:打破 preload_window 造成的时序差,确保目标页面能拿到源页面最新填写的值
if hasattr(self, '_panel_factory'):
self._panel_factory._replay_live_panel_inputs()
self._panel_factory.replay_live_panel_inputs()
# 3. 防撕裂回弹机制:如果由于某种原因没跳过去,把左边的蓝条强行拽回当前真实页面
if self._tab_widget.currentIndex() != tab_index:
@ -695,10 +691,6 @@ class WaterQualityGUI(QMainWindow):
def work_dir(self, value):
self._workspace_initializer.work_dir = value
@property
def pipeline(self):
return None
@property
def worker(self):
return self._pipeline_executor.worker
@ -718,6 +710,22 @@ def main():
if multiprocessing.current_process().name != 'MainProcess':
sys.exit(0)
# ★ GDAL 依赖检查(移至此处以利用 global_exception_handler 展示友好弹窗)
try:
import osgeo # noqa: F401
from osgeo import gdal, ogr # noqa: F401
except ImportError:
from PyQt5.QtWidgets import QMessageBox, QApplication as _QA
_qa = _QA.instance() or _QA(sys.argv)
QMessageBox.critical(
None, "依赖缺失",
"GDAL (osgeo) 未安装,程序无法运行。\n\n"
"请运行以下命令安装:\n"
" conda install -c conda-forge gdal\n"
"或访问 https://gdal.org/download.html"
)
sys.exit(1)
app = QApplication.instance()
if not app:
app = QApplication(sys.argv)