diff --git a/src/gui/core/panel_registry.py b/src/gui/core/panel_registry.py index 6e80dec..dfa6ed6 100644 --- a/src/gui/core/panel_registry.py +++ b/src/gui/core/panel_registry.py @@ -18,7 +18,7 @@ from src.gui.panels.step3_panel import Step3Panel from src.gui.panels.step4_sampling_panel import Step4SamplingPanel from src.gui.panels.step5_clean_panel import Step5CleanPanel from src.gui.panels.step6_feature_panel import Step6FeaturePanel -from src.gui.panels.step7_index_panel import Step7IndexPanel +from src.new.views.step7_view import Step7View from src.gui.panels.step8_ml_train_panel import Step8MlTrainPanel from src.gui.panels.step9_ml_predict_panel import Step9MlPredictPanel from src.gui.panels.step10_watercolor_panel import Step10WatercolorPanel @@ -112,7 +112,7 @@ PANEL_REGISTRY = [ }, { 'step_id': 'step7_index', - 'class_ref': Step7IndexPanel, + 'class_ref': Step7View, 'title': '水质光谱指数计算', 'icon': '7.png', 'stage': '阶段二:样本数据准备', diff --git a/src/gui/core/pipeline_executor.py b/src/gui/core/pipeline_executor.py index 26f3884..dc44477 100644 --- a/src/gui/core/pipeline_executor.py +++ b/src/gui/core/pipeline_executor.py @@ -409,6 +409,8 @@ class PipelineExecutor(QObject): step_name = data.get('step_name') config = data.get('config') + print(f"==== Executor 收到单步请求: {step_name} ====", flush=True) + if not step_name: global_event_bus.publish('LogMessage', { 'message': '[单步执行] 请求缺少 step_name,忽略', @@ -416,6 +418,18 @@ class PipelineExecutor(QObject): }) return + # ★ 防死锁:若已有 Worker 在运行,不静默吞掉,而是通知用户 + if self.is_running: + global_event_bus.publish('LogMessage', { + 'message': f'[单步执行] 后台正在运行中,无法启动 {step_name}。请等待当前任务完成或手动停止后再试。', + 'level': 'warning', + }) + QMessageBox.warning( + self.parent(), "后台忙碌", + f"后台正在运行中,无法启动 {step_name}。\n\n请等待当前任务完成,或点击「停止」按钮后再试。" + ) + return + global_event_bus.publish('LogMessage', { 'message': f'[单步执行] 收到 {step_name} 的执行请求', 'level': 'info', diff --git a/src/gui/core/worker_thread.py b/src/gui/core/worker_thread.py index aaef421..5a4dfa6 100644 --- a/src/gui/core/worker_thread.py +++ b/src/gui/core/worker_thread.py @@ -338,8 +338,18 @@ class WorkerThread(QThread): pass def run_single_step(self, scheduler, step_name, config): - """使用新调度器运行单个步骤。""" - step_config = dict(config.get(step_name, {})) + """使用新调度器运行单个步骤。 + + config 兼容两种格式: + 嵌套格式:{'step7': {'training_csv_path': ..., ...}} + 扁平格式:{'training_csv_path': ..., 'formula_names': [...], ...} + 优先检测嵌套格式;若 step_name 对应的子 dict 为空,则回退到扁平格式。 + """ + nested = config.get(step_name) + if nested and isinstance(nested, dict) and len(nested) > 0: + step_config = dict(nested) + else: + step_config = dict(config) # 透传外部预训练模型(非空才覆盖) for key in ('_external_model', '_external_model_path', diff --git a/src/gui/panels/step7_index_panel.py b/src/gui/panels/step7_index_panel.py index 8bec72b..2807034 100644 --- a/src/gui/panels/step7_index_panel.py +++ b/src/gui/panels/step7_index_panel.py @@ -123,6 +123,7 @@ class Step7IndexPanel(QWidget): self.formula_list = QListWidget() self.formula_list.setSelectionMode(QAbstractItemView.MultiSelection) + self.formula_list.setMinimumHeight(300) self.formula_list.itemChanged.connect(self._on_item_changed) self.formula_layout.addWidget(self.formula_list) diff --git a/src/new/views/step7_view.py b/src/new/views/step7_view.py index fa8adf3..8a407a0 100644 --- a/src/new/views/step7_view.py +++ b/src/new/views/step7_view.py @@ -129,9 +129,10 @@ class Step7View(BaseView): self.formula_list.setSelectionMode(QListWidget.MultiSelection) self.formula_list.setMinimumHeight(300) self.formula_list.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + self.formula_list.setUniformItemSizes(True) # view 层不需要 itemChanged 副作用;service 接管时再启用 self.formula_list.blockSignals(True) - formula_outer_layout.addWidget(self.formula_list) + formula_outer_layout.addWidget(self.formula_list, stretch=1) self.formula_group.setLayout(formula_outer_layout) layout.addWidget(self.formula_group) @@ -233,6 +234,8 @@ class Step7View(BaseView): self.index_checkboxes[name] = item self.formula_list.blockSignals(False) self.formula_list.adjustSize() + self.formula_list.updateGeometry() + self.update() for btn in (self.select_all_btn, self.deselect_all_btn, self.select_ratio_btn, self.select_conc_btn, self.refresh_button): @@ -319,6 +322,14 @@ class Step7View(BaseView): # 执行入口 # ------------------------------------------------------------------ def _on_run_single_clicked(self): - from src.gui.core.event_bus import global_event_bus - config = self.get_config() - global_event_bus.publish('RequestRunSingleStep', {'step_name': 'step7', 'config': config}) + import traceback + print("==== Step 7 计算按钮物理按下 ====", flush=True) + try: + from src.gui.core.event_bus import global_event_bus + config = self.get_config() + wrapped_config = {'step7_index': config} + global_event_bus.publish('RequestRunSingleStep', {'step_name': 'step7_index', 'config': wrapped_config}) + except Exception as e: + traceback.print_exc() + from PyQt5.QtWidgets import QMessageBox + QMessageBox.critical(self, "Step7 发射失败", f"收集配置或发送请求时异常:\n\n{e}")