重构继续优化主文件中函数

This commit is contained in:
xinzhu.yin
2026-04-21 11:50:57 +08:00
parent a5595b7e60
commit 6b8bfe06b9
4 changed files with 423 additions and 584 deletions

View File

@@ -730,26 +730,20 @@ def toggle_cct_params_frame(self):
# 屏模组:只有色度参数 # 屏模组:只有色度参数
if "cct" in selected_items: if "cct" in selected_items:
self.cct_params_frame.pack(fill=tk.X, padx=5, pady=5) self.cct_params_frame.pack(fill=tk.X, padx=5, pady=5)
if hasattr(self, "log_gui"):
self.log_gui.log("✓ 显示屏模组色度参数设置")
elif current_test_type == "sdr_movie": elif current_test_type == "sdr_movie":
# SDR只有色度参数色准不需要参数设置框 # SDR只有色度参数色准不需要参数设置框
if "cct" in selected_items: if "cct" in selected_items:
self.sdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5) self.sdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5)
if hasattr(self, "log_gui"):
self.log_gui.log("✓ 显示 SDR 色度参数设置")
elif current_test_type == "hdr_movie": elif current_test_type == "hdr_movie":
# HDR只有色度参数色准不需要参数设置框 # HDR只有色度参数色准不需要参数设置框
if "cct" in selected_items: if "cct" in selected_items:
if hasattr(self, "hdr_cct_params_frame"): if hasattr(self, "hdr_cct_params_frame"):
self.hdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5) self.hdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5)
if hasattr(self, "log_gui"):
self.log_gui.log("✓ 显示 HDR 色度参数设置")
else: else:
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("⚠️ HDR 色度参数框尚未创建") self.log_gui.log("[ERROR] HDR 色度参数框尚未创建")
# ---- gamut 参考标准改变回调(统一实现) ---- # ---- gamut 参考标准改变回调(统一实现) ----

View File

