diff --git a/algorithm/pq_algorithm.py b/algorithm/pq_algorithm.py index 035af91..080e12e 100644 --- a/algorithm/pq_algorithm.py +++ b/algorithm/pq_algorithm.py @@ -40,7 +40,7 @@ def calculate_gamut_coverage(points1, points2): return intersection_area, coverage except Exception as e: - print(f"[Error] 计算色域覆盖率失败: {e}") + print(f"计算色域覆盖率失败: {e}") return 0.0, 0.0 @@ -227,7 +227,7 @@ def calculate_uv_gamut_coverage(uv_coords, reference="DCI-P3"): return coverage except Exception as e: - print(f"[Error] 计算 u'v' 色域覆盖率失败: {str(e)}") + print(f"计算 u'v' 色域覆盖率失败: {str(e)}") import traceback traceback.print_exc() diff --git a/app/config_io.py b/app/config_io.py index bb7cd74..5fa6781 100644 --- a/app/config_io.py +++ b/app/config_io.py @@ -78,7 +78,7 @@ def clear_config_file(self): self.log_gui.log("配置文件不存在", level="error") except Exception as e: - messagebox.showerror("错误", "[Error] 清理失败") - self.log_gui.log(f"[Error] 配置文件清理失败: {str(e)}", level="error") + messagebox.showerror("错误", "清理失败") + self.log_gui.log(f"配置文件清理失败: {str(e)}", level="error") diff --git a/app/pq/pq_config.py b/app/pq/pq_config.py index 82ef750..423a750 100644 --- a/app/pq/pq_config.py +++ b/app/pq/pq_config.py @@ -621,14 +621,14 @@ if __name__ == "__main__": if current_count == 29: print(" set_current_pattern 工作正常") else: - print(f" [Error] set_current_pattern 失败!只有 {current_count} 个图案") + print(f" set_current_pattern 失败!只有 {current_count} 个图案") else: - print(f"\n[Error] 配置错误!") + print(f"\n配置错误!") print(f" 期望: 29 个图案, measurement_max_value=28") print(f" 实际: {pattern_count} 个图案, measurement_max_value={max_value}") - print("\n[Error] 请检查 default_pattern_accuracy 定义!") + print("\n请检查 default_pattern_accuracy 定义!") print(" 应该包含:") print(" - 5个灰阶") print(" - 18个 ColorChecker 色块") diff --git a/app/pq/pq_result.py b/app/pq/pq_result.py index 5301795..60c3c78 100644 --- a/app/pq/pq_result.py +++ b/app/pq/pq_result.py @@ -414,6 +414,122 @@ class PQResult: } +class PQResultStore: + """按 test_type 管理多个 PQResult 实例。 + + 解决两个问题: + 1. `self.results` 在测试流程启动前就存在(避免 AttributeError / NoneType 访问)。 + 2. 支持同时保留多种 test_type(screen_module / sdr_movie / hdr_movie)的历史结果, + 而不是每次启动新测试就把上一次的结果覆盖掉。 + + 使用方式: + # 主类 __init__ 中: + self.results = PQResultStore() + + # 启动一次新测试时: + self.results.new("screen_module", "屏模组性能测试") + + # 现有调用点(隐式访问当前活跃结果)仍然生效: + self.results.add_intermediate_data("gamut", "rgb", data) + self.results.get_intermediate_data("shared", "gray") + + # 跨类型显式访问某次历史结果: + pq = self.results.get("sdr_movie") + if pq is not None: + data = pq.get_intermediate_data("gamut", "rgb") + """ + + # __getattr__ 代理时,这些方法若在无活跃结果时被调用,返回 None 而不是报错, + # 以兼容"尝试读取但数据还没来"的场景。 + _SAFE_GETTERS = frozenset({ + "get_intermediate_data", + "has_intermediate_data", + "get_all_intermediate_data", + "get_test_summary", + "get_progress_info", + "to_dict", + }) + + def __init__(self): + self._results: Dict[str, PQResult] = {} + self._active_type: Optional[str] = None + + # ---------- 显式 API ---------- + + def new(self, test_type: str, test_name: str) -> PQResult: + """为指定 test_type 创建新的 PQResult,并置为当前活跃。 + + 若该 test_type 已有旧结果,会被替换。 + """ + result = PQResult(test_type=test_type, test_name=test_name) + self._results[test_type] = result + self._active_type = test_type + return result + + def get(self, test_type: str) -> Optional[PQResult]: + """按 test_type 取结果;不存在则返回 None。""" + return self._results.get(test_type) + + def has(self, test_type: str) -> bool: + """判断某个 test_type 是否有结果。""" + return test_type in self._results + + def set_active(self, test_type: str) -> bool: + """切换当前活跃结果。成功返回 True。""" + if test_type in self._results: + self._active_type = test_type + return True + return False + + def clear(self, test_type: Optional[str] = None) -> None: + """清空结果。不传参数清全部,否则只清指定 test_type。""" + if test_type is None: + self._results.clear() + self._active_type = None + else: + self._results.pop(test_type, None) + if self._active_type == test_type: + self._active_type = None + + @property + def current(self) -> Optional[PQResult]: + """当前活跃的 PQResult,无则返回 None。""" + if self._active_type is None: + return None + return self._results.get(self._active_type) + + @property + def current_test_type(self) -> Optional[str]: + return self._active_type + + @property + def all_types(self) -> List[str]: + return list(self._results.keys()) + + # ---------- 兼容性:透明代理到 current ---------- + + def __bool__(self) -> bool: + """`if self.results:` 仍可用于判断当前是否有活跃结果。""" + return self.current is not None + + def __getattr__(self, name: str) -> Any: + # 只有常规属性查找失败时才会走到这里 + if name.startswith("_"): + raise AttributeError(name) + current = self.current + if current is not None: + return getattr(current, name) + # 无活跃结果:读类方法返回空值 stub;写类方法抛出清晰错误 + if name in self._SAFE_GETTERS: + def _null_getter(*_args, **_kwargs): + return None + return _null_getter + raise AttributeError( + f"PQResultStore 当前没有活跃的 PQResult(还未调用 new());" + f"无法访问 '{name}'。如需按 test_type 取历史结果,请用 .get(test_type)。" + ) + + # 使用示例和工具函数 def create_pq_result_from_config(config: Dict[str, Any]) -> PQResult: """根据配置创建PQResult实例""" diff --git a/app/runner/test_runner.py b/app/runner/test_runner.py index c798c9f..9e8c138 100644 --- a/app/runner/test_runner.py +++ b/app/runner/test_runner.py @@ -17,7 +17,8 @@ from app.data_range_converter import convert_pattern_params from app.pq.pq_result import PQResult def new_pq_results(self, test_type, test_name): - self.results = PQResult(test_type, test_name) + # 通过 PQResultStore 创建/替换指定 test_type 的结果,并设为当前活跃 + self.results.new(test_type, test_name) # 设置配置 config = { "test_type": test_type, @@ -319,7 +320,7 @@ def send_fix_pattern(self, mode): elif mode == "custom": self.config.set_current_pattern("custom") else: - self.log_gui.log(f"[Error] 未知的图案模式: {mode}", level="error") + self.log_gui.log(f"未知的图案模式: {mode}", level="error") return None # 2. 获取当前测试类型 @@ -364,7 +365,7 @@ def send_fix_pattern(self, mode): if success: self.log_gui.log("SDR 信号格式设置成功", level="success") else: - self.log_gui.log("[Error] SDR 信号格式设置失败", level="error") + self.log_gui.log("SDR 信号格式设置失败", level="error") # 设置图案参数 if mode == "accuracy": @@ -451,7 +452,7 @@ def send_fix_pattern(self, mode): if success: self.log_gui.log("HDR 信号格式设置成功", level="success") else: - self.log_gui.log("[Error] HDR 信号格式设置失败", level="error") + self.log_gui.log("HDR 信号格式设置失败", level="error") # 设置图案参数 if mode == "accuracy": @@ -623,7 +624,7 @@ def send_fix_pattern(self, mode): return results except Exception as e: - self.log_gui.log(f"[Error] 发送图案失败: {str(e)}", level="error") + self.log_gui.log(f"发送图案失败: {str(e)}", level="error") import traceback self.log_gui.log(traceback.format_exc(), level="error") @@ -1119,7 +1120,7 @@ def test_color_accuracy(self, test_type): measured_data_list = self.send_fix_pattern("accuracy") if measured_data_list is None or len(measured_data_list) != 29: - self.log_gui.log(f"[Error] 数据数量不匹配", level="error") + self.log_gui.log(f"数据数量不匹配", level="error") self.log_gui.log(f" 期望: 29 个", level="info") self.log_gui.log( f" 实际: {len(measured_data_list) if measured_data_list else 0} 个" diff --git a/app/tests/local_dimming.py b/app/tests/local_dimming.py index 1568eae..f0c17a3 100644 --- a/app/tests/local_dimming.py +++ b/app/tests/local_dimming.py @@ -127,11 +127,11 @@ def start_local_dimming_test(self): try: image_path = _ensure_window_image(width, height, percentage) except Exception as e: - log(f" [Error] 图像生成失败: {e}", level="error") + log(f" 图像生成失败: {e}", level="error") continue if not send_image_pattern(self.ucd, image_path): - log(f" [Error] {percentage}% 窗口发送失败,跳过", level="error") + log(f" {percentage}% 窗口发送失败,跳过", level="error") continue log(f"等待 {wait_time} 秒...", level="info") @@ -140,10 +140,10 @@ def start_local_dimming_test(self): try: x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay() except Exception as e: - log(f" [Error] 采集亮度异常: {e}", level="error") + log(f" 采集亮度异常: {e}", level="error") continue if lv is None: - log(f" [Error] {percentage}% 窗口采集失败", level="error") + log(f" {percentage}% 窗口采集失败", level="error") continue log(f"采集亮度: {lv:.2f} cd/m²", level="info") @@ -192,12 +192,12 @@ def send_ld_window(self, percentage): try: image_path = _ensure_window_image(width, height, percentage) except Exception as e: - self._dispatch_ui(self.log_gui.log, f"[Error] 图像生成失败: {e}") + self._dispatch_ui(self.log_gui.log, f"图像生成失败: {e}") return ok = send_image_pattern(self.ucd, image_path) msg = ( f"{percentage}% 窗口已发送" if ok - else f"[Error] {percentage}% 窗口发送失败" + else f"{percentage}% 窗口发送失败" ) self._dispatch_ui(self.log_gui.log, msg) @@ -219,10 +219,10 @@ def measure_ld_luminance(self): try: x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay() except Exception as e: - self._dispatch_ui(self.log_gui.log, f"[Error] 采集异常: {str(e)}") + self._dispatch_ui(self.log_gui.log, f"采集异常: {str(e)}") return if lv is None: - self._dispatch_ui(self.log_gui.log, "[Error] 采集失败") + self._dispatch_ui(self.log_gui.log, "采集失败") return timestamp = datetime.datetime.now().strftime("%H:%M:%S") self._dispatch_ui( @@ -277,5 +277,5 @@ def save_local_dimming_results(self): self.log_gui.log(f"测试结果已保存: {save_path}", level="success") messagebox.showinfo("成功", f"测试结果已保存到:\n{save_path}") except Exception as e: - self.log_gui.log(f"[Error] 保存失败: {str(e)}", level="error") + self.log_gui.log(f"保存失败: {str(e)}", level="error") messagebox.showerror("错误", f"保存失败: {str(e)}") diff --git a/app/views/chart_frame.py b/app/views/chart_frame.py index d763bf4..e181990 100644 --- a/app/views/chart_frame.py +++ b/app/views/chart_frame.py @@ -801,8 +801,6 @@ def create_result_chart_frame(self): # 创建单步调试面板实例 self.debug_panel = PQDebugPanel(self.debug_container, self) - self.log_gui.log("单步调试面板已创建(放在测试结果图表下方)", level="success") - def on_chart_tab_changed(self, event): """Tab切换时的事件处理""" try: diff --git a/app/views/panels/cct_panel.py b/app/views/panels/cct_panel.py index e98883b..aa125d6 100644 --- a/app/views/panels/cct_panel.py +++ b/app/views/panels/cct_panel.py @@ -94,7 +94,7 @@ def create_cct_params_frame(self): text="打开调试面板", command=self.toggle_screen_debug_panel, bootstyle="info-outline", - # state=tk.DISABLED, # 初始禁用 + state=tk.DISABLED, # 初始禁用 width=15, ) self.screen_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3) @@ -211,7 +211,7 @@ def create_cct_params_frame(self): text="打开调试面板", command=self.toggle_sdr_debug_panel, bootstyle="info-outline", - # state=tk.DISABLED, # 初始禁用 + state=tk.DISABLED, # 初始禁用 width=15, ) self.sdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3) @@ -328,7 +328,7 @@ def create_cct_params_frame(self): text="打开调试面板", command=self.toggle_hdr_debug_panel, bootstyle="info-outline", - # state=tk.DISABLED, # 初始禁用 + state=tk.DISABLED, # 初始禁用 width=15, ) self.hdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3) @@ -405,9 +405,9 @@ def _save_cct_params_for(self, test_type): """保存指定测试类型的 CCT 参数。""" try: default_params = self.config.get_default_cct_params(test_type) - var_dict = self._get_cct_var_dict(test_type) + var_dict = _get_cct_var_dict(test_type) cct_params = { - key: self._parse_cct_float(var_dict[key], default_params[key]) + key: _parse_cct_float(var_dict[key], default_params[key]) for key in default_params } @@ -452,22 +452,22 @@ def _handle_cct_focus_out(self, var, default_value, save_func, label): def on_sdr_cct_param_focus_out(self, var, default_value): """SDR 色度参数失去焦点时的处理。""" - self._handle_cct_focus_out(var, default_value, self.save_sdr_cct_params, "SDR") + _handle_cct_focus_out(var, default_value, self.save_sdr_cct_params, "SDR") def save_sdr_cct_params(self): """保存 SDR 色度参数。""" - self._save_cct_params_for("sdr_movie") + _save_cct_params_for("sdr_movie") def on_hdr_cct_param_focus_out(self, var, default_value): """HDR 色度参数失去焦点时的处理。""" - self._handle_cct_focus_out(var, default_value, self.save_hdr_cct_params, "HDR") + _handle_cct_focus_out(var, default_value, self.save_hdr_cct_params, "HDR") def save_hdr_cct_params(self): """保存 HDR 色度参数。""" - self._save_cct_params_for("hdr_movie") + _save_cct_params_for("hdr_movie") def recalculate_cct(self): @@ -527,7 +527,7 @@ def recalculate_cct(self): messagebox.showinfo("成功", "色度图已根据新参数重新绘制!") except Exception as e: - self.log_gui.log(f"[Error] 重新计算失败: {str(e)}", level="error") + self.log_gui.log(f"重新计算失败: {str(e)}", level="error") self.log_gui.log(traceback.format_exc(), level="error") messagebox.showerror("错误", f"重新计算失败: {str(e)}") @@ -675,19 +675,19 @@ def recalculate_gamut(self): ) except Exception as e: - self.log_gui.log(f"[Error] 重新计算失败: {str(e)}", level="error") + self.log_gui.log(f"重新计算失败: {str(e)}", level="error") self.log_gui.log(traceback.format_exc(), level="error") messagebox.showerror("错误", f"重新计算失败: {str(e)}") def on_cct_param_focus_out(self, var, default_value): """色度参数失去焦点时的处理 - 空值恢复默认""" - self._handle_cct_focus_out(var, default_value, self.save_cct_params, "屏模组") + _handle_cct_focus_out(var, default_value, self.save_cct_params, "屏模组") def save_cct_params(self): """保存色度参数 - 简化版""" - self._save_cct_params_for(self.config.current_test_type) + _save_cct_params_for(self.config.current_test_type) def reload_cct_params(self): @@ -743,7 +743,7 @@ def toggle_cct_params_frame(self): self.hdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5) else: if hasattr(self, "log_gui"): - self.log_gui.log("[ERROR] HDR 色度参数框尚未创建", level="error") + self.log_gui.log("HDR 色度参数框尚未创建", level="error") # ---- gamut 参考标准改变回调(统一实现) ---- diff --git a/app/views/panels/custom_template_panel.py b/app/views/panels/custom_template_panel.py index 6cbafc9..d2b0f8e 100644 --- a/app/views/panels/custom_template_panel.py +++ b/app/views/panels/custom_template_panel.py @@ -232,10 +232,10 @@ def start_custom_row_single_step(self): children = list(self.custom_result_tree.get_children()) row_no = children.index(item_id) + 1 if item_id in children else 1 - self._clear_custom_result_row(item_id, row_no) + _clear_custom_result_row(item_id, row_no) threading.Thread( - target=self._run_custom_row_single_step, + target=_run_custom_row_single_step, args=(item_id, row_no), daemon=True, ).start() @@ -295,7 +295,7 @@ def _run_custom_row_single_step(self, item_id, row_no): ) if row_no > len(converted_params): - self.log_gui.log(f"[Error] 行号超出 pattern 范围: {row_no}/{len(converted_params)}", level="error") + self.log_gui.log(f"行号超出 pattern 范围: {row_no}/{len(converted_params)}", level="error") self._dispatch_ui(self.status_var.set, "单步测试失败:行号超范围") return @@ -332,14 +332,14 @@ def _run_custom_row_single_step(self, item_id, row_no): } self._dispatch_ui( - self._update_custom_result_row, item_id, row_no, row_data + _update_custom_result_row, item_id, row_no, row_data ) self.log_gui.log(f"第 {row_no} 行单步测试完成并已覆盖", level="success") self._dispatch_ui(self.status_var.set, f"第 {row_no} 行单步测试完成") except Exception as e: - self.log_gui.log(f"[Error] 单步测试失败: {str(e)}", level="error") + self.log_gui.log(f"单步测试失败: {str(e)}", level="error") self._dispatch_ui(self.status_var.set, "单步测试失败") @@ -425,49 +425,6 @@ def copy_custom_result_table(self): if hasattr(self, "log_gui"): self.log_gui.log(f"已复制客户模板表格数据({len(items)} 行)", level="success") - -def fill_custom_result_test_data(self): - """填充 147 行客户模板测试数据(用于界面验证)""" - if not hasattr(self, "custom_result_tree"): - return - - self.clear_custom_template_results() - - pattern_names = [] - if hasattr(self, "config") and hasattr(self.config, "get_temp_pattern_names"): - pattern_names = self.config.get_temp_pattern_names() - - total_rows = 147 - for i in range(1, total_rows + 1): - ratio = (i - 1) / (total_rows - 1) if total_rows > 1 else 0 - row_data = { - "pattern_name": ( - pattern_names[i - 1] if i - 1 < len(pattern_names) else f"P {i}" - ), - "X": 0.8 + ratio * 120, - "Y": 0.9 + ratio * 135, - "Z": 1.1 + ratio * 145, - "x": 0.24 + ratio * 0.10, - "y": 0.26 + ratio * 0.10, - "Lv": 1.0 + ratio * 500, - "u_prime": 0.16 + ratio * 0.12, - "v_prime": 0.42 + ratio * 0.08, - "Tcp": 1800 + ratio * 12000, - "duv": -0.01 + ratio * 0.03, - "lambda_d": 430 + ratio * 200, - "Pe": 10 + ratio * 90, - } - self.append_custom_template_result(i, row_data) - - if hasattr(self, "chart_notebook") and hasattr(self, "custom_template_tab_frame"): - self.chart_notebook.select(self.custom_template_tab_frame) - - if hasattr(self, "status_var"): - self.status_var.set("已填充 147 行客户模板测试数据") - if hasattr(self, "log_gui"): - self.log_gui.log("已填充 147 行客户模板测试数据", level="success") - - def clear_custom_template_results(self): """清空客户模板结果表格""" if not hasattr(self, "custom_result_tree"): @@ -615,3 +572,45 @@ def update_custom_button_visibility(self): else: if self.custom_btn.winfo_manager(): self.custom_btn.pack_forget() + + +# def fill_custom_result_test_data(self): +# """填充 147 行客户模板测试数据(用于界面验证)""" +# if not hasattr(self, "custom_result_tree"): +# return + +# self.clear_custom_template_results() + +# pattern_names = [] +# if hasattr(self, "config") and hasattr(self.config, "get_temp_pattern_names"): +# pattern_names = self.config.get_temp_pattern_names() + +# total_rows = 147 +# for i in range(1, total_rows + 1): +# ratio = (i - 1) / (total_rows - 1) if total_rows > 1 else 0 +# row_data = { +# "pattern_name": ( +# pattern_names[i - 1] if i - 1 < len(pattern_names) else f"P {i}" +# ), +# "X": 0.8 + ratio * 120, +# "Y": 0.9 + ratio * 135, +# "Z": 1.1 + ratio * 145, +# "x": 0.24 + ratio * 0.10, +# "y": 0.26 + ratio * 0.10, +# "Lv": 1.0 + ratio * 500, +# "u_prime": 0.16 + ratio * 0.12, +# "v_prime": 0.42 + ratio * 0.08, +# "Tcp": 1800 + ratio * 12000, +# "duv": -0.01 + ratio * 0.03, +# "lambda_d": 430 + ratio * 200, +# "Pe": 10 + ratio * 90, +# } +# self.append_custom_template_result(i, row_data) + +# if hasattr(self, "chart_notebook") and hasattr(self, "custom_template_tab_frame"): +# self.chart_notebook.select(self.custom_template_tab_frame) + +# if hasattr(self, "status_var"): +# self.status_var.set("已填充 147 行客户模板测试数据") +# if hasattr(self, "log_gui"): +# self.log_gui.log("已填充 147 行客户模板测试数据", level="success") diff --git a/app/views/panels/main_layout.py b/app/views/panels/main_layout.py index e23317f..ed6dbbe 100644 --- a/app/views/panels/main_layout.py +++ b/app/views/panels/main_layout.py @@ -544,7 +544,7 @@ def on_screen_module_timing_changed(self, event=None): self.save_pq_config() except Exception as e: - self.log_gui.log(f"[Error] 屏模组信号格式更改失败: {str(e)}", level="error") + self.log_gui.log(f"屏模组信号格式更改失败: {str(e)}", level="error") def update_test_items(self): diff --git a/app/views/panels/side_panels.py b/app/views/panels/side_panels.py index aec3740..42e5758 100644 --- a/app/views/panels/side_panels.py +++ b/app/views/panels/side_panels.py @@ -1,4 +1,4 @@ -"""侧边面板(日志 / Local Dimming / 调试)(Step 6 重构)。""" +"""侧边面板(日志 / Local Dimming / 调试)""" import traceback import tkinter as tk @@ -258,9 +258,11 @@ def _toggle_debug_panel(self, test_type): try: selected_items = self.get_selected_test_items() dlp = cfg["data_log_prefix"] - results_obj = getattr(self, "results", None) + # 显式按 test_type 拿历史结果,避免依赖"当前活跃"状态 + results_store = getattr(self, "results", None) + results_obj = results_store.get(test_type) if results_store is not None else None if results_obj is None: - self.log_gui.log(f"{dlp} 暂无可用测试结果,面板已打开", level="warning") + self.log_gui.log(f"{dlp} 暂无 {test_type} 的测试结果,面板已打开", level="warning") else: for item_key, debug_key, (cat, sub), data_label, enable_desc in cfg["data_items"]: if item_key not in selected_items: @@ -268,11 +270,10 @@ def _toggle_debug_panel(self, test_type): data = results_obj.get_intermediate_data(cat, sub) if not data: if test_type == "screen_module" and item_key == "gamma": - self.log_gui.log("[Error] 没有可用的灰阶数据", level="error") + self.log_gui.log("没有可用的灰阶数据", level="error") continue self.log_gui.log(f" → 加载 {len(data)} 个{data_label}数据点", level="info") debug_panel_instance.enable_debug(test_type, debug_key, data) - self.log_gui.log(f"{dlp} {enable_desc}已重新启用", level="success") except Exception as e: self.log_gui.log(f"加载{cfg['failure_data_label']}失败: {str(e)}", level="error") self.log_gui.log(traceback.format_exc(), level="error") @@ -282,13 +283,10 @@ def _toggle_debug_panel(self, test_type): def on_closing(): btn.config(text="打开调试面板") getattr(self, win_attr).destroy() - self.log_gui.log(f"{wlp}单步调试窗口已关闭", level="success") win.protocol("WM_DELETE_WINDOW", on_closing) win.update_idletasks() - self.log_gui.log(f"{wlp}单步调试面板已打开(独立窗口)", level="success") - def toggle_screen_debug_panel(self): _toggle_debug_panel(self, "screen_module") diff --git a/app/views/pq_debug_panel.py b/app/views/pq_debug_panel.py index 80461fb..91181de 100644 --- a/app/views/pq_debug_panel.py +++ b/app/views/pq_debug_panel.py @@ -809,7 +809,7 @@ class PQDebugPanel: self._enable_test_button(test_type, test_item) except Exception as e: - self.app.log_gui.log(f"[Error] 单步测试失败: {str(e)}", level="error") + self.app.log_gui.log(f"单步测试失败: {str(e)}", level="error") import traceback self.app.log_gui.log(traceback.format_exc(), level="error") @@ -1146,7 +1146,7 @@ class PQDebugPanel: # 正确的访问方式:通过 test_items if "accuracy" not in self.app.results.test_items: - self.app.log_gui.log("[Error] 未找到 accuracy 测试项", level="error") + self.app.log_gui.log("未找到 accuracy 测试项", level="error") return 0.0 test_item = self.app.results.test_items["accuracy"] @@ -1155,7 +1155,7 @@ class PQDebugPanel: self.app.log_gui.log(f" accuracy_result = {accuracy_result is not None}", level="info") if not accuracy_result: - self.app.log_gui.log("[Error] accuracy_result 为空", level="error") + self.app.log_gui.log("accuracy_result 为空", level="error") return 0.0 # 获取色块名称列表和 ΔE 值列表 @@ -1179,11 +1179,11 @@ class PQDebugPanel: , level="success") return delta_e except ValueError: - self.app.log_gui.log(f"[Error] 未找到色块 '{color_name}'", level="error") + self.app.log_gui.log(f"未找到色块 '{color_name}'", level="error") self.app.log_gui.log(f" 可用色块: {color_patches}", level="info") return 0.0 except IndexError: - self.app.log_gui.log(f"[Error] 索引超出范围: {index}/{len(delta_e_values)}", level="error") + self.app.log_gui.log(f"索引超出范围: {index}/{len(delta_e_values)}", level="error") return 0.0 except Exception as e: diff --git a/pqAutomationApp.py b/pqAutomationApp.py index 338828c..f6aaeb0 100644 --- a/pqAutomationApp.py +++ b/pqAutomationApp.py @@ -11,7 +11,7 @@ import matplotlib.pyplot as plt from app_version import APP_NAME, APP_VERSION, get_app_title from drivers.UCD323_Function import UCDController from app.pq.pq_config import PQConfig -from app.pq.pq_result import PQResult +from app.pq.pq_result import PQResult, PQResultStore from app.views.pq_debug_panel import PQDebugPanel from app.export import ( save_result_images as _save_result_images_impl, @@ -113,6 +113,7 @@ class PQAutomationApp: self.root.title(get_app_title()) self.root.geometry("900x650") self.root.minsize(900, 650) + self.root.state("zoomed") self.root.protocol("WM_DELETE_WINDOW", self.on_closing) self.app_name = APP_NAME self.app_version = APP_VERSION @@ -137,7 +138,8 @@ class PQAutomationApp: # 创建配置对象 self.config = PQConfig() - self.results = None + # 结果管理器:按 test_type 保留每次测试结果,始终存在,避免未初始化错误 + self.results = PQResultStore() # 加载上次保存的设置 self.config_file = self.get_config_path() @@ -278,10 +280,6 @@ class PQAutomationApp: on_test_type_change = _main.on_test_type_change create_cct_params_frame = _ccp.create_cct_params_frame - _get_cct_var_dict = _ccp._get_cct_var_dict - _parse_cct_float = _ccp._parse_cct_float - _save_cct_params_for = _ccp._save_cct_params_for - _handle_cct_focus_out = _ccp._handle_cct_focus_out on_sdr_cct_param_focus_out = _ccp.on_sdr_cct_param_focus_out save_sdr_cct_params = _ccp.save_sdr_cct_params on_hdr_cct_param_focus_out = _ccp.on_hdr_cct_param_focus_out @@ -309,11 +307,7 @@ class PQAutomationApp: show_custom_result_context_menu = _ctp.show_custom_result_context_menu set_custom_result_table_locked = _ctp.set_custom_result_table_locked start_custom_row_single_step = _ctp.start_custom_row_single_step - _clear_custom_result_row = _ctp._clear_custom_result_row - _run_custom_row_single_step = _ctp._run_custom_row_single_step - _update_custom_result_row = _ctp._update_custom_result_row copy_custom_result_table = _ctp.copy_custom_result_table - fill_custom_result_test_data = _ctp.fill_custom_result_test_data clear_custom_template_results = _ctp.clear_custom_template_results auto_expand_custom_result_view = _ctp.auto_expand_custom_result_view append_custom_template_result = _ctp.append_custom_template_result @@ -405,13 +399,13 @@ class PQAutomationApp: self.debug_panel.disable_all_debug() self.log_gui.log("单步调试已禁用", level="success") except Exception as e: - self.log_gui.log(f"[Error] 禁用单步调试失败: {str(e)}", level="error") + self.log_gui.log(f"禁用单步调试失败: {str(e)}", level="error") if hasattr(self, "debug_container"): try: self.debug_container.pack_forget() self.log_gui.log("单步调试面板已隐藏", level="success") except Exception as e: - self.log_gui.log(f"[Error] 隐藏调试面板失败: {str(e)}", level="error") + self.log_gui.log(f"隐藏调试面板失败: {str(e)}", level="error") def _set_config_panel_btn_state(self, state): """统一设置配置面板按钮状态(disabled/normal)。""" @@ -434,7 +428,7 @@ class PQAutomationApp: """切换信号格式 Tab 到目标测试类型。""" if not hasattr(self, "signal_tabs"): if hasattr(self, "log_gui"): - self.log_gui.log("[Error] signal_tabs 尚未创建", level="error") + self.log_gui.log("signal_tabs 尚未创建", level="error") return try: @@ -484,24 +478,14 @@ class PQAutomationApp: if gamma_tab_id in current_tabs: gamma_index = current_tabs.index(gamma_tab_id) self.chart_notebook.forget(gamma_index) - if hasattr(self, "log_gui"): - self.log_gui.log("已隐藏 Gamma 曲线 Tab", level="success") - if eotf_tab_id not in current_tabs: self.chart_notebook.insert(1, self.eotf_chart_frame, text="EOTF 曲线") - if hasattr(self, "log_gui"): - self.log_gui.log("已显示 EOTF 曲线 Tab", level="success") else: if eotf_tab_id in current_tabs: eotf_index = current_tabs.index(eotf_tab_id) self.chart_notebook.forget(eotf_index) - if hasattr(self, "log_gui"): - self.log_gui.log("已隐藏 EOTF 曲线 Tab", level="success") - if gamma_tab_id not in current_tabs: self.chart_notebook.insert(1, self.gamma_chart_frame, text="Gamma 曲线") - if hasattr(self, "log_gui"): - self.log_gui.log("已显示 Gamma 曲线 Tab", level="success") custom_tab_id = str(self.custom_template_tab_frame) current_tabs = list(self.chart_notebook.tabs()) @@ -509,13 +493,9 @@ class PQAutomationApp: if test_type == "sdr_movie": if custom_tab_id not in current_tabs: self.chart_notebook.add(self.custom_template_tab_frame, text="客户模板结果显示") - if hasattr(self, "log_gui"): - self.log_gui.log("已显示客户模板结果 Tab", level="success") else: if custom_tab_id in current_tabs: self.chart_notebook.forget(self.custom_template_tab_frame) - if hasattr(self, "log_gui"): - self.log_gui.log("已隐藏客户模板结果 Tab", level="success") self.chart_notebook.update_idletasks() except Exception as e: @@ -655,7 +635,7 @@ class PQAutomationApp: time.sleep(0.1) self.root.update() if self.test_thread.is_alive(): - self.log_gui.log("[Error] 测试线程未能正常结束,将在后台继续等待", level="error") + self.log_gui.log("测试线程未能正常结束,将在后台继续等待", level="error") else: self.log_gui.log("测试线程已结束", level="success") @@ -663,8 +643,8 @@ class PQAutomationApp: """清空测试结果对象与中间数据缓存。""" try: self.log_gui.log("清理测试数据...", level="info") - if hasattr(self, "results"): - self.results = None + if hasattr(self, "results") and self.results is not None: + self.results.clear() self.log_gui.log(" 测试结果对象已清空", level="success") for attr in [ "gamut_results", @@ -677,7 +657,7 @@ class PQAutomationApp: setattr(self, attr, None) self.log_gui.log(" 所有中间数据已清空", level="success") except Exception as e: - self.log_gui.log(f"[Error] 清理数据时出错: {str(e)}", level="error") + self.log_gui.log(f"清理数据时出错: {str(e)}", level="error") def _clear_charts_and_tables(self): """清空图表与客户模板结果表格,并跳转到色域图 Tab。""" @@ -685,18 +665,18 @@ class PQAutomationApp: self.clear_chart() self.log_gui.log("图表已清空", level="success") except Exception as e: - self.log_gui.log(f"[Error] 清空图表时出错: {str(e)}", level="error") + self.log_gui.log(f"清空图表时出错: {str(e)}", level="error") try: self.clear_custom_template_results() self.log_gui.log("客户模板结果表格已清空", level="success") except Exception as e: - self.log_gui.log(f"[Error] 清空客户模板结果表格失败: {str(e)}", level="error") + self.log_gui.log(f"清空客户模板结果表格失败: {str(e)}", level="error") try: if hasattr(self, "chart_notebook"): self.chart_notebook.select(self.gamut_chart_frame) self.root.update_idletasks() except Exception as e: - self.log_gui.log(f"[Error] 跳转到色域图失败: {str(e)}", level="error") + self.log_gui.log(f"跳转到色域图失败: {str(e)}", level="error") def _restore_ui_after_stop(self): """恢复主按钮与状态栏到非测试态。""" @@ -785,7 +765,7 @@ class PQAutomationApp: messagebox.showinfo("成功", f"测试结果已保存到目录:\n{result_dir}") except Exception as e: - self.log_gui.log(f"[Error] 保存测试结果失败: {str(e)}", level="error") + self.log_gui.log(f"保存测试结果失败: {str(e)}", level="error") import traceback self.log_gui.log(traceback.format_exc(), level="error") @@ -862,7 +842,7 @@ class PQAutomationApp: self.save_pq_config() except Exception as e: - self.log_gui.log(f"[Error] 更新配置失败: {str(e)}", level="error") + self.log_gui.log(f"更新配置失败: {str(e)}", level="error") def update_config_and_tabs(self): """更新配置并同步Tab状态""" diff --git a/settings/pq_config.json b/settings/pq_config.json index d7b733a..ce2ce57 100644 --- a/settings/pq_config.json +++ b/settings/pq_config.json @@ -52,17 +52,11 @@ "timing": "DMT 1920x 1080 @ 60Hz", "color_format": "RGB", "bpc": 8, - "colorimetry": "sRGB", - "cct_params": { - "x_ideal": 0.3127, - "x_tolerance": 0.003, - "y_ideal": 0.329, - "y_tolerance": 0.003 - } + "colorimetry": "sRGB" } }, "device_config": { - "ca_com": "COM3", + "ca_com": "COM1", "ucd_list": "0: UCD-323 [2128C209]", "ca_channel": "0" },