优化日志显示
This commit is contained in:
@@ -40,7 +40,7 @@ def calculate_gamut_coverage(points1, points2):
|
|||||||
return intersection_area, coverage
|
return intersection_area, coverage
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 计算色域覆盖率失败: {e}")
|
print(f"[Error] 计算色域覆盖率失败: {e}")
|
||||||
return 0.0, 0.0
|
return 0.0, 0.0
|
||||||
|
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ def calculate_uv_gamut_coverage(uv_coords, reference="DCI-P3"):
|
|||||||
return coverage
|
return coverage
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 计算 u'v' 色域覆盖率失败: {str(e)}")
|
print(f"[Error] 计算 u'v' 色域覆盖率失败: {str(e)}")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@@ -451,7 +451,7 @@ def calculate_cct_from_results(results):
|
|||||||
"""
|
"""
|
||||||
从测量结果提取色度坐标(xy 坐标)
|
从测量结果提取色度坐标(xy 坐标)
|
||||||
|
|
||||||
⚠️ 注意:方法名保持不变(历史原因),实际功能是提取色度坐标
|
注意:方法名保持不变(历史原因),实际功能是提取色度坐标
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
results: [[x, y, lv, ...], ...] 测量结果列表
|
results: [[x, y, lv, ...], ...] 测量结果列表
|
||||||
@@ -486,7 +486,7 @@ def calculate_cct_from_results(results):
|
|||||||
lv_values.append(0.0)
|
lv_values.append(0.0)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"⚠️ 提取色度坐标失败: {str(e)}")
|
print(f"提取色度坐标失败: {str(e)}")
|
||||||
x_values.append(0.3127)
|
x_values.append(0.3127)
|
||||||
y_values.append(0.3290)
|
y_values.append(0.3290)
|
||||||
lv_values.append(0.0)
|
lv_values.append(0.0)
|
||||||
@@ -555,5 +555,5 @@ if __name__ == "__main__":
|
|||||||
print(f" 点{i+1}: Gamma={result[3]:.3f}")
|
print(f" 点{i+1}: Gamma={result[3]:.3f}")
|
||||||
|
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print("✅ 测试完成!")
|
print("测试完成!")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""配置文件 I/O(Step 4 重构)。
|
"""配置文件 I/O(Step 4 重构)。
|
||||||
|
|
||||||
从 pqAutomationApp.PQAutomationApp 中搬迁。每个函数第一行 `self = app`
|
从 pqAutomationApp.PQAutomationApp 中搬迁。每个函数第一行 `self = app`
|
||||||
以保留原有 `self.xxx` 属性访问不变。
|
以保留原有 `self.xxx` 属性访问不变。
|
||||||
@@ -33,19 +33,19 @@ def get_config_path(self):
|
|||||||
def load_pq_config(self):
|
def load_pq_config(self):
|
||||||
"""加载PQ配置(兼容打包后的程序)"""
|
"""加载PQ配置(兼容打包后的程序)"""
|
||||||
try:
|
try:
|
||||||
# ✅ 使用 self.config_file(已经是动态路径)
|
# 使用 self.config_file(已经是动态路径)
|
||||||
if os.path.exists(self.config_file):
|
if os.path.exists(self.config_file):
|
||||||
with open(self.config_file, "r", encoding="utf-8") as f:
|
with open(self.config_file, "r", encoding="utf-8") as f:
|
||||||
config_dict = json.load(f)
|
config_dict = json.load(f)
|
||||||
self.config.from_dict(config_dict)
|
self.config.from_dict(config_dict)
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log("✓ 配置文件加载成功")
|
self.log_gui.log("配置文件加载成功", level="success")
|
||||||
else:
|
else:
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log("⚠️ 配置文件不存在,使用默认配置")
|
self.log_gui.log("配置文件不存在,使用默认配置", level="error")
|
||||||
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)},使用默认配置", level="error")
|
||||||
|
|
||||||
|
|
||||||
def save_pq_config(self):
|
def save_pq_config(self):
|
||||||
@@ -58,7 +58,7 @@ def save_pq_config(self):
|
|||||||
self.config.save_to_file(self.config_file)
|
self.config.save_to_file(self.config_file)
|
||||||
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)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
def clear_config_file(self):
|
def clear_config_file(self):
|
||||||
@@ -71,14 +71,14 @@ def clear_config_file(self):
|
|||||||
if os.path.exists(config_file):
|
if os.path.exists(config_file):
|
||||||
os.remove(config_file)
|
os.remove(config_file)
|
||||||
self.config_cleared = True
|
self.config_cleared = True
|
||||||
messagebox.showinfo("提示", "✓ 清理成功")
|
messagebox.showinfo("提示", "清理成功")
|
||||||
self.log_gui.log("✓ 配置文件清理成功")
|
self.log_gui.log("配置文件清理成功", level="success")
|
||||||
else:
|
else:
|
||||||
messagebox.showinfo("提示", "配置文件不存在")
|
messagebox.showinfo("提示", "配置文件不存在")
|
||||||
self.log_gui.log("⚠️ 配置文件不存在")
|
self.log_gui.log("配置文件不存在", level="error")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messagebox.showerror("错误", "❌ 清理失败")
|
messagebox.showerror("错误", "[Error] 清理失败")
|
||||||
self.log_gui.log(f"❌ 配置文件清理失败: {str(e)}")
|
self.log_gui.log(f"[Error] 配置文件清理失败: {str(e)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class DataRangeConverter:
|
|||||||
# Full Range 不需要转换
|
# Full Range 不需要转换
|
||||||
if data_range == "Full":
|
if data_range == "Full":
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print("✓ 使用 Full Range (0-255),无需转换")
|
print("使用 Full Range (0-255),无需转换")
|
||||||
return pattern_params
|
return pattern_params
|
||||||
|
|
||||||
# Limited Range 需要转换
|
# Limited Range 需要转换
|
||||||
@@ -157,7 +157,7 @@ class DataRangeConverter:
|
|||||||
|
|
||||||
def _print_footer(self, total_count):
|
def _print_footer(self, total_count):
|
||||||
"""打印转换尾部信息"""
|
"""打印转换尾部信息"""
|
||||||
print(f"✓ 转换完成,共 {total_count} 个图案")
|
print(f"转换完成,共 {total_count} 个图案")
|
||||||
print("=" * 80)
|
print("=" * 80)
|
||||||
|
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""设备连接(UCD323 / CA410)相关逻辑(Step 4 重构)。
|
"""设备连接(UCD323 / CA410)相关逻辑(Step 4 重构)。
|
||||||
|
|
||||||
从 pqAutomationApp.PQAutomationApp 中搬迁。每个函数第一行 `self = app`
|
从 pqAutomationApp.PQAutomationApp 中搬迁。每个函数第一行 `self = app`
|
||||||
以保留原有 `self.xxx` 属性访问不变。
|
以保留原有 `self.xxx` 属性访问不变。
|
||||||
@@ -23,7 +23,7 @@ def get_available_com_ports(self):
|
|||||||
ports = serial.tools.list_ports.comports()
|
ports = serial.tools.list_ports.comports()
|
||||||
return [port.device for port in ports]
|
return [port.device for port in ports]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"获取COM端口列表出错: {e}")
|
self.log_gui.log(f"获取COM端口列表出错: {e}", level="error")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ def check_port_connection(self, is_ucd=True):
|
|||||||
if not self.ucd.open(self.ucd_list_var.get()):
|
if not self.ucd.open(self.ucd_list_var.get()):
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"设备 {self.ucd_list_var.get()} 异常,UCD323连接失败"
|
f"设备 {self.ucd_list_var.get()} 异常,UCD323连接失败"
|
||||||
)
|
, level="error")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
@@ -147,12 +147,12 @@ def check_port_connection(self, is_ucd=True):
|
|||||||
else:
|
else:
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"端口 {self.config.device_config["ca_com"]} 异常,色温仪连接失败"
|
f"端口 {self.config.device_config["ca_com"]} 异常,色温仪连接失败"
|
||||||
)
|
, level="error")
|
||||||
self.ca.close()
|
self.ca.close()
|
||||||
self.ca = None
|
self.ca = None
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"端口连接失败: {e}")
|
self.log_gui.log(f"端口连接失败: {e}", level="error")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ def disconnect_com_connections(self):
|
|||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
self.ucd.status = False
|
self.ucd.status = False
|
||||||
self.log_gui.log("UCD连接已断开")
|
self.log_gui.log("UCD连接已断开", level="info")
|
||||||
|
|
||||||
# 断开CA连接
|
# 断开CA连接
|
||||||
if self.ca is not None:
|
if self.ca is not None:
|
||||||
@@ -183,7 +183,7 @@ def disconnect_com_connections(self):
|
|||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
self.ca = None
|
self.ca = None
|
||||||
self.log_gui.log("CA连接已断开")
|
self.log_gui.log("CA连接已断开", level="info")
|
||||||
|
|
||||||
# 重新启用相关控件
|
# 重新启用相关控件
|
||||||
self.enable_com_widgets()
|
self.enable_com_widgets()
|
||||||
@@ -192,7 +192,7 @@ def disconnect_com_connections(self):
|
|||||||
self.status_var.set("串口连接已断开")
|
self.status_var.set("串口连接已断开")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"断开连接时发生错误: {str(e)}")
|
self.log_gui.log(f"断开连接时发生错误: {str(e)}", level="info")
|
||||||
messagebox.showerror("错误", f"断开连接失败: {str(e)}")
|
messagebox.showerror("错误", f"断开连接失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ def _section_gamut(ws, styles, row, results, log):
|
|||||||
_apply_data_row(ws, row, ["A", "B", "C", "D"], styles)
|
_apply_data_row(ws, row, ["A", "B", "C", "D"], styles)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
log(" ✓ 添加色域数据")
|
log(" 添加色域数据", level="info")
|
||||||
return row + 1
|
return row + 1
|
||||||
|
|
||||||
|
|
||||||
@@ -274,7 +274,7 @@ def _section_curve(ws, styles, row, results, log, curve_type):
|
|||||||
_apply_data_row(ws, row, ["A", "B", "C", "D", "E", "F"], styles)
|
_apply_data_row(ws, row, ["A", "B", "C", "D", "E", "F"], styles)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
log(f" ✓ 添加 {label_prefix} 数据")
|
log(f" 添加 {label_prefix} 数据", level="info")
|
||||||
return row + 1
|
return row + 1
|
||||||
|
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ def _section_cct(ws, styles, row, results, log):
|
|||||||
_apply_data_row(ws, row, ["A", "B", "C", "D"], styles)
|
_apply_data_row(ws, row, ["A", "B", "C", "D"], styles)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
log(" ✓ 添加色度一致性数据")
|
log(" 添加色度一致性数据", level="info")
|
||||||
return row + 1
|
return row + 1
|
||||||
|
|
||||||
|
|
||||||
@@ -354,7 +354,7 @@ def _section_contrast(ws, styles, row, results, log):
|
|||||||
ws[f"B{row}"].border = styles["thin_border"]
|
ws[f"B{row}"].border = styles["thin_border"]
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
log(" ✓ 添加对比度数据")
|
log(" 添加对比度数据", level="info")
|
||||||
return row + 1
|
return row + 1
|
||||||
|
|
||||||
|
|
||||||
@@ -440,7 +440,7 @@ def _section_accuracy(ws, styles, row, results, log):
|
|||||||
_apply_data_row(ws, row, ["A", "B", "C", "D", "E", "F", "G"], styles)
|
_apply_data_row(ws, row, ["A", "B", "C", "D", "E", "F", "G"], styles)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
log(" ✓ 添加色准数据(含 xy 坐标和亮度)")
|
log(" 添加色准数据(含 xy 坐标和亮度)")
|
||||||
return row + 1
|
return row + 1
|
||||||
|
|
||||||
|
|
||||||
@@ -493,12 +493,12 @@ def export_excel_report(result_dir, current_test_type, selected_items,
|
|||||||
excel_path = os.path.join(result_dir, "测试数据.xlsx")
|
excel_path = os.path.join(result_dir, "测试数据.xlsx")
|
||||||
wb.save(excel_path)
|
wb.save(excel_path)
|
||||||
|
|
||||||
log("✓ 已保存: 测试数据.xlsx")
|
log("已保存: 测试数据.xlsx", level="success")
|
||||||
log("=" * 60)
|
log("=" * 60, level="seperator")
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
log("⚠️ 未安装 openpyxl 库,跳过 Excel 导出")
|
log("未安装 openpyxl 库,跳过 Excel 导出", level="error")
|
||||||
log(" 安装方法: pip install openpyxl")
|
log(" 安装方法: pip install openpyxl")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f"⚠️ Excel 导出失败: {str(e)}")
|
log(f"Excel 导出失败: {str(e)}", level="error")
|
||||||
log(traceback.format_exc())
|
log(traceback.format_exc())
|
||||||
|
|||||||
@@ -35,4 +35,4 @@ def save_result_images(result_dir, current_test_type, selected_items,
|
|||||||
fig.savefig(path, dpi=300)
|
fig.savefig(path, dpi=300)
|
||||||
else:
|
else:
|
||||||
fig.savefig(path, dpi=300, bbox_inches="tight")
|
fig.savefig(path, dpi=300, bbox_inches="tight")
|
||||||
log(f"✓ 已保存: {filename}")
|
log(f"已保存: {filename}")
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ def plot_accuracy(self, accuracy_data, test_type):
|
|||||||
grade_color = "orange"
|
grade_color = "orange"
|
||||||
else:
|
else:
|
||||||
grade = "需要校准"
|
grade = "需要校准"
|
||||||
grade_icon = "✗"
|
grade_icon = "[Error]"
|
||||||
grade_color = "red"
|
grade_color = "red"
|
||||||
|
|
||||||
self.accuracy_ax.text(
|
self.accuracy_ax.text(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""CCT / 色度一致性绘制。
|
"""CCT / 色度一致性绘制。
|
||||||
|
|
||||||
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_cct 原样搬迁。
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_cct 原样搬迁。
|
||||||
"""
|
"""
|
||||||
@@ -16,7 +16,7 @@ def plot_cct(self, test_type):
|
|||||||
gray_data = self.results.get_intermediate_data("cct", "gray")
|
gray_data = self.results.get_intermediate_data("cct", "gray")
|
||||||
|
|
||||||
if not gray_data or len(gray_data) < 2:
|
if not gray_data or len(gray_data) < 2:
|
||||||
self.log_gui.log("⚠️ 无 xy 数据可用")
|
self.log_gui.log("无 xy 数据可用", level="error")
|
||||||
ax = self.cct_fig.add_subplot(111)
|
ax = self.cct_fig.add_subplot(111)
|
||||||
ax.text(
|
ax.text(
|
||||||
0.5,
|
0.5,
|
||||||
@@ -46,9 +46,9 @@ def plot_cct(self, test_type):
|
|||||||
total_points = len(gray_data)
|
total_points = len(gray_data)
|
||||||
grayscale = np.linspace(100 / total_points, 100, len(x_measured))
|
grayscale = np.linspace(100 / total_points, 100, len(x_measured))
|
||||||
|
|
||||||
self.log_gui.log(f"✓ 已移除第一个数据点,当前数据点数: {len(x_measured)}")
|
self.log_gui.log(f"已移除第一个数据点,当前数据点数: {len(x_measured)}", level="success")
|
||||||
self.log_gui.log(f" x范围: {min(x_measured):.6f} - {max(x_measured):.6f}")
|
self.log_gui.log(f" x范围: {min(x_measured):.6f} - {max(x_measured):.6f}", level="info")
|
||||||
self.log_gui.log(f" y范围: {min(y_measured):.6f} - {max(y_measured):.6f}")
|
self.log_gui.log(f" y范围: {min(y_measured):.6f} - {max(y_measured):.6f}", level="info")
|
||||||
|
|
||||||
# ========== 根据测试类型读取对应参数 ==========
|
# ========== 根据测试类型读取对应参数 ==========
|
||||||
if test_type == "sdr_movie":
|
if test_type == "sdr_movie":
|
||||||
@@ -57,50 +57,50 @@ def plot_cct(self, test_type):
|
|||||||
x_tolerance = float(self.sdr_cct_x_tolerance_var.get())
|
x_tolerance = float(self.sdr_cct_x_tolerance_var.get())
|
||||||
y_ideal = float(self.sdr_cct_y_ideal_var.get())
|
y_ideal = float(self.sdr_cct_y_ideal_var.get())
|
||||||
y_tolerance = float(self.sdr_cct_y_tolerance_var.get())
|
y_tolerance = float(self.sdr_cct_y_tolerance_var.get())
|
||||||
self.log_gui.log("✓ 使用 SDR 色度参数")
|
self.log_gui.log("使用 SDR 色度参数", level="success")
|
||||||
except:
|
except:
|
||||||
x_ideal = 0.3127
|
x_ideal = 0.3127
|
||||||
x_tolerance = 0.003
|
x_tolerance = 0.003
|
||||||
y_ideal = 0.3290
|
y_ideal = 0.3290
|
||||||
y_tolerance = 0.003
|
y_tolerance = 0.003
|
||||||
self.log_gui.log("⚠️ SDR 参数读取失败,使用默认值")
|
self.log_gui.log("SDR 参数读取失败,使用默认值", level="error")
|
||||||
elif test_type == "hdr_movie":
|
elif test_type == "hdr_movie":
|
||||||
try:
|
try:
|
||||||
x_ideal = float(self.hdr_cct_x_ideal_var.get())
|
x_ideal = float(self.hdr_cct_x_ideal_var.get())
|
||||||
x_tolerance = float(self.hdr_cct_x_tolerance_var.get())
|
x_tolerance = float(self.hdr_cct_x_tolerance_var.get())
|
||||||
y_ideal = float(self.hdr_cct_y_ideal_var.get())
|
y_ideal = float(self.hdr_cct_y_ideal_var.get())
|
||||||
y_tolerance = float(self.hdr_cct_y_tolerance_var.get())
|
y_tolerance = float(self.hdr_cct_y_tolerance_var.get())
|
||||||
self.log_gui.log("✓ 使用 HDR 色度参数")
|
self.log_gui.log("使用 HDR 色度参数", level="success")
|
||||||
except:
|
except:
|
||||||
x_ideal = 0.3127
|
x_ideal = 0.3127
|
||||||
x_tolerance = 0.003
|
x_tolerance = 0.003
|
||||||
y_ideal = 0.3290
|
y_ideal = 0.3290
|
||||||
y_tolerance = 0.003
|
y_tolerance = 0.003
|
||||||
self.log_gui.log("⚠️ HDR 参数读取失败,使用默认值")
|
self.log_gui.log("HDR 参数读取失败,使用默认值", level="error")
|
||||||
else: # screen_module
|
else: # screen_module
|
||||||
try:
|
try:
|
||||||
x_ideal = float(self.cct_x_ideal_var.get())
|
x_ideal = float(self.cct_x_ideal_var.get())
|
||||||
x_tolerance = float(self.cct_x_tolerance_var.get())
|
x_tolerance = float(self.cct_x_tolerance_var.get())
|
||||||
y_ideal = float(self.cct_y_ideal_var.get())
|
y_ideal = float(self.cct_y_ideal_var.get())
|
||||||
y_tolerance = float(self.cct_y_tolerance_var.get())
|
y_tolerance = float(self.cct_y_tolerance_var.get())
|
||||||
self.log_gui.log("✓ 使用屏模组色度参数")
|
self.log_gui.log("使用屏模组色度参数", level="success")
|
||||||
except:
|
except:
|
||||||
x_ideal = 0.306
|
x_ideal = 0.306
|
||||||
x_tolerance = 0.003
|
x_tolerance = 0.003
|
||||||
y_ideal = 0.318
|
y_ideal = 0.318
|
||||||
y_tolerance = 0.003
|
y_tolerance = 0.003
|
||||||
self.log_gui.log("⚠️ 屏模组参数读取失败,使用默认值")
|
self.log_gui.log("屏模组参数读取失败,使用默认值", level="error")
|
||||||
|
|
||||||
x_low = x_ideal - x_tolerance
|
x_low = x_ideal - x_tolerance
|
||||||
x_high = x_ideal + x_tolerance
|
x_high = x_ideal + x_tolerance
|
||||||
y_low = y_ideal - y_tolerance
|
y_low = y_ideal - y_tolerance
|
||||||
y_high = y_ideal + y_tolerance
|
y_high = y_ideal + y_tolerance
|
||||||
|
|
||||||
self.log_gui.log(f"✓ 用户设置参数:")
|
self.log_gui.log(f"用户设置参数:", level="success")
|
||||||
self.log_gui.log(f" x-ideal={x_ideal:.4f}, tolerance={x_tolerance:.4f}")
|
self.log_gui.log(f" x-ideal={x_ideal:.4f}, tolerance={x_tolerance:.4f}", level="info")
|
||||||
self.log_gui.log(f" x范围: [{x_low:.4f}, {x_high:.4f}]")
|
self.log_gui.log(f" x范围: [{x_low:.4f}, {x_high:.4f}]", level="info")
|
||||||
self.log_gui.log(f" y-ideal={y_ideal:.4f}, tolerance={y_tolerance:.4f}")
|
self.log_gui.log(f" y-ideal={y_ideal:.4f}, tolerance={y_tolerance:.4f}", level="info")
|
||||||
self.log_gui.log(f" y范围: [{y_low:.4f}, {y_high:.4f}]")
|
self.log_gui.log(f" y范围: [{y_low:.4f}, {y_high:.4f}]", level="info")
|
||||||
|
|
||||||
# 为所有测试类型创建子图
|
# 为所有测试类型创建子图
|
||||||
ax1 = self.cct_fig.add_subplot(211)
|
ax1 = self.cct_fig.add_subplot(211)
|
||||||
@@ -180,7 +180,7 @@ def plot_cct(self, test_type):
|
|||||||
x_max_data = max(x_measured)
|
x_max_data = max(x_measured)
|
||||||
data_range_x = x_max_data - x_min_data
|
data_range_x = x_max_data - x_min_data
|
||||||
|
|
||||||
self.log_gui.log(f" x数据波动: {data_range_x:.6f}")
|
self.log_gui.log(f" x数据波动: {data_range_x:.6f}", level="info")
|
||||||
|
|
||||||
range_span = x_tolerance * 2
|
range_span = x_tolerance * 2
|
||||||
margin_ratio = 0.20
|
margin_ratio = 0.20
|
||||||
@@ -190,16 +190,16 @@ def plot_cct(self, test_type):
|
|||||||
final_y_max = max(x_max_data, x_high) + extra_margin
|
final_y_max = max(x_max_data, x_high) + extra_margin
|
||||||
|
|
||||||
if x_min_data >= x_low and x_max_data <= x_high:
|
if x_min_data >= x_low and x_max_data <= x_high:
|
||||||
self.log_gui.log(f" x数据在tolerance范围内,使用tolerance范围显示")
|
self.log_gui.log(f" x数据在tolerance范围内,使用tolerance范围显示", level="info")
|
||||||
final_y_min = x_low - extra_margin
|
final_y_min = x_low - extra_margin
|
||||||
final_y_max = x_high + extra_margin
|
final_y_max = x_high + extra_margin
|
||||||
else:
|
else:
|
||||||
self.log_gui.log(f" x数据超出tolerance范围,扩展显示范围")
|
self.log_gui.log(f" x数据超出tolerance范围,扩展显示范围", level="info")
|
||||||
|
|
||||||
ax1.set_ylim(final_y_min, final_y_max)
|
ax1.set_ylim(final_y_min, final_y_max)
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f" x轴显示范围: {final_y_min:.6f} - {final_y_max:.6f} (跨度: {final_y_max - final_y_min:.6f})"
|
f" x轴显示范围: {final_y_min:.6f} - {final_y_max:.6f} (跨度: {final_y_max - final_y_min:.6f})"
|
||||||
)
|
, level="info")
|
||||||
|
|
||||||
# ========== 下图:y coordinates ==========
|
# ========== 下图:y coordinates ==========
|
||||||
ax2.plot(
|
ax2.plot(
|
||||||
@@ -273,7 +273,7 @@ def plot_cct(self, test_type):
|
|||||||
y_max_data = max(y_measured)
|
y_max_data = max(y_measured)
|
||||||
data_range_y = y_max_data - y_min_data
|
data_range_y = y_max_data - y_min_data
|
||||||
|
|
||||||
self.log_gui.log(f" y数据波动: {data_range_y:.6f}")
|
self.log_gui.log(f" y数据波动: {data_range_y:.6f}", level="info")
|
||||||
|
|
||||||
range_span = y_tolerance * 2
|
range_span = y_tolerance * 2
|
||||||
extra_margin = range_span * margin_ratio
|
extra_margin = range_span * margin_ratio
|
||||||
@@ -282,16 +282,16 @@ def plot_cct(self, test_type):
|
|||||||
final_y_max = max(y_max_data, y_high) + extra_margin
|
final_y_max = max(y_max_data, y_high) + extra_margin
|
||||||
|
|
||||||
if y_min_data >= y_low and y_max_data <= y_high:
|
if y_min_data >= y_low and y_max_data <= y_high:
|
||||||
self.log_gui.log(f" y数据在tolerance范围内,使用tolerance范围显示")
|
self.log_gui.log(f" y数据在tolerance范围内,使用tolerance范围显示", level="info")
|
||||||
final_y_min = y_low - extra_margin
|
final_y_min = y_low - extra_margin
|
||||||
final_y_max = y_high + extra_margin
|
final_y_max = y_high + extra_margin
|
||||||
else:
|
else:
|
||||||
self.log_gui.log(f" y数据超出tolerance范围,扩展显示范围")
|
self.log_gui.log(f" y数据超出tolerance范围,扩展显示范围", level="info")
|
||||||
|
|
||||||
ax2.set_ylim(final_y_min, final_y_max)
|
ax2.set_ylim(final_y_min, final_y_max)
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f" y轴显示范围: {final_y_min:.6f} - {final_y_max:.6f} (跨度: {final_y_max - final_y_min:.6f})"
|
f" y轴显示范围: {final_y_min:.6f} - {final_y_max:.6f} (跨度: {final_y_max - final_y_min:.6f})"
|
||||||
)
|
, level="info")
|
||||||
|
|
||||||
# ========== 总标题 - 统一格式(去掉统计信息)==========
|
# ========== 总标题 - 统一格式(去掉统计信息)==========
|
||||||
test_type_name = self.get_test_type_name(test_type)
|
test_type_name = self.get_test_type_name(test_type)
|
||||||
@@ -321,4 +321,4 @@ def plot_cct(self, test_type):
|
|||||||
self.cct_canvas.draw()
|
self.cct_canvas.draw()
|
||||||
self.chart_notebook.select(self.cct_chart_frame)
|
self.chart_notebook.select(self.cct_chart_frame)
|
||||||
|
|
||||||
self.log_gui.log("✓ xy 色度坐标图绘制完成")
|
self.log_gui.log("xy 色度坐标图绘制完成", level="success")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""EOTF 曲线绘制(HDR)。
|
"""EOTF 曲线绘制(HDR)。
|
||||||
|
|
||||||
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_eotf 原样搬迁。
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_eotf 原样搬迁。
|
||||||
"""
|
"""
|
||||||
@@ -145,4 +145,4 @@ def plot_eotf(self, L_bar, results_with_eotf_list, test_type):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.log_gui.log("EOTF 曲线 + 数据表格绘制完成")
|
self.log_gui.log("EOTF 曲线 + 数据表格绘制完成", level="success")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Gamma 曲线绘制。
|
"""Gamma 曲线绘制。
|
||||||
|
|
||||||
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamma 原样搬迁。
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamma 原样搬迁。
|
||||||
"""
|
"""
|
||||||
@@ -139,4 +139,4 @@ def plot_gamma(self, L_bar, results_with_gamma_list, target_gamma, test_type):
|
|||||||
self.gamma_canvas.draw()
|
self.gamma_canvas.draw()
|
||||||
self.chart_notebook.select(self.gamma_chart_frame)
|
self.chart_notebook.select(self.gamma_chart_frame)
|
||||||
|
|
||||||
self.log_gui.log("Gamma曲线 + 数据表格绘制完成")
|
self.log_gui.log("Gamma曲线 + 数据表格绘制完成", level="success")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""色域图(Gamut)绘制。
|
"""色域图(Gamut)绘制。
|
||||||
|
|
||||||
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamut 整体搬迁,
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamut 整体搬迁,
|
||||||
实现与原方法完全一致;原方法仅保留为一行转发。
|
实现与原方法完全一致;原方法仅保留为一行转发。
|
||||||
@@ -30,7 +30,7 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
UV_PIXELS_PER_U = 615.7260
|
UV_PIXELS_PER_U = 615.7260
|
||||||
UV_PIXELS_PER_V = 599.8432
|
UV_PIXELS_PER_V = 599.8432
|
||||||
|
|
||||||
# ========== ✅ 读取用户选择的参考标准 ==========
|
# ========== 读取用户选择的参考标准 ==========
|
||||||
if test_type == "screen_module":
|
if test_type == "screen_module":
|
||||||
current_ref = self.screen_gamut_ref_var.get()
|
current_ref = self.screen_gamut_ref_var.get()
|
||||||
elif test_type == "sdr_movie":
|
elif test_type == "sdr_movie":
|
||||||
@@ -40,7 +40,7 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
else:
|
else:
|
||||||
current_ref = "DCI-P3"
|
current_ref = "DCI-P3"
|
||||||
|
|
||||||
# ========== ✅✅✅ 根据参考标准重新计算覆盖率(XY 空间)==========
|
# ========== ✅✅根据参考标准重新计算覆盖率(XY 空间)==========
|
||||||
xy_coverage = coverage # 默认使用传入的值
|
xy_coverage = coverage # 默认使用传入的值
|
||||||
uv_coverage = 0.0
|
uv_coverage = 0.0
|
||||||
|
|
||||||
@@ -67,18 +67,18 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
xy_points
|
xy_points
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.log_gui.log(f"⚠️ 未知参考标准 '{current_ref}',使用 DCI-P3")
|
self.log_gui.log(f"未知参考标准 '{current_ref}',使用 DCI-P3", level="error")
|
||||||
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_DCIP3(
|
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_DCIP3(
|
||||||
xy_points
|
xy_points
|
||||||
)
|
)
|
||||||
current_ref = "DCI-P3"
|
current_ref = "DCI-P3"
|
||||||
|
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"✓ XY 空间覆盖率({current_ref}): {xy_coverage:.1f}%"
|
f"XY 空间覆盖率({current_ref}): {xy_coverage:.1f}%"
|
||||||
)
|
, level="success")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"⚠️ 重新计算 XY 覆盖率失败: {str(e)}")
|
self.log_gui.log(f"重新计算 XY 覆盖率失败: {str(e)}", level="error")
|
||||||
xy_coverage = coverage # 回退到传入值
|
xy_coverage = coverage # 回退到传入值
|
||||||
# =================================================
|
# =================================================
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
img_xy = mpimg.imread(get_resource_path("assets/cie.png"))
|
img_xy = mpimg.imread(get_resource_path("assets/cie.png"))
|
||||||
h_xy, w_xy = img_xy.shape[:2]
|
h_xy, w_xy = img_xy.shape[:2]
|
||||||
|
|
||||||
self.log_gui.log(f"加载 XY 色域图: {w_xy}x{h_xy}")
|
self.log_gui.log(f"加载 XY 色域图: {w_xy}x{h_xy}", level="info")
|
||||||
|
|
||||||
self.gamut_ax_xy.imshow(img_xy, extent=[0, w_xy, h_xy, 0], aspect="equal")
|
self.gamut_ax_xy.imshow(img_xy, extent=[0, w_xy, h_xy, 0], aspect="equal")
|
||||||
self.gamut_ax_xy.set_xlim(0, w_xy)
|
self.gamut_ax_xy.set_xlim(0, w_xy)
|
||||||
@@ -109,7 +109,7 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"测量色域: R({red_x:.4f},{red_y:.4f}) "
|
f"测量色域: R({red_x:.4f},{red_y:.4f}) "
|
||||||
f"G({green_x:.4f},{green_y:.4f}) B({blue_x:.4f},{blue_y:.4f})"
|
f"G({green_x:.4f},{green_y:.4f}) B({blue_x:.4f},{blue_y:.4f})"
|
||||||
)
|
, level="info")
|
||||||
|
|
||||||
# ========== 绘制测量三角形 ==========
|
# ========== 绘制测量三角形 ==========
|
||||||
points = [
|
points = [
|
||||||
@@ -257,7 +257,7 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
zorder=3,
|
zorder=3,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ========== ✅ XY 覆盖率标注(使用重新计算的值)==========
|
# ========== XY 覆盖率标注(使用重新计算的值)==========
|
||||||
self.gamut_ax_xy.text(
|
self.gamut_ax_xy.text(
|
||||||
w_xy * 0.85,
|
w_xy * 0.85,
|
||||||
h_xy * 0.92,
|
h_xy * 0.92,
|
||||||
@@ -287,17 +287,17 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"XY 图绘制失败: {str(e)}")
|
self.log_gui.log(f"XY 图绘制失败: {str(e)}", level="error")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
self.log_gui.log(traceback.format_exc())
|
self.log_gui.log(traceback.format_exc(), level="error")
|
||||||
|
|
||||||
# ========== 右图:CIE 1976 u'v' ==========
|
# ========== 右图:CIE 1976 u'v' ==========
|
||||||
try:
|
try:
|
||||||
img_uv = mpimg.imread(get_resource_path("assets/cie_uv.png"))
|
img_uv = mpimg.imread(get_resource_path("assets/cie_uv.png"))
|
||||||
h_uv, w_uv = img_uv.shape[:2]
|
h_uv, w_uv = img_uv.shape[:2]
|
||||||
|
|
||||||
self.log_gui.log(f"加载 UV 色域图: {w_uv}x{h_uv}")
|
self.log_gui.log(f"加载 UV 色域图: {w_uv}x{h_uv}", level="info")
|
||||||
|
|
||||||
self.gamut_ax_uv.imshow(img_uv, extent=[0, w_uv, h_uv, 0], aspect="equal")
|
self.gamut_ax_uv.imshow(img_uv, extent=[0, w_uv, h_uv, 0], aspect="equal")
|
||||||
self.gamut_ax_uv.set_xlim(0, w_uv)
|
self.gamut_ax_uv.set_xlim(0, w_uv)
|
||||||
@@ -329,18 +329,18 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
[u, v] for u, v in [xy_to_uv(r[0], r[1]) for r in rgb_results]
|
[u, v] for u, v in [xy_to_uv(r[0], r[1]) for r in rgb_results]
|
||||||
]
|
]
|
||||||
|
|
||||||
self.log_gui.log(f"UV 坐标: {uv_coords}")
|
self.log_gui.log(f"UV 坐标: {uv_coords}", level="info")
|
||||||
|
|
||||||
# ========== ✅✅✅ 计算 u'v' 覆盖率(使用参考标准)==========
|
# ========== ✅✅计算 u'v' 覆盖率(使用参考标准)==========
|
||||||
try:
|
try:
|
||||||
uv_coverage = pq_algorithm.calculate_uv_gamut_coverage(
|
uv_coverage = pq_algorithm.calculate_uv_gamut_coverage(
|
||||||
uv_coords, reference=current_ref
|
uv_coords, reference=current_ref
|
||||||
)
|
)
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"✓ UV 空间覆盖率({current_ref}): {uv_coverage:.1f}%"
|
f"UV 空间覆盖率({current_ref}): {uv_coverage:.1f}%"
|
||||||
)
|
, level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"⚠️ 计算 UV 覆盖率失败: {str(e)}")
|
self.log_gui.log(f"计算 UV 覆盖率失败: {str(e)}", level="error")
|
||||||
uv_coverage = 0.0
|
uv_coverage = 0.0
|
||||||
# =================================================
|
# =================================================
|
||||||
|
|
||||||
@@ -491,7 +491,7 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
zorder=3,
|
zorder=3,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ========== ✅ UV 覆盖率标注(使用动态计算的值)==========
|
# ========== UV 覆盖率标注(使用动态计算的值)==========
|
||||||
self.gamut_ax_uv.text(
|
self.gamut_ax_uv.text(
|
||||||
w_uv * 0.85,
|
w_uv * 0.85,
|
||||||
h_uv * 0.92,
|
h_uv * 0.92,
|
||||||
@@ -521,10 +521,10 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"UV 图绘制失败: {str(e)}")
|
self.log_gui.log(f"UV 图绘制失败: {str(e)}", level="error")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
self.log_gui.log(traceback.format_exc())
|
self.log_gui.log(traceback.format_exc(), level="error")
|
||||||
|
|
||||||
# ========== 总标题 ==========
|
# ========== 总标题 ==========
|
||||||
test_type_name = self.get_test_type_name(test_type)
|
test_type_name = self.get_test_type_name(test_type)
|
||||||
@@ -535,4 +535,4 @@ def plot_gamut(self, results, coverage, test_type):
|
|||||||
self.gamut_canvas.draw()
|
self.gamut_canvas.draw()
|
||||||
self.chart_notebook.select(self.gamut_chart_frame)
|
self.chart_notebook.select(self.gamut_chart_frame)
|
||||||
|
|
||||||
self.log_gui.log("色域图绘制完成")
|
self.log_gui.log("色域图绘制完成", level="success")
|
||||||
|
|||||||
@@ -375,13 +375,13 @@ class PQConfig:
|
|||||||
"default_pattern_gray", self.default_pattern_gray
|
"default_pattern_gray", self.default_pattern_gray
|
||||||
)
|
)
|
||||||
|
|
||||||
# ========== ✅ 强制使用新的 29色配置 ==========
|
# ========== 强制使用新的 29色配置 ==========
|
||||||
loaded_accuracy = config_dict.get("default_pattern_accuracy", None)
|
loaded_accuracy = config_dict.get("default_pattern_accuracy", None)
|
||||||
|
|
||||||
# 检查加载的配置是否是旧的 10色
|
# 检查加载的配置是否是旧的 10色
|
||||||
if loaded_accuracy and len(loaded_accuracy.get("pattern_params", [])) != 29:
|
if loaded_accuracy and len(loaded_accuracy.get("pattern_params", [])) != 29:
|
||||||
print(
|
print(
|
||||||
f"⚠️ 检测到旧的配置({len(loaded_accuracy.get('pattern_params', []))}色),强制使用新的 29色配置"
|
f"检测到旧的配置({len(loaded_accuracy.get('pattern_params', []))}色),强制使用新的 29色配置"
|
||||||
)
|
)
|
||||||
# 使用 __init__ 中定义的新配置
|
# 使用 __init__ 中定义的新配置
|
||||||
self.default_pattern_accuracy = self.default_pattern_accuracy
|
self.default_pattern_accuracy = self.default_pattern_accuracy
|
||||||
@@ -431,7 +431,7 @@ class PQConfig:
|
|||||||
self.current_pattern = self.default_pattern_rgb
|
self.current_pattern = self.default_pattern_rgb
|
||||||
elif mode == "gray":
|
elif mode == "gray":
|
||||||
self.current_pattern = self.default_pattern_gray
|
self.current_pattern = self.default_pattern_gray
|
||||||
elif mode == "accuracy": # ✅ 色准模式(SDR 和 HDR 通用 29色)
|
elif mode == "accuracy": # 色准模式(SDR 和 HDR 通用 29色)
|
||||||
self.current_pattern = self.default_pattern_accuracy
|
self.current_pattern = self.default_pattern_accuracy
|
||||||
elif mode == "custom":
|
elif mode == "custom":
|
||||||
# self.current_pattern = self.custom_pattern
|
# self.current_pattern = self.custom_pattern
|
||||||
@@ -459,7 +459,7 @@ class PQConfig:
|
|||||||
self.custom_pattern["measurement_max_value"] = len(pattern_params) - 1
|
self.custom_pattern["measurement_max_value"] = len(pattern_params) - 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# ========== ✅ 获取 29色名称列表 ==========
|
# ========== 获取 29色名称列表 ==========
|
||||||
def get_accuracy_color_names(self):
|
def get_accuracy_color_names(self):
|
||||||
"""
|
"""
|
||||||
获取色准测试的 29个颜色名称(SDR 和 HDR 通用)
|
获取色准测试的 29个颜色名称(SDR 和 HDR 通用)
|
||||||
@@ -502,7 +502,7 @@ class PQConfig:
|
|||||||
"100% Yellow",
|
"100% Yellow",
|
||||||
]
|
]
|
||||||
|
|
||||||
# ========== ✅ 获取 29色的 RGB 值 ==========
|
# ========== 获取 29色的 RGB 值 ==========
|
||||||
def get_accuracy_color_rgb(self):
|
def get_accuracy_color_rgb(self):
|
||||||
"""
|
"""
|
||||||
获取色准测试的 RGB 值(用于标准值计算)
|
获取色准测试的 RGB 值(用于标准值计算)
|
||||||
@@ -579,7 +579,7 @@ class PQConfig:
|
|||||||
return config_info
|
return config_info
|
||||||
|
|
||||||
|
|
||||||
# ========== ✅ 验证代码(测试完成后可删除)==========
|
# ========== 验证代码(测试完成后可删除)==========
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("验证 pq_config.py 配置")
|
print("验证 pq_config.py 配置")
|
||||||
@@ -596,7 +596,7 @@ if __name__ == "__main__":
|
|||||||
print(f" measurement_max_value: {max_value}")
|
print(f" measurement_max_value: {max_value}")
|
||||||
|
|
||||||
if pattern_count == 29 and max_value == 28:
|
if pattern_count == 29 and max_value == 28:
|
||||||
print("\n✅ 配置正确(29色)")
|
print("\n配置正确(29色)")
|
||||||
|
|
||||||
# 显示前 5 个图案
|
# 显示前 5 个图案
|
||||||
print("\n前5个图案:")
|
print("\n前5个图案:")
|
||||||
@@ -619,16 +619,16 @@ if __name__ == "__main__":
|
|||||||
print(f" current_pattern 图案数量: {current_count}")
|
print(f" current_pattern 图案数量: {current_count}")
|
||||||
|
|
||||||
if current_count == 29:
|
if current_count == 29:
|
||||||
print(" ✅ set_current_pattern 工作正常")
|
print(" set_current_pattern 工作正常")
|
||||||
else:
|
else:
|
||||||
print(f" ❌ set_current_pattern 失败!只有 {current_count} 个图案")
|
print(f" [Error] set_current_pattern 失败!只有 {current_count} 个图案")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(f"\n❌ 配置错误!")
|
print(f"\n[Error] 配置错误!")
|
||||||
print(f" 期望: 29 个图案, measurement_max_value=28")
|
print(f" 期望: 29 个图案, measurement_max_value=28")
|
||||||
print(f" 实际: {pattern_count} 个图案, measurement_max_value={max_value}")
|
print(f" 实际: {pattern_count} 个图案, measurement_max_value={max_value}")
|
||||||
|
|
||||||
print("\n❌ 请检查 default_pattern_accuracy 定义!")
|
print("\n[Error] 请检查 default_pattern_accuracy 定义!")
|
||||||
print(" 应该包含:")
|
print(" 应该包含:")
|
||||||
print(" - 5个灰阶")
|
print(" - 5个灰阶")
|
||||||
print(" - 18个 ColorChecker 色块")
|
print(" - 18个 ColorChecker 色块")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
"""Local Dimming 测试逻辑(应用层)。
|
"""Local Dimming 测试逻辑(应用层)。
|
||||||
|
|
||||||
整合自原 drivers/local_dimming_test.py:窗口图片生成与测试主循环
|
整合自原 drivers/local_dimming_test.py:窗口图片生成与测试主循环
|
||||||
直接落在本模块,UCD 通用操作下沉到 drivers.ucd_helpers。
|
直接落在本模块,UCD 通用操作下沉到 drivers.ucd_helpers。
|
||||||
@@ -107,51 +107,51 @@ def start_local_dimming_test(self):
|
|||||||
|
|
||||||
def worker():
|
def worker():
|
||||||
log = self.log_gui.log
|
log = self.log_gui.log
|
||||||
log("=" * 60)
|
log("=" * 60, level="separator")
|
||||||
log("开始 Local Dimming 测试")
|
log("开始 Local Dimming 测试", level="info")
|
||||||
log("=" * 60)
|
log("=" * 60, level="separator")
|
||||||
|
|
||||||
width, height = get_current_resolution(self.ucd)
|
width, height = get_current_resolution(self.ucd)
|
||||||
total = len(DEFAULT_WINDOW_PERCENTAGES)
|
total = len(DEFAULT_WINDOW_PERCENTAGES)
|
||||||
log(f" 分辨率: {width}x{height}")
|
log(f" 分辨率: {width}x{height}", level="info")
|
||||||
log(f" 测试窗口: {DEFAULT_WINDOW_PERCENTAGES}")
|
log(f" 测试窗口: {DEFAULT_WINDOW_PERCENTAGES}", level="info")
|
||||||
log(f" 等待时间: {wait_time} 秒")
|
log(f" 等待时间: {wait_time} 秒", level="info")
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for i, percentage in enumerate(DEFAULT_WINDOW_PERCENTAGES, 1):
|
for i, percentage in enumerate(DEFAULT_WINDOW_PERCENTAGES, 1):
|
||||||
if stop_event.is_set():
|
if stop_event.is_set():
|
||||||
log("⚠️ 测试已停止")
|
log("测试已停止", level="error")
|
||||||
break
|
break
|
||||||
|
|
||||||
log(f"[{i}/{total}] 测试 {percentage}% 窗口...")
|
log(f"[{i}/{total}] 测试 {percentage}% 窗口...", level="info")
|
||||||
try:
|
try:
|
||||||
image_path = _ensure_window_image(width, height, percentage)
|
image_path = _ensure_window_image(width, height, percentage)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f" ❌ 图像生成失败: {e}")
|
log(f" [Error] 图像生成失败: {e}", level="error")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not send_image_pattern(self.ucd, image_path):
|
if not send_image_pattern(self.ucd, image_path):
|
||||||
log(f" ❌ {percentage}% 窗口发送失败,跳过")
|
log(f" [Error] {percentage}% 窗口发送失败,跳过", level="error")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
log(f" ⏳ 等待 {wait_time} 秒...")
|
log(f"等待 {wait_time} 秒...", level="info")
|
||||||
time.sleep(wait_time)
|
time.sleep(wait_time)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f" ❌ 采集亮度异常: {e}")
|
log(f" [Error] 采集亮度异常: {e}", level="error")
|
||||||
continue
|
continue
|
||||||
if lv is None:
|
if lv is None:
|
||||||
log(f" ❌ {percentage}% 窗口采集失败")
|
log(f" [Error] {percentage}% 窗口采集失败", level="error")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
log(f" ✓ 采集亮度: {lv:.2f} cd/m²")
|
log(f"采集亮度: {lv:.2f} cd/m²", level="info")
|
||||||
results.append((percentage, x, y, lv, _X, _Y, _Z))
|
results.append((percentage, x, y, lv, _X, _Y, _Z))
|
||||||
|
|
||||||
log("=" * 60)
|
log("=" * 60, level="separator")
|
||||||
log(f"✅ Local Dimming 测试完成 ({len(results)}/{total})")
|
log(f"Local Dimming 测试完成 ({len(results)}/{total})", level="success")
|
||||||
log("=" * 60)
|
log("=" * 60, level="separator")
|
||||||
|
|
||||||
self.ld_test_results = results
|
self.ld_test_results = results
|
||||||
self._dispatch_ui(self.update_ld_results, results)
|
self._dispatch_ui(self.update_ld_results, results)
|
||||||
@@ -184,7 +184,7 @@ def send_ld_window(self, percentage):
|
|||||||
messagebox.showwarning("警告", "请先连接 UCD323 设备")
|
messagebox.showwarning("警告", "请先连接 UCD323 设备")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.log_gui.log(f"🔆 发送 {percentage}% 窗口...")
|
self.log_gui.log(f"🔆 发送 {percentage}% 窗口...", level="info")
|
||||||
self.current_ld_percentage = percentage
|
self.current_ld_percentage = percentage
|
||||||
|
|
||||||
def send():
|
def send():
|
||||||
@@ -192,12 +192,12 @@ def send_ld_window(self, percentage):
|
|||||||
try:
|
try:
|
||||||
image_path = _ensure_window_image(width, height, percentage)
|
image_path = _ensure_window_image(width, height, percentage)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._dispatch_ui(self.log_gui.log, f"❌ 图像生成失败: {e}")
|
self._dispatch_ui(self.log_gui.log, f"[Error] 图像生成失败: {e}")
|
||||||
return
|
return
|
||||||
ok = send_image_pattern(self.ucd, image_path)
|
ok = send_image_pattern(self.ucd, image_path)
|
||||||
msg = (
|
msg = (
|
||||||
f"✅ {percentage}% 窗口已发送" if ok
|
f"{percentage}% 窗口已发送" if ok
|
||||||
else f"❌ {percentage}% 窗口发送失败"
|
else f"[Error] {percentage}% 窗口发送失败"
|
||||||
)
|
)
|
||||||
self._dispatch_ui(self.log_gui.log, msg)
|
self._dispatch_ui(self.log_gui.log, msg)
|
||||||
|
|
||||||
@@ -213,16 +213,16 @@ def measure_ld_luminance(self):
|
|||||||
messagebox.showinfo("提示", "请先发送一个窗口图案")
|
messagebox.showinfo("提示", "请先发送一个窗口图案")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.log_gui.log("📏 正在采集亮度...")
|
self.log_gui.log("📏 正在采集亮度...", level="info")
|
||||||
|
|
||||||
def measure():
|
def measure():
|
||||||
try:
|
try:
|
||||||
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._dispatch_ui(self.log_gui.log, f"❌ 采集异常: {str(e)}")
|
self._dispatch_ui(self.log_gui.log, f"[Error] 采集异常: {str(e)}")
|
||||||
return
|
return
|
||||||
if lv is None:
|
if lv is None:
|
||||||
self._dispatch_ui(self.log_gui.log, "❌ 采集失败")
|
self._dispatch_ui(self.log_gui.log, "[Error] 采集失败")
|
||||||
return
|
return
|
||||||
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
|
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
|
||||||
self._dispatch_ui(
|
self._dispatch_ui(
|
||||||
@@ -236,7 +236,7 @@ def measure_ld_luminance(self):
|
|||||||
f"{lv:.2f}", f"{x:.4f}", f"{y:.4f}", timestamp,
|
f"{lv:.2f}", f"{x:.4f}", f"{y:.4f}", timestamp,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self._dispatch_ui(self.log_gui.log, f"✅ 采集完成: {lv:.2f} cd/m²")
|
self._dispatch_ui(self.log_gui.log, f"采集完成: {lv:.2f} cd/m²")
|
||||||
|
|
||||||
threading.Thread(target=measure, daemon=True).start()
|
threading.Thread(target=measure, daemon=True).start()
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ def clear_ld_records(self):
|
|||||||
self.ld_tree.delete(item)
|
self.ld_tree.delete(item)
|
||||||
self.ld_result_label.config(text="亮度: -- cd/m² | x: -- | y: --")
|
self.ld_result_label.config(text="亮度: -- cd/m² | x: -- | y: --")
|
||||||
self.current_ld_percentage = None
|
self.current_ld_percentage = None
|
||||||
self.log_gui.log("🗑️ 测试记录已清空")
|
self.log_gui.log("测试记录已清空", level="info")
|
||||||
|
|
||||||
|
|
||||||
def save_local_dimming_results(self):
|
def save_local_dimming_results(self):
|
||||||
@@ -274,8 +274,8 @@ def save_local_dimming_results(self):
|
|||||||
writer.writerow(["窗口百分比", "亮度 (cd/m²)", "x", "y", "时间"])
|
writer.writerow(["窗口百分比", "亮度 (cd/m²)", "x", "y", "时间"])
|
||||||
for item in self.ld_tree.get_children():
|
for item in self.ld_tree.get_children():
|
||||||
writer.writerow(self.ld_tree.item(item, "values"))
|
writer.writerow(self.ld_tree.item(item, "values"))
|
||||||
self.log_gui.log(f"✓ 测试结果已保存: {save_path}")
|
self.log_gui.log(f"测试结果已保存: {save_path}", level="success")
|
||||||
messagebox.showinfo("成功", f"测试结果已保存到:\n{save_path}")
|
messagebox.showinfo("成功", f"测试结果已保存到:\n{save_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"❌ 保存失败: {str(e)}")
|
self.log_gui.log(f"[Error] 保存失败: {str(e)}", level="error")
|
||||||
messagebox.showerror("错误", f"保存失败: {str(e)}")
|
messagebox.showerror("错误", f"保存失败: {str(e)}")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""图表框架相关逻辑(Step 3 重构)。
|
"""图表框架相关逻辑(Step 3 重构)。
|
||||||
|
|
||||||
从 pqAutomationApp.PQAutomationApp 中搬迁而来。每个函数第一行 `self = app`
|
从 pqAutomationApp.PQAutomationApp 中搬迁而来。每个函数第一行 `self = app`
|
||||||
以保留原有 `self.xxx` 属性访问不变。
|
以保留原有 `self.xxx` 属性访问不变。
|
||||||
@@ -21,7 +21,7 @@ def init_gamut_chart(self):
|
|||||||
canvas_widget = self.gamut_canvas.get_tk_widget()
|
canvas_widget = self.gamut_canvas.get_tk_widget()
|
||||||
canvas_widget.pack(expand=True, fill=tk.BOTH)
|
canvas_widget.pack(expand=True, fill=tk.BOTH)
|
||||||
|
|
||||||
# ✅ 恢复原来的大尺寸:0.84 高度
|
# 恢复原来的大尺寸:0.84 高度
|
||||||
self.gamut_ax_xy = self.gamut_fig.add_axes(
|
self.gamut_ax_xy = self.gamut_fig.add_axes(
|
||||||
[0.02, 0.08, 0.46, 0.84]
|
[0.02, 0.08, 0.46, 0.84]
|
||||||
) # ← 改回 0.84
|
) # ← 改回 0.84
|
||||||
@@ -47,7 +47,7 @@ def init_gamut_chart(self):
|
|||||||
self.gamut_canvas.draw()
|
self.gamut_canvas.draw()
|
||||||
|
|
||||||
def init_gamma_chart(self):
|
def init_gamma_chart(self):
|
||||||
"""初始化Gamma曲线图表 - 左侧曲线 + 右侧表格(✅ 4列 + 通用说明)"""
|
"""初始化Gamma曲线图表 - 左侧曲线 + 右侧表格(4列 + 通用说明)"""
|
||||||
container = ttk.Frame(self.gamma_chart_frame)
|
container = ttk.Frame(self.gamma_chart_frame)
|
||||||
container.pack(expand=True, fill=tk.BOTH)
|
container.pack(expand=True, fill=tk.BOTH)
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ def init_gamma_chart(self):
|
|||||||
self.gamma_canvas.draw()
|
self.gamma_canvas.draw()
|
||||||
|
|
||||||
def init_eotf_chart(self):
|
def init_eotf_chart(self):
|
||||||
"""初始化 EOTF 曲线图表(HDR 专用)- 左侧曲线 + 右侧表格(✅ 4列)"""
|
"""初始化 EOTF 曲线图表(HDR 专用)- 左侧曲线 + 右侧表格(4列)"""
|
||||||
container = ttk.Frame(self.eotf_chart_frame)
|
container = ttk.Frame(self.eotf_chart_frame)
|
||||||
container.pack(expand=True, fill=tk.BOTH)
|
container.pack(expand=True, fill=tk.BOTH)
|
||||||
|
|
||||||
@@ -741,7 +741,7 @@ def update_chart_tabs_state(self):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(f"更新Tab状态失败: {str(e)}")
|
self.log_gui.log(f"更新Tab状态失败: {str(e)}", level="error")
|
||||||
|
|
||||||
def create_result_chart_frame(self):
|
def create_result_chart_frame(self):
|
||||||
"""创建结果图表区域 - 6个独立Tab(Gamma 和 EOTF 分离)"""
|
"""创建结果图表区域 - 6个独立Tab(Gamma 和 EOTF 分离)"""
|
||||||
@@ -790,10 +790,10 @@ def create_result_chart_frame(self):
|
|||||||
# 绑定Tab切换事件
|
# 绑定Tab切换事件
|
||||||
self.chart_notebook.bind("<<NotebookTabChanged>>", self.on_chart_tab_changed)
|
self.chart_notebook.bind("<<NotebookTabChanged>>", self.on_chart_tab_changed)
|
||||||
|
|
||||||
# ==================== ✅ 在图表下方创建单步调试面板 ====================
|
# ==================== 在图表下方创建单步调试面板 ====================
|
||||||
self.debug_container = ttk.LabelFrame(
|
self.debug_container = ttk.LabelFrame(
|
||||||
self.result_frame, # ← 放在 result_frame 内,图表正下方
|
self.result_frame, # ← 放在 result_frame 内,图表正下方
|
||||||
text="🔧 单步调试",
|
text=" 单步调试",
|
||||||
padding=10,
|
padding=10,
|
||||||
)
|
)
|
||||||
# 默认不显示
|
# 默认不显示
|
||||||
@@ -801,7 +801,7 @@ def create_result_chart_frame(self):
|
|||||||
# 创建单步调试面板实例
|
# 创建单步调试面板实例
|
||||||
self.debug_panel = PQDebugPanel(self.debug_container, self)
|
self.debug_panel = PQDebugPanel(self.debug_container, self)
|
||||||
|
|
||||||
self.log_gui.log("✓ 单步调试面板已创建(放在测试结果图表下方)")
|
self.log_gui.log("单步调试面板已创建(放在测试结果图表下方)", level="success")
|
||||||
|
|
||||||
def on_chart_tab_changed(self, event):
|
def on_chart_tab_changed(self, event):
|
||||||
"""Tab切换时的事件处理"""
|
"""Tab切换时的事件处理"""
|
||||||
@@ -810,5 +810,5 @@ def on_chart_tab_changed(self, event):
|
|||||||
self.chart_notebook.select()
|
self.chart_notebook.select()
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"Tab切换事件处理失败: {str(e)}")
|
self.log_gui.log(f"Tab切换事件处理失败: {str(e)}", level="error")
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""CCT 参数面板及其处理函数(与主文件重构版本保持同步)。"""
|
"""CCT 参数面板及其处理函数(与主文件重构版本保持同步)。"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
@@ -10,7 +10,7 @@ import algorithm.pq_algorithm as pq_algorithm
|
|||||||
|
|
||||||
|
|
||||||
def create_cct_params_frame(self):
|
def create_cct_params_frame(self):
|
||||||
"""创建色度参数设置区域 - 屏模组、SDR、HDR 独立(✅ 增加色域参考标准选择 + 单步调试按钮)"""
|
"""创建色度参数设置区域 - 屏模组、SDR、HDR 独立(增加色域参考标准选择 + 单步调试按钮)"""
|
||||||
|
|
||||||
# ==================== 屏模组色度参数 Frame ====================
|
# ==================== 屏模组色度参数 Frame ====================
|
||||||
self.cct_params_frame = ttk.LabelFrame(
|
self.cct_params_frame = ttk.LabelFrame(
|
||||||
@@ -84,7 +84,7 @@ def create_cct_params_frame(self):
|
|||||||
)
|
)
|
||||||
self.screen_gamut_combo = screen_gamut_combo
|
self.screen_gamut_combo = screen_gamut_combo
|
||||||
|
|
||||||
# ==================== ✅ 单步调试按钮(右侧第二行)====================
|
# ==================== 单步调试按钮(右侧第二行)====================
|
||||||
ttk.Label(self.cct_params_frame, text="单步调试:").grid(
|
ttk.Label(self.cct_params_frame, text="单步调试:").grid(
|
||||||
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
||||||
)
|
)
|
||||||
@@ -94,7 +94,7 @@ def create_cct_params_frame(self):
|
|||||||
text="打开调试面板",
|
text="打开调试面板",
|
||||||
command=self.toggle_screen_debug_panel,
|
command=self.toggle_screen_debug_panel,
|
||||||
bootstyle="info-outline",
|
bootstyle="info-outline",
|
||||||
state=tk.DISABLED, # 初始禁用
|
# state=tk.DISABLED, # 初始禁用
|
||||||
width=15,
|
width=15,
|
||||||
)
|
)
|
||||||
self.screen_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
self.screen_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
||||||
@@ -201,7 +201,7 @@ def create_cct_params_frame(self):
|
|||||||
sdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_sdr_gamut_ref_changed)
|
sdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_sdr_gamut_ref_changed)
|
||||||
self.sdr_gamut_combo = sdr_gamut_combo
|
self.sdr_gamut_combo = sdr_gamut_combo
|
||||||
|
|
||||||
# ==================== ✅ SDR 单步调试按钮(右侧第二行)====================
|
# ==================== SDR 单步调试按钮(右侧第二行)====================
|
||||||
ttk.Label(self.sdr_cct_params_frame, text="单步调试:").grid(
|
ttk.Label(self.sdr_cct_params_frame, text="单步调试:").grid(
|
||||||
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
||||||
)
|
)
|
||||||
@@ -211,7 +211,7 @@ def create_cct_params_frame(self):
|
|||||||
text="打开调试面板",
|
text="打开调试面板",
|
||||||
command=self.toggle_sdr_debug_panel,
|
command=self.toggle_sdr_debug_panel,
|
||||||
bootstyle="info-outline",
|
bootstyle="info-outline",
|
||||||
state=tk.DISABLED, # 初始禁用
|
# state=tk.DISABLED, # 初始禁用
|
||||||
width=15,
|
width=15,
|
||||||
)
|
)
|
||||||
self.sdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
self.sdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
||||||
@@ -318,7 +318,7 @@ def create_cct_params_frame(self):
|
|||||||
hdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_hdr_gamut_ref_changed)
|
hdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_hdr_gamut_ref_changed)
|
||||||
self.hdr_gamut_combo = hdr_gamut_combo
|
self.hdr_gamut_combo = hdr_gamut_combo
|
||||||
|
|
||||||
# ==================== ✅ HDR 单步调试按钮(右侧第二行)====================
|
# ==================== HDR 单步调试按钮(右侧第二行)====================
|
||||||
ttk.Label(self.hdr_cct_params_frame, text="单步调试:").grid(
|
ttk.Label(self.hdr_cct_params_frame, text="单步调试:").grid(
|
||||||
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
||||||
)
|
)
|
||||||
@@ -328,7 +328,7 @@ def create_cct_params_frame(self):
|
|||||||
text="打开调试面板",
|
text="打开调试面板",
|
||||||
command=self.toggle_hdr_debug_panel,
|
command=self.toggle_hdr_debug_panel,
|
||||||
bootstyle="info-outline",
|
bootstyle="info-outline",
|
||||||
state=tk.DISABLED, # 初始禁用
|
# state=tk.DISABLED, # 初始禁用
|
||||||
width=15,
|
width=15,
|
||||||
)
|
)
|
||||||
self.hdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
self.hdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
||||||
@@ -427,7 +427,7 @@ def _handle_cct_focus_out(self, var, default_value, save_func, label):
|
|||||||
if value == "":
|
if value == "":
|
||||||
var.set(str(default_value))
|
var.set(str(default_value))
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(f"✓ {label} 参数为空,恢复默认值: {default_value}")
|
self.log_gui.log(f"{label} 参数为空,恢复默认值: {default_value}", level="success")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
float_val = float(value)
|
float_val = float(value)
|
||||||
@@ -435,19 +435,19 @@ def _handle_cct_focus_out(self, var, default_value, save_func, label):
|
|||||||
var.set(str(default_value))
|
var.set(str(default_value))
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"⚠️ {label} 参数超出范围,恢复默认值: {default_value}"
|
f"{label} 参数超出范围,恢复默认值: {default_value}"
|
||||||
)
|
, level="error")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
var.set(str(default_value))
|
var.set(str(default_value))
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
f"⚠️ {label} 参数无效,恢复默认值: {default_value}"
|
f"{label} 参数无效,恢复默认值: {default_value}"
|
||||||
)
|
, level="error")
|
||||||
|
|
||||||
save_func()
|
save_func()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(f"处理 {label} 参数失败: {str(e)}")
|
self.log_gui.log(f"处理 {label} 参数失败: {str(e)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
def on_sdr_cct_param_focus_out(self, var, default_value):
|
def on_sdr_cct_param_focus_out(self, var, default_value):
|
||||||
@@ -475,7 +475,7 @@ def recalculate_cct(self):
|
|||||||
try:
|
try:
|
||||||
# 1. 保存新参数
|
# 1. 保存新参数
|
||||||
self.save_cct_params()
|
self.save_cct_params()
|
||||||
self.log_gui.log("✓ 色度参数已更新")
|
self.log_gui.log("色度参数已更新", level="success")
|
||||||
|
|
||||||
# 2. 收起配置项
|
# 2. 收起配置项
|
||||||
if hasattr(self, "config_panel_frame"):
|
if hasattr(self, "config_panel_frame"):
|
||||||
@@ -493,7 +493,7 @@ def recalculate_cct(self):
|
|||||||
|
|
||||||
# 4. 检查是否有数据
|
# 4. 检查是否有数据
|
||||||
if not hasattr(self, "results") or not self.results:
|
if not hasattr(self, "results") or not self.results:
|
||||||
self.log_gui.log("⚠️ 没有测试数据,无法重新绘制")
|
self.log_gui.log("没有测试数据,无法重新绘制", level="error")
|
||||||
messagebox.showwarning("警告", "请先完成测试后再重新计算")
|
messagebox.showwarning("警告", "请先完成测试后再重新计算")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -503,14 +503,14 @@ def recalculate_cct(self):
|
|||||||
gray_data = self.results.get_intermediate_data("cct", "gray")
|
gray_data = self.results.get_intermediate_data("cct", "gray")
|
||||||
|
|
||||||
if not gray_data or len(gray_data) < 2:
|
if not gray_data or len(gray_data) < 2:
|
||||||
self.log_gui.log("⚠️ 没有可用的灰阶数据")
|
self.log_gui.log("没有可用的灰阶数据", level="error")
|
||||||
messagebox.showwarning("警告", "没有找到色度测试数据")
|
messagebox.showwarning("警告", "没有找到色度测试数据")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 6. 重新计算 CCT
|
# 6. 重新计算 CCT
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
self.log_gui.log("开始重新计算色度一致性...")
|
self.log_gui.log("开始重新计算色度一致性...", level="info")
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
|
|
||||||
cct_values = pq_algorithm.calculate_cct_from_results(gray_data)
|
cct_values = pq_algorithm.calculate_cct_from_results(gray_data)
|
||||||
|
|
||||||
@@ -521,14 +521,14 @@ def recalculate_cct(self):
|
|||||||
test_type = self.config.current_test_type
|
test_type = self.config.current_test_type
|
||||||
self.plot_cct(test_type)
|
self.plot_cct(test_type)
|
||||||
|
|
||||||
self.log_gui.log("✓ 色度图已重新绘制")
|
self.log_gui.log("色度图已重新绘制", level="success")
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
|
|
||||||
messagebox.showinfo("成功", "色度图已根据新参数重新绘制!")
|
messagebox.showinfo("成功", "色度图已根据新参数重新绘制!")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"❌ 重新计算失败: {str(e)}")
|
self.log_gui.log(f"[Error] 重新计算失败: {str(e)}", level="error")
|
||||||
self.log_gui.log(traceback.format_exc())
|
self.log_gui.log(traceback.format_exc(), level="error")
|
||||||
messagebox.showerror("错误", f"重新计算失败: {str(e)}")
|
messagebox.showerror("错误", f"重新计算失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@@ -551,7 +551,7 @@ def recalculate_gamut(self):
|
|||||||
|
|
||||||
# 3. 检查是否有数据
|
# 3. 检查是否有数据
|
||||||
if not hasattr(self, "results") or not self.results:
|
if not hasattr(self, "results") or not self.results:
|
||||||
self.log_gui.log("⚠️ 没有测试数据,无法重新绘制")
|
self.log_gui.log("没有测试数据,无法重新绘制", level="error")
|
||||||
messagebox.showwarning("警告", "请先完成测试后再重新计算")
|
messagebox.showwarning("警告", "请先完成测试后再重新计算")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -559,7 +559,7 @@ def recalculate_gamut(self):
|
|||||||
rgb_data = self.results.get_intermediate_data("gamut", "rgb")
|
rgb_data = self.results.get_intermediate_data("gamut", "rgb")
|
||||||
|
|
||||||
if not rgb_data or len(rgb_data) < 3:
|
if not rgb_data or len(rgb_data) < 3:
|
||||||
self.log_gui.log("⚠️ 没有可用的色域数据")
|
self.log_gui.log("没有可用的色域数据", level="error")
|
||||||
messagebox.showwarning("警告", "没有找到色域测试数据")
|
messagebox.showwarning("警告", "没有找到色域测试数据")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -576,9 +576,9 @@ def recalculate_gamut(self):
|
|||||||
else:
|
else:
|
||||||
reference_standard = "DCI-P3"
|
reference_standard = "DCI-P3"
|
||||||
|
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
self.log_gui.log(f"开始重新计算色域(参考标准: {reference_standard})...")
|
self.log_gui.log(f"开始重新计算色域(参考标准: {reference_standard})...", level="info")
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
|
|
||||||
# 7. 重新计算 XY 色域覆盖率
|
# 7. 重新计算 XY 色域覆盖率
|
||||||
xy_points = [[result[0], result[1]] for result in rgb_data]
|
xy_points = [[result[0], result[1]] for result in rgb_data]
|
||||||
@@ -602,10 +602,10 @@ def recalculate_gamut(self):
|
|||||||
)
|
)
|
||||||
reference_standard = "DCI-P3"
|
reference_standard = "DCI-P3"
|
||||||
|
|
||||||
self.log_gui.log(f"✓ 参考标准: {reference_standard}")
|
self.log_gui.log(f"参考标准: {reference_standard}", level="success")
|
||||||
self.log_gui.log(f"✓ XY 色域覆盖率: {coverage_xy:.1f}%")
|
self.log_gui.log(f"XY 色域覆盖率: {coverage_xy:.1f}%", level="success")
|
||||||
|
|
||||||
# ========== ✅✅✅ 8. 重新计算 UV 色域覆盖率 ==========
|
# ========== ✅✅8. 重新计算 UV 色域覆盖率 ==========
|
||||||
# 将 XY 坐标转换为 UV 坐标
|
# 将 XY 坐标转换为 UV 坐标
|
||||||
uv_points = []
|
uv_points = []
|
||||||
for x, y in xy_points:
|
for x, y in xy_points:
|
||||||
@@ -621,7 +621,7 @@ def recalculate_gamut(self):
|
|||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.log_gui.log(f"✓ 转换后的 UV 点数量: {len(uv_points)}")
|
self.log_gui.log(f"转换后的 UV 点数量: {len(uv_points)}", level="success")
|
||||||
|
|
||||||
# 根据参考标准计算 UV 覆盖率
|
# 根据参考标准计算 UV 覆盖率
|
||||||
if reference_standard == "BT.2020":
|
if reference_standard == "BT.2020":
|
||||||
@@ -641,10 +641,10 @@ def recalculate_gamut(self):
|
|||||||
uv_points
|
uv_points
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log_gui.log(f"✓ UV 色域覆盖率: {coverage_uv:.1f}%")
|
self.log_gui.log(f"UV 色域覆盖率: {coverage_uv:.1f}%", level="success")
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
|
||||||
# 9. ✅ 更新结果(同时保存 XY 和 UV 覆盖率)
|
# 9. 更新结果(同时保存 XY 和 UV 覆盖率)
|
||||||
self.results.set_test_item_result(
|
self.results.set_test_item_result(
|
||||||
"gamut",
|
"gamut",
|
||||||
{
|
{
|
||||||
@@ -659,13 +659,13 @@ def recalculate_gamut(self):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log_gui.log("✓ 测试结果已更新到 results 对象")
|
self.log_gui.log("测试结果已更新到 results 对象", level="success")
|
||||||
|
|
||||||
# 10. 重新绘制色域图
|
# 10. 重新绘制色域图
|
||||||
self.plot_gamut(rgb_data, coverage_xy, test_type)
|
self.plot_gamut(rgb_data, coverage_xy, test_type)
|
||||||
|
|
||||||
self.log_gui.log("✓ 色域图已重新绘制")
|
self.log_gui.log("色域图已重新绘制", level="success")
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
|
|
||||||
messagebox.showinfo(
|
messagebox.showinfo(
|
||||||
"成功",
|
"成功",
|
||||||
@@ -675,8 +675,8 @@ def recalculate_gamut(self):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"❌ 重新计算失败: {str(e)}")
|
self.log_gui.log(f"[Error] 重新计算失败: {str(e)}", level="error")
|
||||||
self.log_gui.log(traceback.format_exc())
|
self.log_gui.log(traceback.format_exc(), level="error")
|
||||||
messagebox.showerror("错误", f"重新计算失败: {str(e)}")
|
messagebox.showerror("错误", f"重新计算失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@@ -709,7 +709,7 @@ def reload_cct_params(self):
|
|||||||
|
|
||||||
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)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
def toggle_cct_params_frame(self):
|
def toggle_cct_params_frame(self):
|
||||||
@@ -743,7 +743,7 @@ def toggle_cct_params_frame(self):
|
|||||||
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)
|
||||||
else:
|
else:
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log("[ERROR] HDR 色度参数框尚未创建")
|
self.log_gui.log("[ERROR] HDR 色度参数框尚未创建", level="error")
|
||||||
|
|
||||||
|
|
||||||
# ---- gamut 参考标准改变回调(统一实现) ----
|
# ---- gamut 参考标准改变回调(统一实现) ----
|
||||||
@@ -758,14 +758,14 @@ def _on_gamut_ref_changed(self, test_type, event=None):
|
|||||||
cfg = _GAMUT_REF_CONFIGS[test_type]
|
cfg = _GAMUT_REF_CONFIGS[test_type]
|
||||||
try:
|
try:
|
||||||
new_ref = getattr(self, cfg["var_attr"]).get()
|
new_ref = getattr(self, cfg["var_attr"]).get()
|
||||||
self.log_gui.log(f"✓ {cfg['label']} 色域参考标准已更改为: {new_ref}")
|
self.log_gui.log(f"{cfg['label']} 色域参考标准已更改为: {new_ref}", level="success")
|
||||||
|
|
||||||
if test_type not in self.config.current_test_types:
|
if test_type not in self.config.current_test_types:
|
||||||
self.config.current_test_types[test_type] = {}
|
self.config.current_test_types[test_type] = {}
|
||||||
self.config.current_test_types[test_type]["gamut_reference"] = new_ref
|
self.config.current_test_types[test_type]["gamut_reference"] = new_ref
|
||||||
self.save_pq_config()
|
self.save_pq_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"保存 {cfg['label']} 色域参考标准失败: {str(e)}")
|
self.log_gui.log(f"保存 {cfg['label']} 色域参考标准失败: {str(e)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
def on_screen_gamut_ref_changed(self, event=None):
|
def on_screen_gamut_ref_changed(self, event=None):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""自定义模板结果面板(Step 6 重构)。"""
|
"""自定义模板结果面板(Step 6 重构)。"""
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -274,7 +274,7 @@ def _run_custom_row_single_step(self, item_id, row_no):
|
|||||||
"""后台执行客户模板单步测试"""
|
"""后台执行客户模板单步测试"""
|
||||||
try:
|
try:
|
||||||
self._dispatch_ui(self.status_var.set, f"单步测试第 {row_no} 行...")
|
self._dispatch_ui(self.status_var.set, f"单步测试第 {row_no} 行...")
|
||||||
self.log_gui.log(f"开始单步测试第 {row_no} 行")
|
self.log_gui.log(f"开始单步测试第 {row_no} 行", level="info")
|
||||||
|
|
||||||
self.config.set_current_pattern("custom")
|
self.config.set_current_pattern("custom")
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@ def _run_custom_row_single_step(self, item_id, row_no):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if row_no > len(converted_params):
|
if row_no > len(converted_params):
|
||||||
self.log_gui.log(f"❌ 行号超出 pattern 范围: {row_no}/{len(converted_params)}")
|
self.log_gui.log(f"[Error] 行号超出 pattern 范围: {row_no}/{len(converted_params)}", level="error")
|
||||||
self._dispatch_ui(self.status_var.set, "单步测试失败:行号超范围")
|
self._dispatch_ui(self.status_var.set, "单步测试失败:行号超范围")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -335,11 +335,11 @@ def _run_custom_row_single_step(self, item_id, row_no):
|
|||||||
self._update_custom_result_row, item_id, row_no, row_data
|
self._update_custom_result_row, item_id, row_no, row_data
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log_gui.log(f"✓ 第 {row_no} 行单步测试完成并已覆盖")
|
self.log_gui.log(f"第 {row_no} 行单步测试完成并已覆盖", level="success")
|
||||||
self._dispatch_ui(self.status_var.set, f"第 {row_no} 行单步测试完成")
|
self._dispatch_ui(self.status_var.set, f"第 {row_no} 行单步测试完成")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"❌ 单步测试失败: {str(e)}")
|
self.log_gui.log(f"[Error] 单步测试失败: {str(e)}", level="error")
|
||||||
self._dispatch_ui(self.status_var.set, "单步测试失败")
|
self._dispatch_ui(self.status_var.set, "单步测试失败")
|
||||||
|
|
||||||
|
|
||||||
@@ -423,7 +423,7 @@ def copy_custom_result_table(self):
|
|||||||
if hasattr(self, "status_var"):
|
if hasattr(self, "status_var"):
|
||||||
self.status_var.set(f"已复制 {len(items)} 行客户模板数据到剪贴板")
|
self.status_var.set(f"已复制 {len(items)} 行客户模板数据到剪贴板")
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(f"✓ 已复制客户模板表格数据({len(items)} 行)")
|
self.log_gui.log(f"已复制客户模板表格数据({len(items)} 行)", level="success")
|
||||||
|
|
||||||
|
|
||||||
def fill_custom_result_test_data(self):
|
def fill_custom_result_test_data(self):
|
||||||
@@ -465,7 +465,7 @@ def fill_custom_result_test_data(self):
|
|||||||
if hasattr(self, "status_var"):
|
if hasattr(self, "status_var"):
|
||||||
self.status_var.set("已填充 147 行客户模板测试数据")
|
self.status_var.set("已填充 147 行客户模板测试数据")
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log("✓ 已填充 147 行客户模板测试数据")
|
self.log_gui.log("已填充 147 行客户模板测试数据", level="success")
|
||||||
|
|
||||||
|
|
||||||
def clear_custom_template_results(self):
|
def clear_custom_template_results(self):
|
||||||
@@ -511,7 +511,7 @@ def auto_expand_custom_result_view(self):
|
|||||||
self.root.update_idletasks()
|
self.root.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"⚠️ 自动扩展客户模板窗口失败: {str(e)}")
|
self.log_gui.log(f"自动扩展客户模板窗口失败: {str(e)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
def append_custom_template_result(self, row_no, result_data):
|
def append_custom_template_result(self, row_no, result_data):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""主布局面板创建函数(Step 6 重构)。"""
|
"""主布局面板创建函数(Step 6 重构)。"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
@@ -405,7 +405,7 @@ def create_test_type_frame(self):
|
|||||||
fill=tk.X, padx=10, pady=10
|
fill=tk.X, padx=10, pady=10
|
||||||
)
|
)
|
||||||
|
|
||||||
# ✅ 只保留日志按钮
|
# 只保留日志按钮
|
||||||
self.log_btn = ttk.Button(
|
self.log_btn = ttk.Button(
|
||||||
self.sidebar_frame,
|
self.sidebar_frame,
|
||||||
text="测试日志",
|
text="测试日志",
|
||||||
@@ -515,7 +515,7 @@ def on_screen_module_timing_changed(self, event=None):
|
|||||||
selected_timing = self.screen_module_timing_var.get()
|
selected_timing = self.screen_module_timing_var.get()
|
||||||
|
|
||||||
# 记录日志
|
# 记录日志
|
||||||
self.log_gui.log(f"屏模组信号格式已更改为: {selected_timing}")
|
self.log_gui.log(f"屏模组信号格式已更改为: {selected_timing}", level="info")
|
||||||
|
|
||||||
match = re.search(r"(\d+)x(\d+)\s*@\s*(\d+)", selected_timing)
|
match = re.search(r"(\d+)x(\d+)\s*@\s*(\d+)", selected_timing)
|
||||||
if match:
|
if match:
|
||||||
@@ -523,28 +523,28 @@ def on_screen_module_timing_changed(self, event=None):
|
|||||||
height = int(match.group(2))
|
height = int(match.group(2))
|
||||||
refresh_rate = int(match.group(3))
|
refresh_rate = int(match.group(3))
|
||||||
|
|
||||||
self.log_gui.log(f" ├─ 分辨率: {width}x{height}")
|
self.log_gui.log(f" ├─ 分辨率: {width}x{height}", level="info")
|
||||||
self.log_gui.log(f" └─ 刷新率: {refresh_rate}Hz")
|
self.log_gui.log(f" └─ 刷新率: {refresh_rate}Hz", level="info")
|
||||||
|
|
||||||
# 根据分辨率给出提示
|
# 根据分辨率给出提示
|
||||||
if width >= 3840: # 4K及以上
|
if width >= 3840: # 4K及以上
|
||||||
self.log_gui.log(" ℹ️ 检测到4K分辨率")
|
self.log_gui.log(" ℹ️ 检测到4K分辨率", level="info")
|
||||||
|
|
||||||
if refresh_rate >= 120:
|
if refresh_rate >= 120:
|
||||||
self.log_gui.log(" ℹ️ 检测到高刷新率")
|
self.log_gui.log(" ℹ️ 检测到高刷新率", level="info")
|
||||||
|
|
||||||
# 更新配置
|
# 更新配置
|
||||||
self.config.set_current_timing(selected_timing)
|
self.config.set_current_timing(selected_timing)
|
||||||
|
|
||||||
# 如果正在测试,提示用户
|
# 如果正在测试,提示用户
|
||||||
if self.testing:
|
if self.testing:
|
||||||
self.log_gui.log("⚠️ 警告: 测试进行中,信号格式更改将在下次测试时生效")
|
self.log_gui.log("警告: 测试进行中,信号格式更改将在下次测试时生效", level="error")
|
||||||
|
|
||||||
# 保存配置
|
# 保存配置
|
||||||
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)}", level="error")
|
||||||
|
|
||||||
|
|
||||||
def update_test_items(self):
|
def update_test_items(self):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""侧边面板(日志 / Local Dimming / 调试)(Step 6 重构)。"""
|
"""侧边面板(日志 / Local Dimming / 调试)(Step 6 重构)。"""
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
@@ -141,7 +141,7 @@ def create_local_dimming_panel(self):
|
|||||||
|
|
||||||
self.ld_clear_btn = ttk.Button(
|
self.ld_clear_btn = ttk.Button(
|
||||||
bottom_frame,
|
bottom_frame,
|
||||||
text="🗑️ 清空记录",
|
text="清空记录",
|
||||||
command=self.clear_ld_records,
|
command=self.clear_ld_records,
|
||||||
bootstyle="danger-outline",
|
bootstyle="danger-outline",
|
||||||
width=12,
|
width=12,
|
||||||
@@ -187,7 +187,7 @@ DEBUG_PANEL_CONFIGS = {
|
|||||||
"screen_module": {
|
"screen_module": {
|
||||||
"window_attr": "debug_window",
|
"window_attr": "debug_window",
|
||||||
"btn_attr": "screen_debug_btn",
|
"btn_attr": "screen_debug_btn",
|
||||||
"title": "🔧 单步调试面板",
|
"title": " 单步调试面板",
|
||||||
"window_log_prefix": "",
|
"window_log_prefix": "",
|
||||||
"data_log_prefix": "屏模组",
|
"data_log_prefix": "屏模组",
|
||||||
"failure_data_label": "调试数据",
|
"failure_data_label": "调试数据",
|
||||||
@@ -200,7 +200,7 @@ DEBUG_PANEL_CONFIGS = {
|
|||||||
"sdr_movie": {
|
"sdr_movie": {
|
||||||
"window_attr": "sdr_debug_window",
|
"window_attr": "sdr_debug_window",
|
||||||
"btn_attr": "sdr_debug_btn",
|
"btn_attr": "sdr_debug_btn",
|
||||||
"title": "🔧 SDR 单步调试面板",
|
"title": " SDR 单步调试面板",
|
||||||
"window_log_prefix": "SDR ",
|
"window_log_prefix": "SDR ",
|
||||||
"data_log_prefix": "SDR",
|
"data_log_prefix": "SDR",
|
||||||
"failure_data_label": "SDR 调试数据",
|
"failure_data_label": "SDR 调试数据",
|
||||||
@@ -213,7 +213,7 @@ DEBUG_PANEL_CONFIGS = {
|
|||||||
"hdr_movie": {
|
"hdr_movie": {
|
||||||
"window_attr": "hdr_debug_window",
|
"window_attr": "hdr_debug_window",
|
||||||
"btn_attr": "hdr_debug_btn",
|
"btn_attr": "hdr_debug_btn",
|
||||||
"title": "🔧 HDR 单步调试面板",
|
"title": " HDR 单步调试面板",
|
||||||
"window_log_prefix": "HDR ",
|
"window_log_prefix": "HDR ",
|
||||||
"data_log_prefix": "HDR",
|
"data_log_prefix": "HDR",
|
||||||
"failure_data_label": "HDR 调试数据",
|
"failure_data_label": "HDR 调试数据",
|
||||||
@@ -238,7 +238,6 @@ def _toggle_debug_panel(self, test_type):
|
|||||||
if existing is not None and existing.winfo_exists():
|
if existing is not None and existing.winfo_exists():
|
||||||
existing.destroy()
|
existing.destroy()
|
||||||
btn.config(text="打开调试面板")
|
btn.config(text="打开调试面板")
|
||||||
self.log_gui.log(f"✓ {wlp}单步调试面板已关闭")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# 创建新窗口
|
# 创建新窗口
|
||||||
@@ -255,38 +254,40 @@ def _toggle_debug_panel(self, test_type):
|
|||||||
# 创建调试面板实例(不要对它调用 pack)
|
# 创建调试面板实例(不要对它调用 pack)
|
||||||
debug_panel_instance = PQDebugPanel(debug_container, self)
|
debug_panel_instance = PQDebugPanel(debug_container, self)
|
||||||
|
|
||||||
self.log_gui.log(f"✓ {wlp}单步调试面板实例已创建")
|
|
||||||
|
|
||||||
# 重新启用调试(如果有数据)
|
# 重新启用调试(如果有数据)
|
||||||
try:
|
try:
|
||||||
selected_items = self.get_selected_test_items()
|
selected_items = self.get_selected_test_items()
|
||||||
dlp = cfg["data_log_prefix"]
|
dlp = cfg["data_log_prefix"]
|
||||||
for item_key, debug_key, (cat, sub), data_label, enable_desc in cfg["data_items"]:
|
results_obj = getattr(self, "results", None)
|
||||||
if item_key not in selected_items:
|
if results_obj is None:
|
||||||
continue
|
self.log_gui.log(f"{dlp} 暂无可用测试结果,面板已打开", level="warning")
|
||||||
data = self.results.get_intermediate_data(cat, sub)
|
else:
|
||||||
if not data:
|
for item_key, debug_key, (cat, sub), data_label, enable_desc in cfg["data_items"]:
|
||||||
if test_type == "screen_module" and item_key == "gamma":
|
if item_key not in selected_items:
|
||||||
self.log_gui.log(" ✗ 没有可用的灰阶数据")
|
continue
|
||||||
continue
|
data = results_obj.get_intermediate_data(cat, sub)
|
||||||
self.log_gui.log(f" → 加载 {len(data)} 个{data_label}数据点")
|
if not data:
|
||||||
debug_panel_instance.enable_debug(test_type, debug_key, data)
|
if test_type == "screen_module" and item_key == "gamma":
|
||||||
self.log_gui.log(f"✓ {dlp} {enable_desc}已重新启用")
|
self.log_gui.log("[Error] 没有可用的灰阶数据", 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:
|
except Exception as e:
|
||||||
self.log_gui.log(f"⚠️ 加载{cfg['failure_data_label']}失败: {str(e)}")
|
self.log_gui.log(f"加载{cfg['failure_data_label']}失败: {str(e)}", level="error")
|
||||||
self.log_gui.log(traceback.format_exc())
|
self.log_gui.log(traceback.format_exc(), level="error")
|
||||||
|
|
||||||
btn.config(text="关闭调试面板")
|
btn.config(text="关闭调试面板")
|
||||||
|
|
||||||
def on_closing():
|
def on_closing():
|
||||||
btn.config(text="打开调试面板")
|
btn.config(text="打开调试面板")
|
||||||
getattr(self, win_attr).destroy()
|
getattr(self, win_attr).destroy()
|
||||||
self.log_gui.log(f"✓ {wlp}单步调试窗口已关闭")
|
self.log_gui.log(f"{wlp}单步调试窗口已关闭", level="success")
|
||||||
|
|
||||||
win.protocol("WM_DELETE_WINDOW", on_closing)
|
win.protocol("WM_DELETE_WINDOW", on_closing)
|
||||||
win.update_idletasks()
|
win.update_idletasks()
|
||||||
|
|
||||||
self.log_gui.log(f"✓ {wlp}单步调试面板已打开(独立窗口)")
|
self.log_gui.log(f"{wlp}单步调试面板已打开(独立窗口)", level="success")
|
||||||
|
|
||||||
|
|
||||||
def toggle_screen_debug_panel(self):
|
def toggle_screen_debug_panel(self):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""
|
"""
|
||||||
PQ 单步调试面板
|
PQ 单步调试面板
|
||||||
支持屏模组、SDR、HDR 三种测试类型的单步调试功能
|
支持屏模组、SDR、HDR 三种测试类型的单步调试功能
|
||||||
"""
|
"""
|
||||||
@@ -34,7 +34,7 @@ class PQDebugPanel:
|
|||||||
# 原始测试数据(用于对比)
|
# 原始测试数据(用于对比)
|
||||||
self.original_data = {}
|
self.original_data = {}
|
||||||
|
|
||||||
# ==================== ✅ 创建主容器并自动 pack ====================
|
# ==================== 创建主容器并自动 pack ====================
|
||||||
self.main_container = ttk.Frame(parent)
|
self.main_container = ttk.Frame(parent)
|
||||||
self.main_container.pack(fill=tk.BOTH, expand=True)
|
self.main_container.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
@@ -600,13 +600,13 @@ class PQDebugPanel:
|
|||||||
|
|
||||||
if test_type == "screen_module":
|
if test_type == "screen_module":
|
||||||
self.screen_frame.pack(fill=tk.BOTH, expand=True)
|
self.screen_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
self.app.log_gui.log("✓ 显示屏模组调试面板")
|
self.app.log_gui.log("显示屏模组调试面板", level="success")
|
||||||
elif test_type == "sdr_movie":
|
elif test_type == "sdr_movie":
|
||||||
self.sdr_frame.pack(fill=tk.BOTH, expand=True)
|
self.sdr_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
self.app.log_gui.log("✓ 显示 SDR 调试面板")
|
self.app.log_gui.log("显示 SDR 调试面板", level="success")
|
||||||
elif test_type == "hdr_movie":
|
elif test_type == "hdr_movie":
|
||||||
self.hdr_frame.pack(fill=tk.BOTH, expand=True)
|
self.hdr_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
self.app.log_gui.log("✓ 显示 HDR 调试面板")
|
self.app.log_gui.log("显示 HDR 调试面板", level="success")
|
||||||
|
|
||||||
# ==================== 启用/禁用控制 ====================
|
# ==================== 启用/禁用控制 ====================
|
||||||
|
|
||||||
@@ -631,39 +631,39 @@ class PQDebugPanel:
|
|||||||
if test_item == "gamma":
|
if test_item == "gamma":
|
||||||
self.screen_gray_combo.config(state="readonly")
|
self.screen_gray_combo.config(state="readonly")
|
||||||
self.screen_test_btn.config(state=tk.NORMAL)
|
self.screen_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ 屏模组 Gamma 单步调试已启用")
|
self.app.log_gui.log("屏模组 Gamma 单步调试已启用", level="success")
|
||||||
elif test_item == "rgb":
|
elif test_item == "rgb":
|
||||||
self.screen_rgb_combo.config(state="readonly")
|
self.screen_rgb_combo.config(state="readonly")
|
||||||
self.screen_rgb_test_btn.config(state=tk.NORMAL)
|
self.screen_rgb_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ 屏模组 RGB 单步调试已启用")
|
self.app.log_gui.log("屏模组 RGB 单步调试已启用", level="success")
|
||||||
|
|
||||||
elif test_type == "sdr_movie":
|
elif test_type == "sdr_movie":
|
||||||
if test_item == "gamma":
|
if test_item == "gamma":
|
||||||
self.sdr_gray_combo.config(state="readonly")
|
self.sdr_gray_combo.config(state="readonly")
|
||||||
self.sdr_gamma_test_btn.config(state=tk.NORMAL)
|
self.sdr_gamma_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ SDR Gamma 单步调试已启用")
|
self.app.log_gui.log("SDR Gamma 单步调试已启用", level="success")
|
||||||
elif test_item == "accuracy":
|
elif test_item == "accuracy":
|
||||||
self.sdr_color_combo.config(state="readonly")
|
self.sdr_color_combo.config(state="readonly")
|
||||||
self.sdr_accuracy_test_btn.config(state=tk.NORMAL)
|
self.sdr_accuracy_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ SDR 色准单步调试已启用")
|
self.app.log_gui.log("SDR 色准单步调试已启用", level="success")
|
||||||
elif test_item == "rgb":
|
elif test_item == "rgb":
|
||||||
self.sdr_rgb_combo.config(state="readonly")
|
self.sdr_rgb_combo.config(state="readonly")
|
||||||
self.sdr_rgb_test_btn.config(state=tk.NORMAL)
|
self.sdr_rgb_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ SDR RGB 单步调试已启用")
|
self.app.log_gui.log("SDR RGB 单步调试已启用", level="success")
|
||||||
|
|
||||||
elif test_type == "hdr_movie":
|
elif test_type == "hdr_movie":
|
||||||
if test_item == "eotf":
|
if test_item == "eotf":
|
||||||
self.hdr_gray_combo.config(state="readonly")
|
self.hdr_gray_combo.config(state="readonly")
|
||||||
self.hdr_eotf_test_btn.config(state=tk.NORMAL)
|
self.hdr_eotf_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ HDR EOTF 单步调试已启用")
|
self.app.log_gui.log("HDR EOTF 单步调试已启用", level="success")
|
||||||
elif test_item == "accuracy":
|
elif test_item == "accuracy":
|
||||||
self.hdr_color_combo.config(state="readonly")
|
self.hdr_color_combo.config(state="readonly")
|
||||||
self.hdr_accuracy_test_btn.config(state=tk.NORMAL)
|
self.hdr_accuracy_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ HDR 色准单步调试已启用")
|
self.app.log_gui.log("HDR 色准单步调试已启用", level="success")
|
||||||
elif test_item == "rgb":
|
elif test_item == "rgb":
|
||||||
self.hdr_rgb_combo.config(state="readonly")
|
self.hdr_rgb_combo.config(state="readonly")
|
||||||
self.hdr_rgb_test_btn.config(state=tk.NORMAL)
|
self.hdr_rgb_test_btn.config(state=tk.NORMAL)
|
||||||
self.app.log_gui.log("✓ HDR RGB 单步调试已启用")
|
self.app.log_gui.log("HDR RGB 单步调试已启用", level="success")
|
||||||
|
|
||||||
def disable_all_debug(self):
|
def disable_all_debug(self):
|
||||||
"""禁用所有单步调试(新测试开始时调用)"""
|
"""禁用所有单步调试(新测试开始时调用)"""
|
||||||
@@ -759,11 +759,11 @@ class PQDebugPanel:
|
|||||||
def _run_single_step_thread(self, test_type, test_item, selected):
|
def _run_single_step_thread(self, test_type, test_item, selected):
|
||||||
"""单步测试线程"""
|
"""单步测试线程"""
|
||||||
try:
|
try:
|
||||||
self.app.log_gui.log("=" * 50)
|
self.app.log_gui.log("=" * 50, level="info")
|
||||||
self.app.log_gui.log(
|
self.app.log_gui.log(
|
||||||
f"开始单步调试: {test_type} - {test_item} - {selected}"
|
f"开始单步调试: {test_type} - {test_item} - {selected}"
|
||||||
)
|
, level="info")
|
||||||
self.app.log_gui.log("=" * 50)
|
self.app.log_gui.log("=" * 50, level="info")
|
||||||
|
|
||||||
# 禁用按钮
|
# 禁用按钮
|
||||||
self._disable_test_button(test_type, test_item)
|
self._disable_test_button(test_type, test_item)
|
||||||
@@ -796,9 +796,9 @@ class PQDebugPanel:
|
|||||||
x, y, lv, X, Y, Z = self.app.ca.readAllDisplay()
|
x, y, lv, X, Y, Z = self.app.ca.readAllDisplay()
|
||||||
|
|
||||||
self.app.log_gui.log(
|
self.app.log_gui.log(
|
||||||
f"✓ 测量完成: x={x:.4f}, y={y:.4f}, lv={lv:.2f}, "
|
f"测量完成: x={x:.4f}, y={y:.4f}, lv={lv:.2f}, "
|
||||||
f"X={X:.4f}, Y={Y:.4f}, Z={Z:.4f}"
|
f"X={X:.4f}, Y={Y:.4f}, Z={Z:.4f}"
|
||||||
)
|
, level="success")
|
||||||
|
|
||||||
# 对比数据
|
# 对比数据
|
||||||
self._compare_and_display(
|
self._compare_and_display(
|
||||||
@@ -809,10 +809,10 @@ class PQDebugPanel:
|
|||||||
self._enable_test_button(test_type, test_item)
|
self._enable_test_button(test_type, test_item)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.log_gui.log(f"❌ 单步测试失败: {str(e)}")
|
self.app.log_gui.log(f"[Error] 单步测试失败: {str(e)}", level="error")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
self.app.log_gui.log(traceback.format_exc())
|
self.app.log_gui.log(traceback.format_exc(), level="error")
|
||||||
self._enable_test_button(test_type, test_item)
|
self._enable_test_button(test_type, test_item)
|
||||||
|
|
||||||
def _setup_signal_format(self, test_type):
|
def _setup_signal_format(self, test_type):
|
||||||
@@ -842,7 +842,7 @@ class PQDebugPanel:
|
|||||||
# 获取原始数据
|
# 获取原始数据
|
||||||
key = f"{test_type}_{test_item}"
|
key = f"{test_type}_{test_item}"
|
||||||
if key not in self.original_data:
|
if key not in self.original_data:
|
||||||
self.app.log_gui.log("⚠️ 未找到原始测试数据")
|
self.app.log_gui.log("未找到原始测试数据", level="error")
|
||||||
return
|
return
|
||||||
|
|
||||||
original_data_list = self.original_data[key]
|
original_data_list = self.original_data[key]
|
||||||
@@ -856,12 +856,12 @@ class PQDebugPanel:
|
|||||||
index = self.get_rgb_index(selected)
|
index = self.get_rgb_index(selected)
|
||||||
|
|
||||||
if index >= len(original_data_list):
|
if index >= len(original_data_list):
|
||||||
self.app.log_gui.log(f"⚠️ 索引超出范围: {index}")
|
self.app.log_gui.log(f"索引超出范围: {index}", level="error")
|
||||||
return
|
return
|
||||||
|
|
||||||
original_data = original_data_list[index]
|
original_data = original_data_list[index]
|
||||||
|
|
||||||
# ==================== ✅ 构建对比数据 ====================
|
# ==================== 构建对比数据 ====================
|
||||||
comparison = {}
|
comparison = {}
|
||||||
|
|
||||||
if test_item == "gamma":
|
if test_item == "gamma":
|
||||||
@@ -1140,57 +1140,57 @@ class PQDebugPanel:
|
|||||||
def _get_delta_e_from_results(self, test_type, color_name):
|
def _get_delta_e_from_results(self, test_type, color_name):
|
||||||
"""从原始测试结果中读取 ΔE 值"""
|
"""从原始测试结果中读取 ΔE 值"""
|
||||||
try:
|
try:
|
||||||
self.app.log_gui.log(f"[读取 ΔE] 开始:")
|
self.app.log_gui.log(f"[读取 ΔE] 开始:", level="info")
|
||||||
self.app.log_gui.log(f" test_type = {test_type}")
|
self.app.log_gui.log(f" test_type = {test_type}", level="info")
|
||||||
self.app.log_gui.log(f" color_name = {color_name}")
|
self.app.log_gui.log(f" color_name = {color_name}", level="info")
|
||||||
|
|
||||||
# ✅ 正确的访问方式:通过 test_items
|
# 正确的访问方式:通过 test_items
|
||||||
if "accuracy" not in self.app.results.test_items:
|
if "accuracy" not in self.app.results.test_items:
|
||||||
self.app.log_gui.log(" ✗ 未找到 accuracy 测试项")
|
self.app.log_gui.log("[Error] 未找到 accuracy 测试项", level="error")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
test_item = self.app.results.test_items["accuracy"]
|
test_item = self.app.results.test_items["accuracy"]
|
||||||
accuracy_result = test_item.final_result
|
accuracy_result = test_item.final_result
|
||||||
|
|
||||||
self.app.log_gui.log(f" accuracy_result = {accuracy_result is not None}")
|
self.app.log_gui.log(f" accuracy_result = {accuracy_result is not None}", level="info")
|
||||||
|
|
||||||
if not accuracy_result:
|
if not accuracy_result:
|
||||||
self.app.log_gui.log(" ✗ accuracy_result 为空")
|
self.app.log_gui.log("[Error] accuracy_result 为空", level="error")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
# 获取色块名称列表和 ΔE 值列表
|
# 获取色块名称列表和 ΔE 值列表
|
||||||
color_patches = accuracy_result.get("color_patches", [])
|
color_patches = accuracy_result.get("color_patches", [])
|
||||||
delta_e_values = accuracy_result.get("delta_e_values", [])
|
delta_e_values = accuracy_result.get("delta_e_values", [])
|
||||||
|
|
||||||
self.app.log_gui.log(f" color_patches 数量: {len(color_patches)}")
|
self.app.log_gui.log(f" color_patches 数量: {len(color_patches)}", level="info")
|
||||||
self.app.log_gui.log(f" delta_e_values 数量: {len(delta_e_values)}")
|
self.app.log_gui.log(f" delta_e_values 数量: {len(delta_e_values)}", level="info")
|
||||||
|
|
||||||
if color_patches:
|
if color_patches:
|
||||||
self.app.log_gui.log(f" 前3个色块: {color_patches[:3]}")
|
self.app.log_gui.log(f" 前3个色块: {color_patches[:3]}", level="info")
|
||||||
if delta_e_values:
|
if delta_e_values:
|
||||||
self.app.log_gui.log(f" 前3个ΔE: {delta_e_values[:3]}")
|
self.app.log_gui.log(f" 前3个ΔE: {delta_e_values[:3]}", level="info")
|
||||||
|
|
||||||
# 查找对应色块的索引
|
# 查找对应色块的索引
|
||||||
try:
|
try:
|
||||||
index = color_patches.index(color_name)
|
index = color_patches.index(color_name)
|
||||||
delta_e = delta_e_values[index]
|
delta_e = delta_e_values[index]
|
||||||
self.app.log_gui.log(
|
self.app.log_gui.log(
|
||||||
f" ✓ 找到 {color_name}: index={index}, ΔE={delta_e:.2f}"
|
f" 找到 {color_name}: index={index}, ΔE={delta_e:.2f}"
|
||||||
)
|
, level="success")
|
||||||
return delta_e
|
return delta_e
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.app.log_gui.log(f" ✗ 未找到色块 '{color_name}'")
|
self.app.log_gui.log(f"[Error] 未找到色块 '{color_name}'", level="error")
|
||||||
self.app.log_gui.log(f" 可用色块: {color_patches}")
|
self.app.log_gui.log(f" 可用色块: {color_patches}", level="info")
|
||||||
return 0.0
|
return 0.0
|
||||||
except IndexError:
|
except IndexError:
|
||||||
self.app.log_gui.log(f" ✗ 索引超出范围: {index}/{len(delta_e_values)}")
|
self.app.log_gui.log(f"[Error] 索引超出范围: {index}/{len(delta_e_values)}", level="error")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.log_gui.log(f"⚠️ 读取 ΔE 失败: {str(e)}")
|
self.app.log_gui.log(f"读取 ΔE 失败: {str(e)}", level="error")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
self.app.log_gui.log(traceback.format_exc())
|
self.app.log_gui.log(traceback.format_exc(), level="error")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
def _calculate_delta_e_for_color(
|
def _calculate_delta_e_for_color(
|
||||||
@@ -1215,5 +1215,5 @@ class PQDebugPanel:
|
|||||||
return delta_e
|
return delta_e
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.log_gui.log(f"⚠️ 计算 ΔE 失败: {str(e)}")
|
self.app.log_gui.log(f"计算 ΔE 失败: {str(e)}", level="error")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|||||||
@@ -1,31 +1,160 @@
|
|||||||
|
import threading
|
||||||
|
from datetime import datetime
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
import ttkbootstrap as ttk
|
import ttkbootstrap as ttk
|
||||||
|
|
||||||
class PQLogGUI(ttk.Frame):
|
class PQLogGUI(ttk.Frame):
|
||||||
|
VALID_LEVELS = {"info", "success", "warning", "error", "debug", "separator", "blank"}
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self._line_count = 0
|
||||||
|
self._max_lines = 1500
|
||||||
self.create_widgets()
|
self.create_widgets()
|
||||||
|
|
||||||
def create_widgets(self):
|
def create_widgets(self):
|
||||||
log_frame = ttk.LabelFrame(self, text="测试日志")
|
log_frame = ttk.LabelFrame(self, text="测试日志")
|
||||||
log_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
log_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
self.log_text = ttk.Text(log_frame, height=8, width=50)
|
toolbar = ttk.Frame(log_frame)
|
||||||
|
toolbar.pack(fill=tk.X, padx=6, pady=(6, 2))
|
||||||
|
|
||||||
|
self.log_summary_var = tk.StringVar(value="0 条日志")
|
||||||
|
ttk.Label(
|
||||||
|
toolbar,
|
||||||
|
textvariable=self.log_summary_var,
|
||||||
|
bootstyle="secondary",
|
||||||
|
).pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
ttk.Button(
|
||||||
|
toolbar,
|
||||||
|
text="清空日志",
|
||||||
|
command=self.clear_log,
|
||||||
|
bootstyle="secondary-outline",
|
||||||
|
width=10,
|
||||||
|
).pack(side=tk.RIGHT)
|
||||||
|
|
||||||
|
text_container = ttk.Frame(log_frame)
|
||||||
|
text_container.pack(fill=tk.BOTH, expand=True, padx=6, pady=(0, 6))
|
||||||
|
|
||||||
|
self.log_text = tk.Text(
|
||||||
|
text_container,
|
||||||
|
height=10,
|
||||||
|
width=50,
|
||||||
|
wrap=tk.WORD,
|
||||||
|
font=("Consolas", 10),
|
||||||
|
bg="#fbfcfe",
|
||||||
|
fg="#1f2937",
|
||||||
|
relief=tk.FLAT,
|
||||||
|
bd=0,
|
||||||
|
padx=10,
|
||||||
|
pady=8,
|
||||||
|
spacing1=2,
|
||||||
|
spacing3=2,
|
||||||
|
insertbackground="#1f2937",
|
||||||
|
)
|
||||||
self.log_text.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
|
self.log_text.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
|
||||||
|
|
||||||
log_scrollbar = ttk.Scrollbar(log_frame, command=self.log_text.yview)
|
log_scrollbar = ttk.Scrollbar(text_container, command=self.log_text.yview)
|
||||||
log_scrollbar.pack(fill=tk.Y, side=tk.RIGHT)
|
log_scrollbar.pack(fill=tk.Y, side=tk.RIGHT)
|
||||||
self.log_text.config(yscrollcommand=log_scrollbar.set)
|
self.log_text.config(yscrollcommand=log_scrollbar.set)
|
||||||
|
|
||||||
|
self._configure_tags()
|
||||||
self.log_text.config(state=tk.DISABLED)
|
self.log_text.config(state=tk.DISABLED)
|
||||||
|
|
||||||
def log(self, message):
|
def log(self, message, level="info"):
|
||||||
|
if threading.current_thread() is not threading.main_thread():
|
||||||
|
self.after(0, self.log, message, level)
|
||||||
|
return
|
||||||
|
|
||||||
|
text = "" if message is None else str(message)
|
||||||
|
normalized_level = self._normalize_level(level, text)
|
||||||
self.log_text.config(state=tk.NORMAL)
|
self.log_text.config(state=tk.NORMAL)
|
||||||
self.log_text.insert(tk.END, message + "\n")
|
self._append_message(text, normalized_level)
|
||||||
self.log_text.see(tk.END)
|
self.log_text.see(tk.END)
|
||||||
self.log_text.config(state=tk.DISABLED)
|
self.log_text.config(state=tk.DISABLED)
|
||||||
|
|
||||||
def clear_log(self):
|
def clear_log(self):
|
||||||
|
if threading.current_thread() is not threading.main_thread():
|
||||||
|
self.after(0, self.clear_log)
|
||||||
|
return
|
||||||
|
|
||||||
self.log_text.config(state=tk.NORMAL)
|
self.log_text.config(state=tk.NORMAL)
|
||||||
self.log_text.delete(1.0, tk.END)
|
self.log_text.delete(1.0, tk.END)
|
||||||
self.log_text.config(state=tk.DISABLED)
|
self.log_text.config(state=tk.DISABLED)
|
||||||
|
self._line_count = 0
|
||||||
|
self._update_summary()
|
||||||
|
|
||||||
|
def _configure_tags(self):
|
||||||
|
self.log_text.tag_configure("timestamp", foreground="#6b7280")
|
||||||
|
self.log_text.tag_configure("level_info", foreground="#2563eb")
|
||||||
|
self.log_text.tag_configure("level_success", foreground="#0f766e")
|
||||||
|
self.log_text.tag_configure("level_warning", foreground="#b45309")
|
||||||
|
self.log_text.tag_configure("level_error", foreground="#b91c1c")
|
||||||
|
self.log_text.tag_configure("level_debug", foreground="#7c3aed")
|
||||||
|
self.log_text.tag_configure("message", foreground="#1f2937")
|
||||||
|
self.log_text.tag_configure("message_success", foreground="#0f766e")
|
||||||
|
self.log_text.tag_configure("message_warning", foreground="#b45309")
|
||||||
|
self.log_text.tag_configure("message_error", foreground="#991b1b")
|
||||||
|
self.log_text.tag_configure("message_debug", foreground="#6d28d9")
|
||||||
|
self.log_text.tag_configure("separator", foreground="#94a3b8")
|
||||||
|
self.log_text.tag_configure("traceback", foreground="#7f1d1d")
|
||||||
|
self.log_text.tag_configure("blank", spacing1=4, spacing3=4)
|
||||||
|
|
||||||
|
def _append_message(self, message, level):
|
||||||
|
lines = message.splitlines() or [""]
|
||||||
|
for line in lines:
|
||||||
|
self._append_line(line, level)
|
||||||
|
self._trim_excess_lines()
|
||||||
|
self._update_summary()
|
||||||
|
|
||||||
|
def _append_line(self, line, level):
|
||||||
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||||
|
rendered = "" if line is None else str(line).strip()
|
||||||
|
|
||||||
|
if level == "blank" or not rendered:
|
||||||
|
self.log_text.insert(tk.END, "\n", ("blank",))
|
||||||
|
self._line_count += 1
|
||||||
|
return
|
||||||
|
|
||||||
|
if level == "separator":
|
||||||
|
self.log_text.insert(tk.END, f"[{timestamp}] ", ("timestamp",))
|
||||||
|
self.log_text.insert(tk.END, "[SECTION] ", ("level_info",))
|
||||||
|
self.log_text.insert(tk.END, rendered + "\n", ("separator",))
|
||||||
|
self._line_count += 1
|
||||||
|
return
|
||||||
|
|
||||||
|
level_tag = f"level_{level}"
|
||||||
|
level_label = level.upper().ljust(7)
|
||||||
|
if level == "error" and rendered.startswith("Traceback"):
|
||||||
|
message_tag = "traceback"
|
||||||
|
elif level in {"success", "warning", "error", "debug"}:
|
||||||
|
message_tag = f"message_{level}"
|
||||||
|
else:
|
||||||
|
message_tag = "message"
|
||||||
|
|
||||||
|
self.log_text.insert(tk.END, f"[{timestamp}] ", ("timestamp",))
|
||||||
|
self.log_text.insert(tk.END, f"[{level_label}] ", (level_tag,))
|
||||||
|
self.log_text.insert(tk.END, rendered + "\n", (message_tag,))
|
||||||
|
self._line_count += 1
|
||||||
|
|
||||||
|
def _normalize_level(self, level, message):
|
||||||
|
normalized = "info" if level is None else str(level).strip().lower()
|
||||||
|
if normalized not in self.VALID_LEVELS:
|
||||||
|
normalized = "info"
|
||||||
|
|
||||||
|
if normalized == "info" and (message is None or str(message).strip() == ""):
|
||||||
|
return "blank"
|
||||||
|
|
||||||
|
return normalized
|
||||||
|
|
||||||
|
def _trim_excess_lines(self):
|
||||||
|
overflow = self._line_count - self._max_lines
|
||||||
|
if overflow <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.log_text.delete("1.0", f"{overflow + 1}.0")
|
||||||
|
self._line_count = self._max_lines
|
||||||
|
|
||||||
|
def _update_summary(self):
|
||||||
|
self.log_summary_var.set(f"{self._line_count} 条日志")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import ttkbootstrap as ttk
|
import ttkbootstrap as ttk
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import messagebox, filedialog
|
from tkinter import messagebox, filedialog
|
||||||
import sys
|
import sys
|
||||||
@@ -246,7 +246,7 @@ class PQAutomationApp:
|
|||||||
self.change_test_type("screen_module")
|
self.change_test_type("screen_module")
|
||||||
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)}", level="error")
|
||||||
|
|
||||||
get_config_path = _cfg_get_config_path
|
get_config_path = _cfg_get_config_path
|
||||||
load_pq_config = _cfg_load_pq_config
|
load_pq_config = _cfg_load_pq_config
|
||||||
@@ -360,7 +360,7 @@ class PQAutomationApp:
|
|||||||
if not swallow_errors:
|
if not swallow_errors:
|
||||||
raise
|
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)}", level="error")
|
||||||
|
|
||||||
def _save_cct_params_before_test_type_switch(self):
|
def _save_cct_params_before_test_type_switch(self):
|
||||||
"""切换测试类型前,按当前类型保存色度参数。"""
|
"""切换测试类型前,按当前类型保存色度参数。"""
|
||||||
@@ -376,10 +376,10 @@ class PQAutomationApp:
|
|||||||
if combo is not None:
|
if combo is not None:
|
||||||
combo.configure(state=state)
|
combo.configure(state=state)
|
||||||
if success_msg and hasattr(self, "log_gui"):
|
if success_msg and hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(success_msg)
|
self.log_gui.log(success_msg, level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(f"{error_prefix}: {str(e)}")
|
self.log_gui.log(f"{error_prefix}: {str(e)}", level="error")
|
||||||
|
|
||||||
def _hide_recalc_buttons(self, include_gamut=False):
|
def _hide_recalc_buttons(self, include_gamut=False):
|
||||||
"""隐藏重新计算按钮。include_gamut=True 时同时隐藏色域重算按钮。"""
|
"""隐藏重新计算按钮。include_gamut=True 时同时隐藏色域重算按钮。"""
|
||||||
@@ -403,15 +403,15 @@ class PQAutomationApp:
|
|||||||
if hasattr(self, "debug_panel"):
|
if hasattr(self, "debug_panel"):
|
||||||
try:
|
try:
|
||||||
self.debug_panel.disable_all_debug()
|
self.debug_panel.disable_all_debug()
|
||||||
self.log_gui.log("✓ 单步调试已禁用")
|
self.log_gui.log("单步调试已禁用", level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 禁用单步调试失败: {str(e)}")
|
self.log_gui.log(f"[Error] 禁用单步调试失败: {str(e)}", level="error")
|
||||||
if hasattr(self, "debug_container"):
|
if hasattr(self, "debug_container"):
|
||||||
try:
|
try:
|
||||||
self.debug_container.pack_forget()
|
self.debug_container.pack_forget()
|
||||||
self.log_gui.log("✓ 单步调试面板已隐藏")
|
self.log_gui.log("单步调试面板已隐藏", level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 隐藏调试面板失败: {str(e)}")
|
self.log_gui.log(f"[Error] 隐藏调试面板失败: {str(e)}", level="error")
|
||||||
|
|
||||||
def _set_config_panel_btn_state(self, state):
|
def _set_config_panel_btn_state(self, state):
|
||||||
"""统一设置配置面板按钮状态(disabled/normal)。"""
|
"""统一设置配置面板按钮状态(disabled/normal)。"""
|
||||||
@@ -428,13 +428,13 @@ class PQAutomationApp:
|
|||||||
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}", level="error")
|
||||||
|
|
||||||
def _switch_signal_format_tabs(self, test_type):
|
def _switch_signal_format_tabs(self, test_type):
|
||||||
"""切换信号格式 Tab 到目标测试类型。"""
|
"""切换信号格式 Tab 到目标测试类型。"""
|
||||||
if not hasattr(self, "signal_tabs"):
|
if not hasattr(self, "signal_tabs"):
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log("[Error] signal_tabs 尚未创建")
|
self.log_gui.log("[Error] signal_tabs 尚未创建", level="error")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -465,10 +465,10 @@ class PQAutomationApp:
|
|||||||
|
|
||||||
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]} 信号格式", level="success")
|
||||||
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)}", level="error")
|
||||||
|
|
||||||
def _switch_chart_tabs_by_test_type(self, test_type):
|
def _switch_chart_tabs_by_test_type(self, test_type):
|
||||||
"""按测试类型切换 Gamma/EOTF 与客户模板结果 Tab。"""
|
"""按测试类型切换 Gamma/EOTF 与客户模板结果 Tab。"""
|
||||||
@@ -485,23 +485,23 @@ class PQAutomationApp:
|
|||||||
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", level="success")
|
||||||
|
|
||||||
if eotf_tab_id not in current_tabs:
|
if eotf_tab_id not in current_tabs:
|
||||||
self.chart_notebook.insert(1, self.eotf_chart_frame, text="EOTF 曲线")
|
self.chart_notebook.insert(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", level="success")
|
||||||
else:
|
else:
|
||||||
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", level="success")
|
||||||
|
|
||||||
if gamma_tab_id not in current_tabs:
|
if gamma_tab_id not in current_tabs:
|
||||||
self.chart_notebook.insert(1, self.gamma_chart_frame, text="Gamma 曲线")
|
self.chart_notebook.insert(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", level="success")
|
||||||
|
|
||||||
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())
|
||||||
@@ -510,17 +510,17 @@ class PQAutomationApp:
|
|||||||
if custom_tab_id not in current_tabs:
|
if custom_tab_id not in current_tabs:
|
||||||
self.chart_notebook.add(self.custom_template_tab_frame, text="客户模板结果显示")
|
self.chart_notebook.add(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", level="success")
|
||||||
else:
|
else:
|
||||||
if custom_tab_id in current_tabs:
|
if custom_tab_id in current_tabs:
|
||||||
self.chart_notebook.forget(self.custom_template_tab_frame)
|
self.chart_notebook.forget(self.custom_template_tab_frame)
|
||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log("✓ 已隐藏客户模板结果 Tab")
|
self.log_gui.log("已隐藏客户模板结果 Tab", level="success")
|
||||||
|
|
||||||
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)}", level="error")
|
||||||
|
|
||||||
def change_test_type(self, test_type):
|
def change_test_type(self, test_type):
|
||||||
"""切换测试类型"""
|
"""切换测试类型"""
|
||||||
@@ -637,9 +637,9 @@ class PQAutomationApp:
|
|||||||
def _signal_stop_and_update_ui(self):
|
def _signal_stop_and_update_ui(self):
|
||||||
"""设置停止标志并立即更新 UI 以反馈给用户。"""
|
"""设置停止标志并立即更新 UI 以反馈给用户。"""
|
||||||
self.testing = False
|
self.testing = False
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
self.log_gui.log("正在停止测试...")
|
self.log_gui.log("正在停止测试...", level="info")
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
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()
|
||||||
@@ -648,24 +648,24 @@ class PQAutomationApp:
|
|||||||
"""等待测试线程结束,最多 timeout_seconds 秒,同时保持 UI 响应。"""
|
"""等待测试线程结束,最多 timeout_seconds 秒,同时保持 UI 响应。"""
|
||||||
if not (self.test_thread and self.test_thread.is_alive()):
|
if not (self.test_thread and self.test_thread.is_alive()):
|
||||||
return
|
return
|
||||||
self.log_gui.log("等待测试线程结束...")
|
self.log_gui.log("等待测试线程结束...", level="info")
|
||||||
for _ in range(int(timeout_seconds * 10)):
|
for _ in range(int(timeout_seconds * 10)):
|
||||||
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("[Error] 测试线程未能正常结束,将在后台继续等待")
|
self.log_gui.log("[Error] 测试线程未能正常结束,将在后台继续等待", level="error")
|
||||||
else:
|
else:
|
||||||
self.log_gui.log("✓ 测试线程已结束")
|
self.log_gui.log("测试线程已结束", level="success")
|
||||||
|
|
||||||
def _clear_test_data(self):
|
def _clear_test_data(self):
|
||||||
"""清空测试结果对象与中间数据缓存。"""
|
"""清空测试结果对象与中间数据缓存。"""
|
||||||
try:
|
try:
|
||||||
self.log_gui.log("清理测试数据...")
|
self.log_gui.log("清理测试数据...", level="info")
|
||||||
if hasattr(self, "results"):
|
if hasattr(self, "results"):
|
||||||
self.results = None
|
self.results = None
|
||||||
self.log_gui.log(" ✓ 测试结果对象已清空")
|
self.log_gui.log(" 测试结果对象已清空", level="success")
|
||||||
for attr in [
|
for attr in [
|
||||||
"gamut_results",
|
"gamut_results",
|
||||||
"gamma_results",
|
"gamma_results",
|
||||||
@@ -675,28 +675,28 @@ 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(" 所有中间数据已清空", level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 清理数据时出错: {str(e)}")
|
self.log_gui.log(f"[Error] 清理数据时出错: {str(e)}", level="error")
|
||||||
|
|
||||||
def _clear_charts_and_tables(self):
|
def _clear_charts_and_tables(self):
|
||||||
"""清空图表与客户模板结果表格,并跳转到色域图 Tab。"""
|
"""清空图表与客户模板结果表格,并跳转到色域图 Tab。"""
|
||||||
try:
|
try:
|
||||||
self.clear_chart()
|
self.clear_chart()
|
||||||
self.log_gui.log("✓ 图表已清空")
|
self.log_gui.log("图表已清空", level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 清空图表时出错: {str(e)}")
|
self.log_gui.log(f"[Error] 清空图表时出错: {str(e)}", level="error")
|
||||||
try:
|
try:
|
||||||
self.clear_custom_template_results()
|
self.clear_custom_template_results()
|
||||||
self.log_gui.log("✓ 客户模板结果表格已清空")
|
self.log_gui.log("客户模板结果表格已清空", level="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 清空客户模板结果表格失败: {str(e)}")
|
self.log_gui.log(f"[Error] 清空客户模板结果表格失败: {str(e)}", level="error")
|
||||||
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()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 跳转到色域图失败: {str(e)}")
|
self.log_gui.log(f"[Error] 跳转到色域图失败: {str(e)}", level="error")
|
||||||
|
|
||||||
def _restore_ui_after_stop(self):
|
def _restore_ui_after_stop(self):
|
||||||
"""恢复主按钮与状态栏到非测试态。"""
|
"""恢复主按钮与状态栏到非测试态。"""
|
||||||
@@ -718,16 +718,16 @@ class PQAutomationApp:
|
|||||||
self._restore_ui_after_stop()
|
self._restore_ui_after_stop()
|
||||||
self._set_gamut_combos_state(
|
self._set_gamut_combos_state(
|
||||||
"disabled",
|
"disabled",
|
||||||
success_msg="✓ 色域参考标准已禁用",
|
success_msg="色域参考标准已禁用",
|
||||||
error_prefix="禁用色域参考标准失败",
|
error_prefix="禁用色域参考标准失败",
|
||||||
)
|
)
|
||||||
hidden = self._hide_recalc_buttons(include_gamut=True)
|
hidden = self._hide_recalc_buttons(include_gamut=True)
|
||||||
if hidden > 0:
|
if hidden > 0:
|
||||||
self.log_gui.log(f"✓ 已隐藏 {hidden} 个重新计算按钮")
|
self.log_gui.log(f"已隐藏 {hidden} 个重新计算按钮", level="success")
|
||||||
self._disable_debug_panel()
|
self._disable_debug_panel()
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
self.log_gui.log("✓ 测试已停止,所有数据已清空")
|
self.log_gui.log("测试已停止,所有数据已清空", level="success")
|
||||||
self.log_gui.log("=" * 50)
|
self.log_gui.log("=" * 50, level="separator")
|
||||||
messagebox.showinfo(
|
messagebox.showinfo(
|
||||||
"测试已停止",
|
"测试已停止",
|
||||||
"测试已停止,本次测试数据已清空。\n\n可以重新开始新的测试。",
|
"测试已停止,本次测试数据已清空。\n\n可以重新开始新的测试。",
|
||||||
@@ -760,8 +760,8 @@ class PQAutomationApp:
|
|||||||
selected_items = self.get_selected_test_items()
|
selected_items = self.get_selected_test_items()
|
||||||
log = self.log_gui.log
|
log = self.log_gui.log
|
||||||
|
|
||||||
log(f"保存测试类型: {current_test_type}")
|
log(f"保存测试类型: {current_test_type}", level="info")
|
||||||
log(f"已选测试项: {selected_items}")
|
log(f"已选测试项: {selected_items}", level="info")
|
||||||
|
|
||||||
# 1) 图片
|
# 1) 图片
|
||||||
_save_result_images_impl(
|
_save_result_images_impl(
|
||||||
@@ -779,16 +779,16 @@ class PQAutomationApp:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 3) 成功提示
|
# 3) 成功提示
|
||||||
log("=" * 50)
|
log("=" * 50, level="separator")
|
||||||
log(f"测试结果已保存到目录: {result_dir}")
|
log(f"测试结果已保存到目录: {result_dir}", level="success")
|
||||||
log("=" * 50)
|
log("=" * 50, level="separator")
|
||||||
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"[Error] 保存测试结果失败: {str(e)}")
|
self.log_gui.log(f"[Error] 保存测试结果失败: {str(e)}", level="error")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
self.log_gui.log(traceback.format_exc())
|
self.log_gui.log(traceback.format_exc(), level="error")
|
||||||
messagebox.showerror("错误", f"保存测试结果失败: {str(e)}")
|
messagebox.showerror("错误", f"保存测试结果失败: {str(e)}")
|
||||||
|
|
||||||
new_pq_results = _run_new_pq_results
|
new_pq_results = _run_new_pq_results
|
||||||
@@ -862,7 +862,7 @@ class PQAutomationApp:
|
|||||||
self.save_pq_config()
|
self.save_pq_config()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_gui.log(f"[Error] 更新配置失败: {str(e)}")
|
self.log_gui.log(f"[Error] 更新配置失败: {str(e)}", level="error")
|
||||||
|
|
||||||
def update_config_and_tabs(self):
|
def update_config_and_tabs(self):
|
||||||
"""更新配置并同步Tab状态"""
|
"""更新配置并同步Tab状态"""
|
||||||
@@ -879,7 +879,7 @@ class PQAutomationApp:
|
|||||||
def on_closing(self):
|
def on_closing(self):
|
||||||
"""窗口关闭时的处理"""
|
"""窗口关闭时的处理"""
|
||||||
try:
|
try:
|
||||||
# ✅ 检查是否清理了配置
|
# 检查是否清理了配置
|
||||||
if not self.config_cleared:
|
if not self.config_cleared:
|
||||||
# 保存配置
|
# 保存配置
|
||||||
self.save_pq_config()
|
self.save_pq_config()
|
||||||
|
|||||||
Reference in New Issue
Block a user