Files
pqAutomationApp/app/views/chart_frame.py
2026-04-20 11:48:38 +08:00

815 lines
26 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""图表框架相关逻辑Step 3 重构)。
从 pqAutomationApp.PQAutomationApp 中搬迁而来。每个函数第一行 `self = app`
以保留原有 `self.xxx` 属性访问不变。
"""
import tkinter as tk
import ttkbootstrap as ttk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from app.views.pq_debug_panel import PQDebugPanel
def init_gamut_chart(self):
"""初始化色域图表 - 手动设置subplot位置完全避免重叠"""
container = ttk.Frame(self.gamut_chart_frame)
container.pack(expand=True, fill=tk.BOTH)
self.gamut_fig = plt.Figure(figsize=(14, 6), dpi=100)
self.gamut_canvas = FigureCanvasTkAgg(self.gamut_fig, master=container)
canvas_widget = self.gamut_canvas.get_tk_widget()
canvas_widget.pack(expand=True, fill=tk.BOTH)
# ✅ 恢复原来的大尺寸0.84 高度
self.gamut_ax_xy = self.gamut_fig.add_axes(
[0.02, 0.08, 0.46, 0.84]
) # ← 改回 0.84
self.gamut_ax_uv = self.gamut_fig.add_axes(
[0.52, 0.08, 0.46, 0.84]
) # ← 改回 0.84
# 初始化XY图
self.gamut_ax_xy.set_xlim(0, 600)
self.gamut_ax_xy.set_ylim(600, 0)
self.gamut_ax_xy.axis("off")
self.gamut_ax_xy.set_clip_on(False)
# 初始化UV图
self.gamut_ax_uv.set_xlim(0, 600)
self.gamut_ax_uv.set_ylim(600, 0)
self.gamut_ax_uv.axis("off")
self.gamut_ax_uv.set_clip_on(False)
# 调整标题位置y=0.98
self.gamut_fig.suptitle("色域测试", fontsize=12, y=0.98)
self.gamut_canvas.draw()
def init_gamma_chart(self):
"""初始化Gamma曲线图表 - 左侧曲线 + 右侧表格(✅ 4列 + 通用说明)"""
container = ttk.Frame(self.gamma_chart_frame)
container.pack(expand=True, fill=tk.BOTH)
self.gamma_fig = plt.Figure(figsize=(12, 6), dpi=100, constrained_layout=False)
self.gamma_canvas = FigureCanvasTkAgg(self.gamma_fig, master=container)
canvas_widget = self.gamma_canvas.get_tk_widget()
canvas_widget.pack(expand=True, fill=tk.BOTH)
# 左侧Gamma 曲线
self.gamma_ax = self.gamma_fig.add_axes([0.08, 0.12, 0.50, 0.78])
self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.gamma_ax.set_ylabel("L_bar", fontsize=10)
self.gamma_ax.set_xlim(0, 105)
self.gamma_ax.set_ylim(0, 1.1)
self.gamma_ax.grid(True, linestyle="--", alpha=0.3)
self.gamma_ax.tick_params(labelsize=9)
# 左侧提示(通用说明,不显示具体 Gamma 值)
self.gamma_ax.text(
0.5,
0.5,
"等待测试数据...\n\n"
"将显示:\n"
"• 实测曲线 (蓝色)\n"
"• 理想 Gamma 曲线 (红色)\n\n"
"Gamma 值由测试配置决定",
ha="center",
va="center",
fontsize=10,
color="gray",
transform=self.gamma_ax.transAxes,
bbox=dict(
boxstyle="round,pad=1", facecolor="white", edgecolor="gray", alpha=0.8
),
)
# 右侧:数据表格
self.gamma_table_ax = self.gamma_fig.add_axes([0.62, 0.12, 0.35, 0.78])
self.gamma_table_ax.axis("off")
# 4列表格数据
table_data = [
["灰阶", "实测亮度\n(cd/m²)", "L_bar\n(计算)", "Gamma"],
["0%", "--", "--", "--"],
["10%", "--", "--", "--"],
["20%", "--", "--", "--"],
["30%", "--", "--", "--"],
["40%", "--", "--", "--"],
["50%", "--", "--", "--"],
["60%", "--", "--", "--"],
["70%", "--", "--", "--"],
["80%", "--", "--", "--"],
["90%", "--", "--", "--"],
["100%", "--", "--", "--"],
]
table = self.gamma_table_ax.table(
cellText=table_data,
cellLoc="center",
loc="center",
colWidths=[0.18, 0.28, 0.27, 0.27], # ← 4列宽度
)
table.auto_set_font_size(False)
table.set_fontsize(7.5)
table.scale(1, 1.5)
# 表头样式
for i in range(4):
cell = table[(0, i)]
cell.set_facecolor("#4472C4")
cell.set_text_props(weight="bold", color="white", fontsize=7)
# 数据行交替颜色
for i in range(1, len(table_data)):
for j in range(4):
cell = table[(i, j)]
if i % 2 == 0:
cell.set_facecolor("#E7E6E6")
else:
cell.set_facecolor("#FFFFFF")
# 底部说明
self.gamma_table_ax.text(
0.5,
0.02,
"表格说明:\n"
"• 实测亮度: 色度计测量值 (cd/m²)\n"
"• L_bar: 归一化亮度 (0-1)\n"
"• Gamma: 实际 Gamma 值",
ha="center",
va="bottom",
fontsize=7,
color="gray",
transform=self.gamma_table_ax.transAxes,
bbox=dict(
boxstyle="round,pad=0.5",
facecolor="lightyellow",
edgecolor="gray",
alpha=0.8,
),
)
self.gamma_fig.suptitle("Gamma曲线 + 数据表格", fontsize=12, y=0.98)
self.gamma_canvas.draw()
def init_eotf_chart(self):
"""初始化 EOTF 曲线图表HDR 专用)- 左侧曲线 + 右侧表格(✅ 4列"""
container = ttk.Frame(self.eotf_chart_frame)
container.pack(expand=True, fill=tk.BOTH)
self.eotf_fig = plt.Figure(figsize=(12, 6), dpi=100, constrained_layout=False)
self.eotf_canvas = FigureCanvasTkAgg(self.eotf_fig, master=container)
canvas_widget = self.eotf_canvas.get_tk_widget()
canvas_widget.pack(expand=True, fill=tk.BOTH)
# 左侧EOTF 曲线
self.eotf_ax = self.eotf_fig.add_axes([0.08, 0.12, 0.50, 0.78])
self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.eotf_ax.set_ylabel("L_bar (归一化亮度)", fontsize=10)
self.eotf_ax.set_xlim(0, 105)
self.eotf_ax.set_ylim(0, 1.1)
self.eotf_ax.grid(True, linestyle="--", alpha=0.3)
self.eotf_ax.tick_params(labelsize=9)
# 左侧提示
self.eotf_ax.text(
0.5,
0.5,
"等待测试数据...\n\n将显示:\n• 实测 EOTF 曲线 (蓝色)\n• 理想 PQ 曲线 (红色)",
ha="center",
va="center",
fontsize=11,
color="gray",
transform=self.eotf_ax.transAxes,
bbox=dict(
boxstyle="round,pad=1", facecolor="white", edgecolor="gray", alpha=0.8
),
)
# 右侧:数据表格
self.eotf_table_ax = self.eotf_fig.add_axes([0.62, 0.12, 0.35, 0.78])
self.eotf_table_ax.axis("off")
# 4列表格数据
table_data = [
["灰阶", "实测亮度\n(cd/m²)", "L_bar\n(计算)", "EOTF γ"],
["0%", "--", "--", "--"],
["10%", "--", "--", "--"],
["20%", "--", "--", "--"],
["30%", "--", "--", "--"],
["40%", "--", "--", "--"],
["50%", "--", "--", "--"],
["60%", "--", "--", "--"],
["70%", "--", "--", "--"],
["80%", "--", "--", "--"],
["90%", "--", "--", "--"],
["100%", "--", "--", "--"],
]
table = self.eotf_table_ax.table(
cellText=table_data,
cellLoc="center",
loc="center",
colWidths=[0.18, 0.28, 0.27, 0.27],
)
table.auto_set_font_size(False)
table.set_fontsize(7.5)
table.scale(1, 1.5)
# 表头样式
for i in range(4):
cell = table[(0, i)]
cell.set_facecolor("#4472C4")
cell.set_text_props(weight="bold", color="white", fontsize=7)
# 数据行交替颜色
for i in range(1, len(table_data)):
for j in range(4):
cell = table[(i, j)]
if i % 2 == 0:
cell.set_facecolor("#E7E6E6")
else:
cell.set_facecolor("#FFFFFF")
# 底部说明
self.eotf_table_ax.text(
0.5,
0.02,
"表格说明:\n"
"• 实测亮度: 色度计测量值 (cd/m²)\n"
"• L_bar: 归一化亮度 (0-1)\n"
"• EOTF γ: HDR 实际 Gamma 值",
ha="center",
va="bottom",
fontsize=7,
color="gray",
transform=self.eotf_table_ax.transAxes,
bbox=dict(
boxstyle="round,pad=0.5",
facecolor="lightyellow",
edgecolor="gray",
alpha=0.8,
),
)
self.eotf_fig.suptitle("EOTF 曲线 + 数据表格", fontsize=12, y=0.98)
self.eotf_canvas.draw()
def init_cct_chart(self):
"""初始化色度坐标图表 - 正向横坐标,标题居中最上方"""
container = ttk.Frame(self.cct_chart_frame)
container.pack(expand=True)
self.cct_fig = plt.Figure(figsize=(8, 6), dpi=100, tight_layout=False)
self.cct_canvas = FigureCanvasTkAgg(self.cct_fig, master=container)
canvas_widget = self.cct_canvas.get_tk_widget()
canvas_widget.pack()
canvas_widget.config(width=800, height=600)
canvas_widget.pack_propagate(False)
self.cct_ax1 = self.cct_fig.add_subplot(211)
self.cct_ax2 = self.cct_fig.add_subplot(212)
# 上图x coordinates
self.cct_ax1.set_xlabel("灰阶 (%)", fontsize=9)
self.cct_ax1.set_ylabel("CIE x", fontsize=9)
self.cct_ax1.set_xlim(0, 105)
self.cct_ax1.set_ylim(0.25, 0.35)
self.cct_ax1.grid(True, linestyle="--", alpha=0.3)
self.cct_ax1.tick_params(labelsize=8)
# 下图y coordinates
self.cct_ax2.set_xlabel("灰阶 (%)", fontsize=9)
self.cct_ax2.set_ylabel("CIE y", fontsize=9)
self.cct_ax2.set_xlim(0, 105)
self.cct_ax2.set_ylim(0.25, 0.35)
self.cct_ax2.grid(True, linestyle="--", alpha=0.3)
self.cct_ax2.tick_params(labelsize=8)
# 调整标题位置y=0.985(比色域/Gamma略高
self.cct_fig.suptitle("色度一致性测试", fontsize=12, y=0.985)
self.cct_fig.subplots_adjust(
left=0.12,
right=0.88,
top=0.90,
bottom=0.08,
hspace=0.25,
)
self.cct_canvas.draw()
def init_contrast_chart(self):
"""初始化对比度图表 - 固定大小,居中显示"""
container = ttk.Frame(self.contrast_chart_frame)
container.pack(expand=True)
self.contrast_fig = plt.Figure(
figsize=(6, 6),
dpi=100,
tight_layout=False,
)
self.contrast_canvas = FigureCanvasTkAgg(self.contrast_fig, master=container)
canvas_widget = self.contrast_canvas.get_tk_widget()
canvas_widget.pack()
canvas_widget.config(width=600, height=600)
canvas_widget.pack_propagate(False)
self.contrast_ax = self.contrast_fig.add_subplot(111)
self.contrast_ax.set_xlim(0, 1)
self.contrast_ax.set_ylim(0, 1)
self.contrast_ax.axis("off")
# 调整标题位置y=0.985
self.contrast_fig.suptitle("对比度测试", fontsize=12, y=0.985)
self.contrast_fig.subplots_adjust(
left=0.02,
right=0.98,
top=0.90,
bottom=0.02,
)
self.contrast_canvas.draw()
def init_accuracy_chart(self):
"""初始化色准图表 - 固定大小,居中显示"""
container = ttk.Frame(self.accuracy_chart_frame)
container.pack(expand=True)
self.accuracy_fig = plt.Figure(
figsize=(10, 6),
dpi=100,
tight_layout=False,
)
self.accuracy_canvas = FigureCanvasTkAgg(self.accuracy_fig, master=container)
canvas_widget = self.accuracy_canvas.get_tk_widget()
canvas_widget.pack()
canvas_widget.config(width=1000, height=600)
canvas_widget.pack_propagate(False)
self.accuracy_ax = self.accuracy_fig.add_subplot(111)
self.accuracy_ax.set_xlim(0, 1)
self.accuracy_ax.set_ylim(0, 1)
self.accuracy_ax.axis("off")
# 调整标题位置
self.accuracy_fig.suptitle("色准测试", fontsize=12, y=0.985)
self.accuracy_fig.subplots_adjust(
left=0.05,
right=0.95,
top=0.90,
bottom=0.05,
)
self.accuracy_canvas.draw()
def clear_chart(self):
"""清空所有图表"""
# ========== 1. 清空色域图表 ==========
if hasattr(self, "gamut_ax_xy") and hasattr(self, "gamut_ax_uv"):
# 清空XY图
self.gamut_ax_xy.clear()
self.gamut_ax_xy.set_xlim(0, 600)
self.gamut_ax_xy.set_ylim(600, 0)
self.gamut_ax_xy.axis("off")
self.gamut_ax_xy.set_clip_on(False)
# 清空UV图
self.gamut_ax_uv.clear()
self.gamut_ax_uv.set_xlim(0, 600)
self.gamut_ax_uv.set_ylim(600, 0)
self.gamut_ax_uv.axis("off")
self.gamut_ax_uv.set_clip_on(False)
self.gamut_fig.suptitle("色域测试", fontsize=12, y=0.98)
self.gamut_canvas.draw()
# ========== 2. 清空Gamma图表4列 + 通用说明)==========
if hasattr(self, "gamma_ax") and hasattr(self, "gamma_table_ax"):
# 清空左侧曲线
self.gamma_ax.clear()
self.gamma_ax.set_xlim(0, 105)
self.gamma_ax.set_ylim(0, 1.1)
self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.gamma_ax.set_ylabel("L_bar", fontsize=10)
self.gamma_ax.grid(True, linestyle="--", alpha=0.3)
self.gamma_ax.tick_params(labelsize=9)
# 左侧提示
self.gamma_ax.text(
0.5,
0.5,
"等待测试数据...\n\n"
"将显示:\n"
"• 实测曲线 (蓝色)\n"
"• 理想 Gamma 曲线 (红色)\n\n"
"Gamma 值由测试配置决定",
ha="center",
va="center",
fontsize=10,
color="gray",
transform=self.gamma_ax.transAxes,
bbox=dict(
boxstyle="round,pad=1",
facecolor="white",
edgecolor="gray",
alpha=0.8,
),
)
# 清空右侧表格
self.gamma_table_ax.clear()
self.gamma_table_ax.axis("off")
# 4列表格
table_data = [
["灰阶", "实测亮度\n(cd/m²)", "L_bar\n(计算)", "Gamma"],
["0%", "--", "--", "--"],
["10%", "--", "--", "--"],
["20%", "--", "--", "--"],
["30%", "--", "--", "--"],
["40%", "--", "--", "--"],
["50%", "--", "--", "--"],
["60%", "--", "--", "--"],
["70%", "--", "--", "--"],
["80%", "--", "--", "--"],
["90%", "--", "--", "--"],
["100%", "--", "--", "--"],
]
table = self.gamma_table_ax.table(
cellText=table_data,
cellLoc="center",
loc="center",
colWidths=[0.18, 0.28, 0.27, 0.27],
)
table.auto_set_font_size(False)
table.set_fontsize(7.5)
table.scale(1, 1.5)
# 表头样式
for i in range(4):
cell = table[(0, i)]
cell.set_facecolor("#4472C4")
cell.set_text_props(weight="bold", color="white", fontsize=7)
# 数据行交替颜色
for i in range(1, len(table_data)):
for j in range(4):
cell = table[(i, j)]
if i % 2 == 0:
cell.set_facecolor("#E7E6E6")
else:
cell.set_facecolor("#FFFFFF")
# 底部说明
self.gamma_table_ax.text(
0.5,
0.02,
"表格说明:\n"
"• 实测亮度: 色度计测量值 (cd/m²)\n"
"• L_bar: 归一化亮度 (0-1)\n"
"• Gamma: 实际 Gamma 值",
ha="center",
va="bottom",
fontsize=7,
color="gray",
transform=self.gamma_table_ax.transAxes,
bbox=dict(
boxstyle="round,pad=0.5",
facecolor="lightyellow",
edgecolor="gray",
alpha=0.8,
),
)
self.gamma_fig.suptitle("Gamma曲线 + 数据表格", fontsize=12, y=0.98)
self.gamma_canvas.draw()
# ========== 3. 清空EOTF图表4列==========
if hasattr(self, "eotf_ax") and hasattr(self, "eotf_table_ax"):
# 清空左侧曲线
self.eotf_ax.clear()
self.eotf_ax.set_xlim(0, 105)
self.eotf_ax.set_ylim(0, 1.1)
self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.eotf_ax.set_ylabel("L_bar (归一化亮度)", fontsize=10)
self.eotf_ax.grid(True, linestyle="--", alpha=0.3)
self.eotf_ax.tick_params(labelsize=9)
# 左侧提示
self.eotf_ax.text(
0.5,
0.5,
"等待测试数据...\n\n将显示:\n• 实测 EOTF 曲线 (蓝色)\n• 理想 PQ 曲线 (红色)",
ha="center",
va="center",
fontsize=11,
color="gray",
transform=self.eotf_ax.transAxes,
bbox=dict(
boxstyle="round,pad=1",
facecolor="white",
edgecolor="gray",
alpha=0.8,
),
)
# 清空右侧表格
self.eotf_table_ax.clear()
self.eotf_table_ax.axis("off")
# 4列表格
table_data = [
["灰阶", "实测亮度\n(cd/m²)", "L_bar\n(计算)", "EOTF γ"],
["0%", "--", "--", "--"],
["10%", "--", "--", "--"],
["20%", "--", "--", "--"],
["30%", "--", "--", "--"],
["40%", "--", "--", "--"],
["50%", "--", "--", "--"],
["60%", "--", "--", "--"],
["70%", "--", "--", "--"],
["80%", "--", "--", "--"],
["90%", "--", "--", "--"],
["100%", "--", "--", "--"],
]
table = self.eotf_table_ax.table(
cellText=table_data,
cellLoc="center",
loc="center",
colWidths=[0.18, 0.28, 0.27, 0.27],
)
table.auto_set_font_size(False)
table.set_fontsize(7.5)
table.scale(1, 1.5)
# 表头样式
for i in range(4):
cell = table[(0, i)]
cell.set_facecolor("#4472C4")
cell.set_text_props(weight="bold", color="white", fontsize=7)
# 数据行交替颜色
for i in range(1, len(table_data)):
for j in range(4):
cell = table[(i, j)]
if i % 2 == 0:
cell.set_facecolor("#E7E6E6")
else:
cell.set_facecolor("#FFFFFF")
# 底部说明
self.eotf_table_ax.text(
0.5,
0.02,
"表格说明:\n"
"• 实测亮度: 色度计测量值 (cd/m²)\n"
"• L_bar: 归一化亮度 (0-1)\n"
"• EOTF γ: HDR 实际 Gamma 值",
ha="center",
va="bottom",
fontsize=7,
color="gray",
transform=self.eotf_table_ax.transAxes,
bbox=dict(
boxstyle="round,pad=0.5",
facecolor="lightyellow",
edgecolor="gray",
alpha=0.8,
),
)
self.eotf_fig.suptitle("EOTF 曲线 + 数据表格", fontsize=12, y=0.98)
self.eotf_canvas.draw()
# ========== 4. 清空色度图表 ==========
if hasattr(self, "cct_ax1") and hasattr(self, "cct_ax2"):
# 上图x coordinates
self.cct_ax1.clear()
self.cct_ax1.set_xlabel("灰阶 (%)", fontsize=9)
self.cct_ax1.set_ylabel("CIE x", fontsize=9)
self.cct_ax1.set_xlim(0, 105)
self.cct_ax1.set_ylim(0.25, 0.35)
self.cct_ax1.grid(True, linestyle="--", alpha=0.3)
self.cct_ax1.tick_params(labelsize=8)
# 下图y coordinates
self.cct_ax2.clear()
self.cct_ax2.set_xlabel("灰阶 (%)", fontsize=9)
self.cct_ax2.set_ylabel("CIE y", fontsize=9)
self.cct_ax2.set_xlim(0, 105)
self.cct_ax2.set_ylim(0.25, 0.35)
self.cct_ax2.grid(True, linestyle="--", alpha=0.3)
self.cct_ax2.tick_params(labelsize=8)
self.cct_fig.suptitle("色度一致性测试", fontsize=12, y=0.985)
# 重置布局
self.cct_fig.subplots_adjust(
left=0.12,
right=0.88,
top=0.90,
bottom=0.08,
hspace=0.25,
)
self.cct_canvas.draw()
# ========== 5. 清空对比度图表 ==========
if hasattr(self, "contrast_ax"):
self.contrast_ax.clear()
self.contrast_ax.set_xlim(0, 1)
self.contrast_ax.set_ylim(0, 1)
self.contrast_ax.axis("off")
self.contrast_fig.suptitle("对比度测试", fontsize=12, y=0.985)
# 重置布局
self.contrast_fig.subplots_adjust(
left=0.02,
right=0.98,
top=0.90,
bottom=0.02,
)
self.contrast_canvas.draw()
# ========== 6. 清空色准图表 ==========
if hasattr(self, "accuracy_ax"):
self.accuracy_ax.clear()
self.accuracy_ax.set_xlim(0, 1)
self.accuracy_ax.set_ylim(0, 1)
self.accuracy_ax.axis("off")
# 标题
self.accuracy_fig.suptitle("色准测试", fontsize=12, y=0.985)
# 重置布局
self.accuracy_fig.subplots_adjust(
left=0.05,
right=0.95,
top=0.90,
bottom=0.05,
)
self.accuracy_canvas.draw()
def update_chart_tabs_state(self):
"""根据测试项目复选框状态动态增删图表 Tab保持规范顺序
- 色域 / Gamma 或 EOTF / 色度一致性 / 对比度 / 色准 全部走动态 add/forget
- Gamma 与 EOTF 二选一,由 current_test_type 决定
- 屏模组测试强制隐藏色准 Tab
- 客户模板 Tab 由 change_test_type 独立管理,这里不动
"""
if not hasattr(self, "chart_notebook"):
return
selected_items = self.get_selected_test_items()
current_test_type = self.config.current_test_type
# 根据测试类型决定 gamma/eotf 显示哪一个
if current_test_type == "hdr_movie":
gamma_like_frame = self.eotf_chart_frame
gamma_like_text = "EOTF 曲线"
gamma_like_other = self.gamma_chart_frame
else:
gamma_like_frame = self.gamma_chart_frame
gamma_like_text = "Gamma 曲线"
gamma_like_other = self.eotf_chart_frame
want_gamut = "gamut" in selected_items
want_gamma_like = "gamma" in selected_items or "eotf" in selected_items
want_cct = "cct" in selected_items
want_contrast = "contrast" in selected_items
want_accuracy = (
"accuracy" in selected_items and current_test_type != "screen_module"
)
# 规范顺序:色域 → Gamma/EOTF → 色度一致性 → 对比度 → 色准
spec = [
(want_gamut, self.gamut_chart_frame, "色域图"),
(want_gamma_like, gamma_like_frame, gamma_like_text),
(want_cct, self.cct_chart_frame, "色度一致性"),
(want_contrast, self.contrast_chart_frame, "对比度"),
(want_accuracy, self.accuracy_chart_frame, "色准"),
]
try:
# 始终先把"另一个" gamma/eotf frame 从 Notebook 移除,保持互斥
current_ids = list(self.chart_notebook.tabs())
if str(gamma_like_other) in current_ids:
self.chart_notebook.forget(gamma_like_other)
# 按规范顺序处理 add/forget
for idx_in_spec, (want, frame, text) in enumerate(spec):
fid = str(frame)
present = fid in self.chart_notebook.tabs()
if want and not present:
# 统计该 frame 在 spec 中前面、当前实际存在的 tab 数 → 插入位置
current_ids = list(self.chart_notebook.tabs())
pos = sum(
1 for pre_want, pre_frame, _ in spec[:idx_in_spec]
if str(pre_frame) in current_ids
)
try:
self.chart_notebook.insert(pos, frame, text=text)
except Exception:
# fallback尾部 add
self.chart_notebook.add(frame, text=text)
elif not want and present:
self.chart_notebook.forget(frame)
except Exception as e:
if hasattr(self, "log_gui"):
self.log_gui.log(f"更新Tab状态失败: {str(e)}")
def create_result_chart_frame(self):
"""创建结果图表区域 - 6个独立TabGamma 和 EOTF 分离)"""
# 创建Notebook用于图表切换
self.chart_notebook = ttk.Notebook(self.result_frame)
self.chart_notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# ========== 创建6个独立的Tab页面 ==========
# 1. 色域图页面
self.gamut_chart_frame = ttk.Frame(self.chart_notebook)
# 2. Gamma图页面SDR/屏模组使用)
self.gamma_chart_frame = ttk.Frame(self.chart_notebook)
# 3. EOTF图页面HDR专用
self.eotf_chart_frame = ttk.Frame(self.chart_notebook)
# 4. 色度一致性页面
self.cct_chart_frame = ttk.Frame(self.chart_notebook)
# 5. 对比度页面
self.contrast_chart_frame = ttk.Frame(self.chart_notebook)
# 6. 色准页面
self.accuracy_chart_frame = ttk.Frame(self.chart_notebook)
# 7. 客户模板结果页面
self.custom_template_tab_frame = ttk.Frame(self.chart_notebook)
# ========== 添加到Notebook初始只添加前5个==========
self.chart_notebook.add(self.gamut_chart_frame, text="色域图")
self.chart_notebook.add(self.gamma_chart_frame, text="Gamma曲线")
# ← EOTF 不添加,由 change_test_type() 动态控制
self.chart_notebook.add(self.cct_chart_frame, text="色度一致性")
self.chart_notebook.add(self.contrast_chart_frame, text="对比度")
self.chart_notebook.add(self.accuracy_chart_frame, text="色准")
# 初始化六个独立的图表
self.init_gamut_chart()
self.init_gamma_chart()
self.init_eotf_chart()
self.init_cct_chart()
self.init_contrast_chart()
self.init_accuracy_chart()
# 绑定Tab切换事件
self.chart_notebook.bind("<<NotebookTabChanged>>", self.on_chart_tab_changed)
# ==================== ✅ 在图表下方创建单步调试面板 ====================
self.debug_container = ttk.LabelFrame(
self.result_frame, # ← 放在 result_frame 内,图表正下方
text="🔧 单步调试",
padding=10,
)
# 默认不显示
# 创建单步调试面板实例
self.debug_panel = PQDebugPanel(self.debug_container, self)
self.log_gui.log("✓ 单步调试面板已创建(放在测试结果图表下方)")
def on_chart_tab_changed(self, event):
"""Tab切换时的事件处理"""
try:
self._last_tab_index = self.chart_notebook.index(
self.chart_notebook.select()
)
except Exception as e:
self.log_gui.log(f"Tab切换事件处理失败: {str(e)}")