@@ -497,8 +497,6 @@ def create_operation_frame(self):
self.update_custom_button_visibility() self.update_custom_button_visibility()
def on_screen_module_timing_changed(self, event=None): def on_screen_module_timing_changed(self, event=None):
"""屏模组信号格式改变时的回调""" """屏模组信号格式改变时的回调"""
try: try:
@@ -535,3 +533,61 @@ def on_screen_module_timing_changed(self, event=None):
except Exception as e: except Exception as e:
self.log_gui.log(f"❌ 屏模组信号格式更改失败: {str(e)}") self.log_gui.log(f"❌ 屏模组信号格式更改失败: {str(e)}")
def update_test_items(self):
"""根据当前测试类型更新测试项目复选框"""
# 先隐藏所有测试项目框架
for config in self.test_items.values():
config["frame"].pack_forget()
current_test_type = self.config.current_test_type
self.test_vars = {}
if current_test_type in self.test_items:
config = self.test_items[current_test_type]
frame = config["frame"]
frame.pack(fill=tk.X, padx=5, pady=5)
# 添加测试类型标签
type_label = ttk.Label(
frame,
text=self.get_test_type_name(current_test_type),
style="primary.TLabel",
)
type_label.grid(row=0, column=0, columnspan=2, sticky=tk.W, padx=5, pady=3)
# 从配置中读取保存的选择状态
saved_test_items = self.config.current_test_types[current_test_type].get(
"test_items", []
)
# 添加复选框
for i, (text, var_name) in enumerate(config["items"]):
is_checked = var_name in saved_test_items
var = tk.BooleanVar(value=is_checked)
self.test_vars[f"{current_test_type}_{var_name}"] = var
ttk.Checkbutton(
frame,
text=text,
variable=var,
bootstyle="round-toggle",
command=self.update_config_and_tabs,
).grid(row=i // 2 + 1, column=i % 2, sticky=tk.W, padx=10, pady=5)
if hasattr(self, "chart_notebook"):
self.update_chart_tabs_state()
if hasattr(self, "cct_params_frame"):
self.toggle_cct_params_frame()
def on_test_type_change(self):
"""根据测试类型更新内容区域"""
# 更新配置信息显示
if hasattr(self, "config") and hasattr(self.config, "get_current_config"):
self.update_config_info_display()
# SDR 选中时显示客户模版按钮
self.update_custom_button_visibility()

View File

@@ -6,9 +6,7 @@ import threading
import time import time
import os import os
import datetime import datetime
import re
import traceback import traceback
import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from app_version import APP_NAME, APP_VERSION, get_app_title from app_version import APP_NAME, APP_VERSION, get_app_title
from drivers.UCD323_Function import UCDController from drivers.UCD323_Function import UCDController
@@ -24,6 +22,7 @@ from app.views.panels import custom_template_panel as _ctp
from app.views.panels import side_panels as _sp from app.views.panels import side_panels as _sp
from app.views.panels import cct_panel as _ccp from app.views.panels import cct_panel as _ccp
from app.views.panels import main_layout as _main from app.views.panels import main_layout as _main
from app.views import panel_manager as PM
# Step 0/1 重构:资源工具和纯算法已迁移到 app/ 包,这里重新导入以保持 # Step 0/1 重构:资源工具和纯算法已迁移到 app/ 包,这里重新导入以保持
# 对原函数名/方法名的向后兼容(老代码内部仍用 self.calculate_* 调用)。 # 对原函数名/方法名的向后兼容(老代码内部仍用 self.calculate_* 调用)。
@@ -107,7 +106,6 @@ from app.runner.test_runner import (
plt.rcParams["font.family"] = ["sans-serif"] plt.rcParams["font.family"] = ["sans-serif"]
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"] plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
class PQAutomationApp: class PQAutomationApp:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
@@ -133,9 +131,7 @@ class PQAutomationApp:
# 创建主框架 # 创建主框架
self.main_frame = ttk.Frame(root) self.main_frame = ttk.Frame(root)
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
backgroud_style_set() backgroud_style_set()
# 创建配置对象 # 创建配置对象
@@ -242,13 +238,9 @@ class PQAutomationApp:
pass pass
def initialize_default_test_type(self): def initialize_default_test_type(self):
"""初始化默认测试类型(在所有控件创建完成后调用)"""
try: try:
# 强制切换到屏模组 # 初始设置为屏模组
self.change_test_type("screen_module") self.change_test_type("screen_module")
if hasattr(self, "log_gui"):
self.log_gui.log("✓ 默认测试类型已设置为屏模组")
except Exception as e: except Exception as e:
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log(f"初始化默认测试类型失败: {str(e)}") self.log_gui.log(f"初始化默认测试类型失败: {str(e)}")
@@ -257,6 +249,10 @@ class PQAutomationApp:
load_pq_config = _cfg_load_pq_config load_pq_config = _cfg_load_pq_config
save_pq_config = _cfg_save_pq_config save_pq_config = _cfg_save_pq_config
register_panel = PM.register_panel
show_panel = PM.show_panel
hide_all_panels = PM.hide_all_panels
init_gamut_chart = _cf_init_gamut_chart init_gamut_chart = _cf_init_gamut_chart
init_gamma_chart = _cf_init_gamma_chart init_gamma_chart = _cf_init_gamma_chart
init_eotf_chart = _cf_init_eotf_chart init_eotf_chart = _cf_init_eotf_chart
@@ -275,6 +271,8 @@ class PQAutomationApp:
create_test_type_frame = _main.create_test_type_frame create_test_type_frame = _main.create_test_type_frame
update_config_info_display = _main.update_config_info_display update_config_info_display = _main.update_config_info_display
on_screen_module_timing_changed = _main.on_screen_module_timing_changed on_screen_module_timing_changed = _main.on_screen_module_timing_changed
update_test_items = _main.update_test_items
on_test_type_change = _main.on_test_type_change
create_cct_params_frame = _ccp.create_cct_params_frame create_cct_params_frame = _ccp.create_cct_params_frame
_get_cct_var_dict = _ccp._get_cct_var_dict _get_cct_var_dict = _ccp._get_cct_var_dict
@@ -340,185 +338,112 @@ class PQAutomationApp:
clear_ld_records = _ld_clear_ld_records clear_ld_records = _ld_clear_ld_records
save_local_dimming_results = _ld_save_local_dimming_results save_local_dimming_results = _ld_save_local_dimming_results
def _save_current_cct_params(self, swallow_errors=True):
def update_test_items(self): """按当前测试类型分发保存对应的 CCT 参数。"""
"""根据当前测试类型更新测试项目复选框"""
# 先隐藏所有测试项目框架
for config in self.test_items.values():
config["frame"].pack_forget()
current_test_type = self.config.current_test_type
self.test_vars = {}
if current_test_type in self.test_items:
config = self.test_items[current_test_type]
frame = config["frame"]
frame.pack(fill=tk.X, padx=5, pady=5)
# 添加测试类型标签
type_label = ttk.Label(
frame,
text=self.get_test_type_display_name(current_test_type),
style="primary.TLabel",
)
type_label.grid(row=0, column=0, columnspan=2, sticky=tk.W, padx=5, pady=3)
# 从配置中读取保存的选择状态
saved_test_items = self.config.current_test_types[current_test_type].get(
"test_items", []
)
# 添加复选框
for i, (text, var_name) in enumerate(config["items"]):
# 修改:根据配置决定是否勾选
# 如果配置中有该测试项,则勾选;否则不勾选
is_checked = var_name in saved_test_items
var = tk.BooleanVar(value=is_checked)
self.test_vars[f"{current_test_type}_{var_name}"] = var
ttk.Checkbutton(
frame,
text=text,
variable=var,
bootstyle="round-toggle",
command=self.update_config_and_tabs,
).grid(row=i // 2 + 1, column=i % 2, sticky=tk.W, padx=10, pady=5)
# 只有在 chart_notebook 已创建后才更新状态
if hasattr(self, "chart_notebook"):
self.update_chart_tabs_state()
# 更新色度参数框的显示状态
if hasattr(self, "cct_params_frame"):
self.toggle_cct_params_frame()
def get_test_type_display_name(self, test_type):
"""获取测试类型的显示名称"""
display_names = {
"screen_module": "屏模组性能测试",
"sdr_movie": "SDR Movie测试",
"hdr_movie": "HDR Movie测试",
}
return display_names.get(test_type, test_type)
def register_panel(self, panel_name, frame, button, visible_attr):
"""注册一个面板到管理系统"""
self.panels[panel_name] = {
"frame": frame,
"button": button,
"visible_attr": visible_attr,
}
def show_panel(self, panel_name):
"""显示指定面板,隐藏其他所有面板"""
if panel_name not in self.panels:
return
# 如果当前面板就是要显示的面板,则隐藏它
if self.current_panel == panel_name:
self.hide_all_panels()
return
# 隐藏所有面板
self.hide_all_panels()
# 显示指定面板
panel_info = self.panels[panel_name]
# 隐藏主内容区域
self.control_frame_top.pack_forget()
self.control_frame_middle.pack_forget()
self.control_frame_bottom.pack_forget()
# 显示目标面板
panel_info["frame"].pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=5, pady=5)
# 更新按钮样式
if panel_info["button"]:
panel_info["button"].configure(style="SidebarSelected.TButton")
# 更新状态
setattr(self, panel_info["visible_attr"], True)
self.current_panel = panel_name
def hide_all_panels(self):
"""隐藏所有面板,显示主内容区域"""
# 隐藏所有注册的面板
for panel_name, panel_info in self.panels.items():
panel_info["frame"].pack_forget()
if panel_info["button"]:
panel_info["button"].configure(style="Sidebar.TButton")
setattr(self, panel_info["visible_attr"], False)
# 显示主内容区域
self.control_frame_top.pack(
side=tk.TOP, fill=tk.BOTH, expand=True, padx=0, pady=5
)
self.control_frame_middle.pack(
side=tk.TOP, fill=tk.BOTH, expand=True, padx=0, pady=5
)
self.control_frame_bottom.pack(
side=tk.TOP, fill=tk.BOTH, expand=True, padx=0, pady=5
)
self.current_panel = None
def change_test_type(self, test_type):
"""切换测试类型"""
# 切换测试类型时,自动隐藏日志面板和 Local Dimming 面板
if self.current_panel in ("log", "local_dimming"):
self.hide_all_panels()
# 先保存当前测试类型的色度参数
if hasattr(self, "cct_x_ideal_var"):
try: try:
current_type = self.config.current_test_type current_type = self.config.current_test_type
if current_type == "screen_module": if current_type == "screen_module":
self.save_cct_params() self.save_cct_params()
elif current_type == "sdr_movie": elif current_type == "sdr_movie":
self.save_sdr_cct_params() self.save_sdr_cct_params()
elif current_type == "hdr_movie": elif current_type == "hdr_movie" and hasattr(self, "save_hdr_cct_params"):
if hasattr(self, "save_hdr_cct_params"):
self.save_hdr_cct_params() self.save_hdr_cct_params()
except Exception as e: except Exception as e:
if not swallow_errors:
raise
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log(f"保存参数失败: {str(e)}") self.log_gui.log(f"保存参数失败: {str(e)}")
# 更新测试类型 def _save_cct_params_before_test_type_switch(self):
"""切换测试类型前,按当前类型保存色度参数。"""
if not hasattr(self, "cct_x_ideal_var"):
return
self._save_current_cct_params()
def _set_gamut_combos_state(self, state, success_msg=None, error_prefix="色域参考标准状态切换失败"):
"""统一切换三个色域参考下拉框的状态。"""
try:
for attr in ("screen_gamut_combo", "sdr_gamut_combo", "hdr_gamut_combo"):
combo = getattr(self, attr, None)
if combo is not None:
combo.configure(state=state)
if success_msg and hasattr(self, "log_gui"):
self.log_gui.log(success_msg)
except Exception as e:
if hasattr(self, "log_gui"):
self.log_gui.log(f"{error_prefix}: {str(e)}")
def _hide_recalc_buttons(self, include_gamut=False):
"""隐藏重新计算按钮。include_gamut=True 时同时隐藏色域重算按钮。"""
attrs = ["recalc_cct_btn", "sdr_recalc_cct_btn", "hdr_recalc_cct_btn"]
if include_gamut:
attrs += ["recalc_gamut_btn", "sdr_recalc_gamut_btn", "hdr_recalc_gamut_btn"]
hidden = 0
for attr in attrs:
btn = getattr(self, attr, None)
if btn is None:
continue
try:
btn.grid_remove()
hidden += 1
except Exception:
pass
return hidden
def _disable_debug_panel(self):
"""禁用并隐藏单步调试面板(统一实现)。"""
if hasattr(self, "debug_panel"):
try:
self.debug_panel.disable_all_debug()
self.log_gui.log("✓ 单步调试已禁用")
except Exception as e:
self.log_gui.log(f"[Error] 禁用单步调试失败: {str(e)}")
if hasattr(self, "debug_container"):
try:
self.debug_container.pack_forget()
self.log_gui.log("✓ 单步调试面板已隐藏")
except Exception as e:
self.log_gui.log(f"[Error] 隐藏调试面板失败: {str(e)}")
def _set_config_panel_btn_state(self, state):
"""统一设置配置面板按钮状态disabled/normal"""
if not hasattr(self, "config_panel_frame"):
return
try:
self.config_panel_frame.btn.configure(state=state)
except Exception:
pass
def _apply_current_test_type(self, test_type):
"""更新 UI 变量与配置中的当前测试类型。"""
self.test_type_var.set(test_type) self.test_type_var.set(test_type)
if hasattr(self, "config") and hasattr(self.config, "set_current_test_type"): if hasattr(self, "config") and hasattr(self.config, "set_current_test_type"):
success = self.config.set_current_test_type(test_type) success = self.config.set_current_test_type(test_type)
if not success and hasattr(self, "log_gui"): if not success and hasattr(self, "log_gui"):
self.log_gui.log(f"切换测试类型失败: {test_type}") self.log_gui.log(f"切换测试类型失败: {test_type}")
# 更新测试项目和侧边栏 def _switch_signal_format_tabs(self, test_type):
self.update_test_items() """切换信号格式 Tab 到目标测试类型。"""
self.update_sidebar_selection() if not hasattr(self, "signal_tabs"):
self.on_test_type_change() if hasattr(self, "log_gui"):
self.log_gui.log("[Error] signal_tabs 尚未创建")
return
# ========== ✅ 1. 切换信号格式 Tab ==========
if hasattr(self, "signal_tabs"):
try: try:
# 定义测试类型与信号格式 Tab 的映射
tab_mapping = { tab_mapping = {
"screen_module": 0, # 屏模组测试 "screen_module": 0,
"sdr_movie": 1, # SDR测试 "sdr_movie": 1,
"hdr_movie": 2, # HDR "hdr_movie": 2,
} }
target_tab = tab_mapping.get(test_type, 0) target_tab = tab_mapping.get(test_type, 0)
# 先启用所有 Tab
for i in range(3): for i in range(3):
self.signal_tabs.tab(i, state="normal") self.signal_tabs.tab(i, state="normal")
# 切换到目标 Tab
self.signal_tabs.select(target_tab) self.signal_tabs.select(target_tab)
# 强制刷新显示
self.signal_tabs.update() self.signal_tabs.update()
self.root.update_idletasks() self.root.update_idletasks()
# 强制显示对应的 Frame
if target_tab == 0: if target_tab == 0:
self.screen_module_signal_frame.tkraise() self.screen_module_signal_frame.tkraise()
elif target_tab == 1: elif target_tab == 1:
@@ -526,78 +451,56 @@ class PQAutomationApp:
elif target_tab == 2: elif target_tab == 2:
self.hdr_signal_frame.tkraise() self.hdr_signal_frame.tkraise()
# 禁用其他 Tab
for i in range(3): for i in range(3):
if i != target_tab: if i != target_tab:
self.signal_tabs.tab(i, state="disabled") self.signal_tabs.tab(i, state="disabled")
# 日志记录
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
tab_names = ["屏模组测试", "SDR测试", "HDR"] tab_names = ["屏模组测试", "SDR测试", "HDR"]
self.log_gui.log(f"✓ 已切换到 {tab_names[target_tab]} 信号格式") self.log_gui.log(f"✓ 已切换到 {tab_names[target_tab]} 信号格式")
except Exception as e: except Exception as e:
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log(f"切换信号格式失败: {str(e)}") self.log_gui.log(f"切换信号格式失败: {str(e)}")
else:
if hasattr(self, "log_gui"):
self.log_gui.log("⚠️ signal_tabs 尚未创建")
# ========== 2. 动态切换 Gamma/EOTF Tab ========== def _switch_chart_tabs_by_test_type(self, test_type):
if hasattr(self, "chart_notebook"): """按测试类型切换 Gamma/EOTF 与客户模板结果 Tab。"""
if not hasattr(self, "chart_notebook"):
return
try: try:
current_tabs = list(self.chart_notebook.tabs()) current_tabs = list(self.chart_notebook.tabs())
# 获取当前 Tab 的索引
gamma_tab_id = str(self.gamma_chart_frame) gamma_tab_id = str(self.gamma_chart_frame)
eotf_tab_id = str(self.eotf_chart_frame) eotf_tab_id = str(self.eotf_chart_frame)
if test_type == "hdr_movie": if test_type == "hdr_movie":
# ========== HDR 测试:移除 Gamma添加 EOTF ==========
# 1. 如果 Gamma Tab 存在,移除它
if gamma_tab_id in current_tabs: if gamma_tab_id in current_tabs:
gamma_index = current_tabs.index(gamma_tab_id) gamma_index = current_tabs.index(gamma_tab_id)
self.chart_notebook.forget(gamma_index) self.chart_notebook.forget(gamma_index)
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("✓ 已隐藏 Gamma 曲线 Tab") self.log_gui.log("✓ 已隐藏 Gamma 曲线 Tab")
# 2. 如果 EOTF Tab 不存在,添加它(在色域图之后)
if eotf_tab_id not in current_tabs: if eotf_tab_id not in current_tabs:
self.chart_notebook.insert( self.chart_notebook.insert(1, self.eotf_chart_frame, text="EOTF 曲线")
1, self.eotf_chart_frame, text="EOTF 曲线"
)
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("✓ 已显示 EOTF 曲线 Tab") self.log_gui.log("✓ 已显示 EOTF 曲线 Tab")
else: else:
# ========== SDR/屏模组测试:移除 EOTF添加 Gamma ==========
# 1. 如果 EOTF Tab 存在,移除它
if eotf_tab_id in current_tabs: if eotf_tab_id in current_tabs:
eotf_index = current_tabs.index(eotf_tab_id) eotf_index = current_tabs.index(eotf_tab_id)
self.chart_notebook.forget(eotf_index) self.chart_notebook.forget(eotf_index)
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("✓ 已隐藏 EOTF 曲线 Tab") self.log_gui.log("✓ 已隐藏 EOTF 曲线 Tab")
# 2. 如果 Gamma Tab 不存在,添加它(在色域图之后)
if gamma_tab_id not in current_tabs: if gamma_tab_id not in current_tabs:
self.chart_notebook.insert( self.chart_notebook.insert(1, self.gamma_chart_frame, text="Gamma 曲线")
1, self.gamma_chart_frame, text="Gamma 曲线"
)
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("✓ 已显示 Gamma 曲线 Tab") self.log_gui.log("✓ 已显示 Gamma 曲线 Tab")
# ========== 3. 仅在 SDR 测试显示客户模板结果 Tab ==========
custom_tab_id = str(self.custom_template_tab_frame) custom_tab_id = str(self.custom_template_tab_frame)
current_tabs = list(self.chart_notebook.tabs()) current_tabs = list(self.chart_notebook.tabs())
if test_type == "sdr_movie": if test_type == "sdr_movie":
if custom_tab_id not in current_tabs: if custom_tab_id not in current_tabs:
self.chart_notebook.add( self.chart_notebook.add(self.custom_template_tab_frame, text="客户模板结果显示")
self.custom_template_tab_frame,
text="客户模板结果显示",
)
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("✓ 已显示客户模板结果 Tab") self.log_gui.log("✓ 已显示客户模板结果 Tab")
else: else:
@@ -606,211 +509,155 @@ class PQAutomationApp:
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log("✓ 已隐藏客户模板结果 Tab") self.log_gui.log("✓ 已隐藏客户模板结果 Tab")
# 刷新显示
self.chart_notebook.update_idletasks() self.chart_notebook.update_idletasks()
except Exception as e: except Exception as e:
if hasattr(self, "log_gui"): if hasattr(self, "log_gui"):
self.log_gui.log(f"切换 Gamma/EOTF Tab 失败: {str(e)}") self.log_gui.log(f"切换 Gamma/EOTF Tab 失败: {str(e)}")
def on_test_type_change(self): def change_test_type(self, test_type):
"""根据测试类型更新内容区域""" """切换测试类型"""
test_type = self.test_type_var.get() # 切换测试类型时,自动隐藏日志面板和 Local Dimming 面板
if self.current_panel in ("log", "local_dimming"):
self.hide_all_panels()
self._save_cct_params_before_test_type_switch()
self._apply_current_test_type(test_type)
# 获取当前测试类型的配置 # 更新测试项目和侧边栏
if hasattr(self, "config") and hasattr(self.config, "get_current_config"): self.update_test_items()
current_config = self.config.get_current_config() self.update_sidebar_selection()
self.on_test_type_change()
self._switch_signal_format_tabs(test_type)
self._switch_chart_tabs_by_test_type(test_type)
# 更新配置信息显示 def _check_start_preconditions(self):
self.update_config_info_display() """检查开始测试前置条件:设备连接 & 未在测试中。"""
# SDR 选中时显示客户模版按钮
self.update_custom_button_visibility()
def start_test(self):
"""开始测试"""
# 检查设备连接状态
if self.ca is None or self.ucd is None: if self.ca is None or self.ucd is None:
messagebox.showerror("错误", "请先连接CA410和信号发生器") messagebox.showerror("错误", "请先连接CA410和信号发生器")
return return False
# 检查是否已经在测试中
if self.testing: if self.testing:
messagebox.showinfo("提示", "测试已在进行中") messagebox.showinfo("提示", "测试已在进行中")
return False
return True
def _collapse_config_panel_for_test(self):
"""收起配置项并禁用其按钮。"""
if not hasattr(self, "config_panel_frame"):
return return
# ✅ 禁用并隐藏单步调试
if hasattr(self, "debug_panel"):
self.debug_panel.disable_all_debug()
self.log_gui.log("✓ 单步调试已禁用")
if hasattr(self, "debug_container"):
self.debug_container.pack_forget()
self.log_gui.log("✓ 单步调试面板已隐藏")
# 获取测试类型和测试项目
test_type = self.test_type_var.get()
test_items = self.get_selected_test_items()
if not test_items:
messagebox.showinfo("提示", "请至少选择一个测试项目")
return
# 自动收起配置项
if hasattr(self, "config_panel_frame"):
try: try:
if self.config_panel_frame.winfo_viewable(): if self.config_panel_frame.winfo_viewable():
self.config_panel_frame.btn.invoke() self.config_panel_frame.btn.invoke()
self.root.update_idletasks() self.root.update_idletasks()
time.sleep(0.2) time.sleep(0.2)
except: except Exception:
pass pass
self._set_config_panel_btn_state("disabled")
# 禁用配置项按钮 def _set_ui_testing_state(self):
try: """切换主 UI 到测试中状态(按钮禁用、状态栏、清空日志/图表)。"""
self.config_panel_frame.btn.configure(state="disabled")
except:
pass
# ✅ 新增:禁用色域参考标准下拉框
try:
if hasattr(self, "screen_gamut_combo"):
self.screen_gamut_combo.configure(state="disabled")
if hasattr(self, "sdr_gamut_combo"):
self.sdr_gamut_combo.configure(state="disabled")
if hasattr(self, "hdr_gamut_combo"):
self.hdr_gamut_combo.configure(state="disabled")
except Exception as e:
self.log_gui.log(f"禁用色域参考标准失败: {str(e)}")
# 隐藏所有重新计算按钮
if hasattr(self, "recalc_cct_btn"):
try:
self.recalc_cct_btn.grid_remove()
except:
pass
if hasattr(self, "sdr_recalc_cct_btn"):
try:
self.sdr_recalc_cct_btn.grid_remove()
except:
pass
if hasattr(self, "hdr_recalc_cct_btn"):
try:
self.hdr_recalc_cct_btn.grid_remove()
except:
pass
# 更新UI状态
self.testing = True self.testing = True
self.start_btn.config(state=tk.DISABLED) self.start_btn.config(state=tk.DISABLED)
self.stop_btn.config(state=tk.NORMAL) self.stop_btn.config(state=tk.NORMAL)
self.save_btn.config(state=tk.DISABLED) self.save_btn.config(state=tk.DISABLED)
self.clear_config_btn.config(state=tk.DISABLED) self.clear_config_btn.config(state=tk.DISABLED)
self.status_var.set("测试进行中...") self.status_var.set("测试进行中...")
# 清空日志和图表
self.log_gui.clear_log() self.log_gui.clear_log()
self.clear_chart() self.clear_chart()
# 根据测试类型显示不同提示 def _prepare_ui_for_test_start(self):
if test_type == "screen_module": """为开始测试准备 UI禁用调试、收起配置、禁用色域、隐藏重算按钮、切换状态"""
# 屏模组测试:提示 byPass All PQ self._disable_debug_panel()
message = f"开始屏模组性能测试,请 byPass All PQ" self._collapse_config_panel_for_test()
self._set_gamut_combos_state("disabled", error_prefix="禁用色域参考标准失败")
self._hide_recalc_buttons(include_gamut=False)
self._set_ui_testing_state()
elif test_type == "sdr_movie": def _rollback_test_start(self):
# SDR测试提示设置正确图像模式 """用户取消测试时恢复 UI 状态。"""
message = f"开始 SDR Movie 测试,请设置正确的图像模式"
elif test_type == "hdr_movie":
# HDR测试提示设置正确图像模式
message = f"开始 HDR Movie 测试,请设置正确的图像模式"
else:
message = f"开始{self.get_test_type_name(test_type)}测试"
confirm = messagebox.askyesno("确认测试", message)
if not confirm:
self.testing = False self.testing = False
self.start_btn.config(state=tk.NORMAL) self.start_btn.config(state=tk.NORMAL)
self.stop_btn.config(state=tk.DISABLED) self.stop_btn.config(state=tk.DISABLED)
self.clear_config_btn.config(state=tk.NORMAL) self.clear_config_btn.config(state=tk.NORMAL)
self.status_var.set("测试已取消") self.status_var.set("测试已取消")
self._set_config_panel_btn_state("normal")
# 恢复配置项按钮 def _build_test_start_message(self, test_type):
if hasattr(self, "config_panel_frame"): """根据测试类型生成确认弹框提示文案。"""
try: if test_type == "screen_module":
self.config_panel_frame.btn.configure(state="normal") return "开始屏模组性能测试,请 byPass All PQ"
except: if test_type == "sdr_movie":
pass return "开始 SDR Movie 测试,请设置正确的图像模式"
return if test_type == "hdr_movie":
return "开始 HDR Movie 测试,请设置正确的图像模式"
return f"开始{self.get_test_type_name(test_type)}测试"
# 在新线程中执行测试 def _launch_test_thread(self, test_type, test_items):
"""在新线程中执行测试。"""
self.test_thread = threading.Thread( self.test_thread = threading.Thread(
target=self.run_test, args=(test_type, test_items) target=self.run_test, args=(test_type, test_items)
) )
self.test_thread.daemon = True self.test_thread.daemon = True
self.test_thread.start() self.test_thread.start()
def stop_test(self): def start_test(self):
"""停止测试 - 放弃本次所有数据(完全集成版)""" """开始测试"""
if not self.testing: if not self._check_start_preconditions():
return return
# ========== 1. 添加确认对话框 ========== test_type = self.test_type_var.get()
confirm = messagebox.askyesno( test_items = self.get_selected_test_items()
if not test_items:
messagebox.showinfo("提示", "请至少选择一个测试项目")
return
self._prepare_ui_for_test_start()
message = self._build_test_start_message(test_type)
if not messagebox.askyesno("确认测试", message):
self._rollback_test_start()
return
self._launch_test_thread(test_type, test_items)
def _confirm_stop_test(self):
"""弹出确认停止测试对话框。"""
return messagebox.askyesno(
"确认停止测试", "确认停止测试",
"测试正在进行中,确定要停止吗?\n\n⚠️ 停止后将放弃本次测试的所有数据,无法保存。", "测试正在进行中,确定要停止吗?\n\n 停止后将放弃本次测试的所有数据,无法保存。",
icon="warning", icon="warning",
) )
if not confirm: def _signal_stop_and_update_ui(self):
self.log_gui.log("用户取消停止操作") """设置停止标志并立即更新 UI 以反馈给用户。"""
return self.testing = False
# ========== 2. 立即设置停止标志 ==========
self.testing = False # ← 关键:先设置标志,让测试线程停止
self.log_gui.log("=" * 50) self.log_gui.log("=" * 50)
self.log_gui.log("⚠️ 正在停止测试...") self.log_gui.log("正在停止测试...")
self.log_gui.log("=" * 50) self.log_gui.log("=" * 50)
# ========== 3. 立即更新UI状态让用户感知到停止==========
self.stop_btn.config(state=tk.DISABLED) self.stop_btn.config(state=tk.DISABLED)
self.status_var.set("正在停止测试,请稍候...") self.status_var.set("正在停止测试,请稍候...")
self.root.update() # 立即刷新界面 self.root.update()
# ========== 4. 等待测试线程结束 ========== def _wait_for_test_thread(self, timeout_seconds=5):
if self.test_thread and self.test_thread.is_alive(): """等待测试线程结束,最多 timeout_seconds 秒,同时保持 UI 响应。"""
if not (self.test_thread and self.test_thread.is_alive()):
return
self.log_gui.log("等待测试线程结束...") self.log_gui.log("等待测试线程结束...")
for _ in range(int(timeout_seconds * 10)):
# 等待最多5秒
for i in range(50): # 50 * 0.1秒 = 5秒
if not self.test_thread.is_alive(): if not self.test_thread.is_alive():
break break
time.sleep(0.1) time.sleep(0.1)
self.root.update() # 保持界面响应 self.root.update()
if self.test_thread.is_alive(): if self.test_thread.is_alive():
self.log_gui.log("⚠️ 测试线程未能正常结束,将在后台继续等待") self.log_gui.log("[Error] 测试线程未能正常结束,将在后台继续等待")
else: else:
self.log_gui.log("✓ 测试线程已结束") self.log_gui.log("✓ 测试线程已结束")
# ========== 5. 延迟1秒后执行清理使用内部函数========== def _clear_test_data(self):
def cleanup_and_finish(): """清空测试结果对象与中间数据缓存。"""
"""清理数据并完成停止操作"""
# ========== 5.1 清理测试数据 ==========
try: try:
self.log_gui.log("清理测试数据...") self.log_gui.log("清理测试数据...")
# 清空测试结果对象
if hasattr(self, "results"): if hasattr(self, "results"):
self.results = None self.results = None
self.log_gui.log(" ✓ 测试结果对象已清空") self.log_gui.log(" ✓ 测试结果对象已清空")
# 清空中间数据缓存
for attr in [ for attr in [
"gamut_results", "gamut_results",
"gamma_results", "gamma_results",
@@ -820,35 +667,31 @@ class PQAutomationApp:
]: ]:
if hasattr(self, attr): if hasattr(self, attr):
setattr(self, attr, None) setattr(self, attr, None)
self.log_gui.log(" ✓ 所有中间数据已清空") self.log_gui.log(" ✓ 所有中间数据已清空")
except Exception as e: except Exception as e:
self.log_gui.log(f"⚠️ 清理数据时出错: {str(e)}") self.log_gui.log(f"[Error] 清理数据时出错: {str(e)}")
# ========== 5.2 清空图表显示 ========== def _clear_charts_and_tables(self):
"""清空图表与客户模板结果表格,并跳转到色域图 Tab。"""
try: try:
self.clear_chart() self.clear_chart()
self.log_gui.log("✓ 图表已清空") self.log_gui.log("✓ 图表已清空")
except Exception as e: except Exception as e:
self.log_gui.log(f"⚠️ 清空图表时出错: {str(e)}") self.log_gui.log(f"[Error] 清空图表时出错: {str(e)}")
try: try:
self.clear_custom_template_results() self.clear_custom_template_results()
self.log_gui.log("✓ 客户模板结果表格已清空") self.log_gui.log("✓ 客户模板结果表格已清空")
except Exception as e: except Exception as e:
self.log_gui.log(f"⚠️ 清空客户模板结果表格失败: {str(e)}") self.log_gui.log(f"[Error] 清空客户模板结果表格失败: {str(e)}")
# ========== 5.2.5 跳转到色域图Tab第一个Tab==========
try: try:
if hasattr(self, "chart_notebook"): if hasattr(self, "chart_notebook"):
self.chart_notebook.select(self.gamut_chart_frame) self.chart_notebook.select(self.gamut_chart_frame)
self.root.update_idletasks() # ← 刷新界面 self.root.update_idletasks()
self.log_gui.log("✓ 已跳转到色域图界面")
except Exception as e: except Exception as e:
self.log_gui.log(f"⚠️ 跳转到色域图失败: {str(e)}") self.log_gui.log(f"[Error] 跳转到色域图失败: {str(e)}")
# ========== 5.3 更新UI状态 ========== def _restore_ui_after_stop(self):
"""恢复主按钮与状态栏到非测试态。"""
self.set_custom_result_table_locked(False) self.set_custom_result_table_locked(False)
self.start_btn.config(state=tk.NORMAL) self.start_btn.config(state=tk.NORMAL)
self.stop_btn.config(state=tk.DISABLED) self.stop_btn.config(state=tk.DISABLED)
@@ -857,81 +700,40 @@ class PQAutomationApp:
if hasattr(self, "custom_btn"): if hasattr(self, "custom_btn"):
self.custom_btn.config(state=tk.NORMAL) self.custom_btn.config(state=tk.NORMAL)
self.status_var.set("测试已停止 - 数据已清空") self.status_var.set("测试已停止 - 数据已清空")
self.log_gui.log("✓ UI状态已更新")
# ========== 5.4 恢复配置项按钮 ==========
if hasattr(self, "config_panel_frame"): if hasattr(self, "config_panel_frame"):
try: self._set_config_panel_btn_state("normal")
self.config_panel_frame.btn.configure(state="normal")
self.log_gui.log("✓ 配置项已恢复")
except:
pass
# ========== 5.4.5 禁用色域参考标准下拉框 ========== def _finalize_stop_test(self):
try: """延迟执行的清理流程总入口(由 root.after 调用)。"""
if hasattr(self, "screen_gamut_combo"): self._clear_test_data()
self.screen_gamut_combo.configure(state="disabled") self._clear_charts_and_tables()
if hasattr(self, "sdr_gamut_combo"): self._restore_ui_after_stop()
self.sdr_gamut_combo.configure(state="disabled") self._set_gamut_combos_state(
if hasattr(self, "hdr_gamut_combo"): "disabled",
self.hdr_gamut_combo.configure(state="disabled") success_msg="✓ 色域参考标准已禁用",
self.log_gui.log("色域参考标准已禁用") error_prefix="禁用色域参考标准失败",
except Exception as e: )
self.log_gui.log(f"禁用色域参考标准失败: {str(e)}") hidden = self._hide_recalc_buttons(include_gamut=True)
if hidden > 0:
# ========== 5.5 隐藏所有重新计算按钮 ========== self.log_gui.log(f"✓ 已隐藏 {hidden} 个重新计算按钮")
try: self._disable_debug_panel()
button_hidden_count = 0
for btn_attr in [
"recalc_cct_btn",
"sdr_recalc_cct_btn",
"hdr_recalc_cct_btn",
"recalc_gamut_btn", # ✅ 新增
"sdr_recalc_gamut_btn", # ✅ 新增
"hdr_recalc_gamut_btn", # ✅ 新增
]:
if hasattr(self, btn_attr):
try:
getattr(self, btn_attr).grid_remove()
button_hidden_count += 1
except:
pass
if button_hidden_count > 0:
self.log_gui.log(f"✓ 已隐藏 {button_hidden_count} 个重新计算按钮")
except Exception as e:
self.log_gui.log(f"⚠️ 隐藏按钮时出错: {str(e)}")
# ========== 5.6 禁用并隐藏单步调试 ==========
if hasattr(self, "debug_panel"):
try:
self.debug_panel.disable_all_debug()
self.log_gui.log("✓ 单步调试已禁用")
except Exception as e:
self.log_gui.log(f"⚠️ 禁用单步调试失败: {str(e)}")
# ✅ 隐藏调试面板
if hasattr(self, "debug_container"):
try:
self.debug_container.pack_forget()
self.log_gui.log("✓ 单步调试面板已隐藏")
except Exception as e:
self.log_gui.log(f"⚠️ 隐藏调试面板失败: {str(e)}")
# ========== 5.7 最终日志 ==========
self.log_gui.log("=" * 50) self.log_gui.log("=" * 50)
self.log_gui.log("✓ 测试已停止,所有数据已清空") self.log_gui.log("✓ 测试已停止,所有数据已清空")
self.log_gui.log("=" * 50) self.log_gui.log("=" * 50)
# ========== 5.8 显示提示信息 ==========
messagebox.showinfo( messagebox.showinfo(
"测试已停止", "测试已停止",
"测试已停止,本次测试数据已清空。\n\n可以重新开始新的测试。", "测试已停止,本次测试数据已清空。\n\n可以重新开始新的测试。",
) )
# ========== 延迟1秒后执行清理 ========== def stop_test(self):
self.root.after(1000, cleanup_and_finish) """停止测试 - 放弃本次所有数据(完全集成版)"""
if not self.testing:
return
if not self._confirm_stop_test():
return
self._signal_stop_and_update_ui()
self._wait_for_test_thread(timeout_seconds=5)
self.root.after(1000, self._finalize_stop_test)
# ==================== 保存测试结果 ==================== # ==================== 保存测试结果 ====================
def save_results(self): def save_results(self):
@@ -970,12 +772,12 @@ class PQAutomationApp:
# 3) 成功提示 # 3) 成功提示
log("=" * 50) log("=" * 50)
log(f"测试结果已保存到目录: {result_dir}") log(f"测试结果已保存到目录: {result_dir}")
log("=" * 50) log("=" * 50)
messagebox.showinfo("成功", f"测试结果已保存到目录:\n{result_dir}") messagebox.showinfo("成功", f"测试结果已保存到目录:\n{result_dir}")
except Exception as e: except Exception as e:
self.log_gui.log(f" 保存测试结果失败: {str(e)}") self.log_gui.log(f"[Error] 保存测试结果失败: {str(e)}")
import traceback import traceback
self.log_gui.log(traceback.format_exc()) self.log_gui.log(traceback.format_exc())
@@ -1052,7 +854,7 @@ class PQAutomationApp:
self.save_pq_config() self.save_pq_config()
except Exception as e: except Exception as e:
self.log_gui.log(f"更新配置失败: {str(e)}") self.log_gui.log(f"[Error] 更新配置失败: {str(e)}")
def update_config_and_tabs(self): def update_config_and_tabs(self):
"""更新配置并同步Tab状态""" """更新配置并同步Tab状态"""
@@ -1060,21 +862,8 @@ class PQAutomationApp:
self.update_chart_tabs_state() self.update_chart_tabs_state()
# 根据当前测试类型保存对应参数 # 根据当前测试类型保存对应参数
current_test_type = self.config.current_test_type if "cct" in self.get_selected_test_items():
selected_items = self.get_selected_test_items() self._save_current_cct_params()
if current_test_type == "screen_module":
if "cct" in selected_items:
self.save_cct_params()
elif current_test_type == "sdr_movie":
if "cct" in selected_items:
self.save_sdr_cct_params()
elif current_test_type == "hdr_movie":
if "cct" in selected_items:
if hasattr(self, "save_hdr_cct_params"):
self.save_hdr_cct_params()
# 控制参数框的显示 # 控制参数框的显示
self.toggle_cct_params_frame() self.toggle_cct_params_frame()

View File

@@ -1,5 +1,5 @@
{ {
"current_test_type": "screen_module", "current_test_type": "sdr_movie",
"test_types": { "test_types": {
"screen_module": { "screen_module": {
"name": "屏模组性能测试", "name": "屏模组性能测试",