修改深色模式下结果图片显示异常

This commit is contained in:
xinzhu.yin
2026-06-05 16:58:46 +08:00
parent 49d82da8b9
commit e9a591bf6e
11 changed files with 385 additions and 140 deletions

View File

@@ -25,6 +25,7 @@ from typing import TYPE_CHECKING
from app.ucd_domain import ConnectionChanged, UcdError from app.ucd_domain import ConnectionChanged, UcdError
from drivers.caSerail import CASerail from drivers.caSerail import CASerail
from drivers.ucd_driver import DeviceInfo from drivers.ucd_driver import DeviceInfo
from app.views.modern_styles import get_theme_palette
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -189,8 +190,7 @@ class ConnectionController:
self.disconnect_ucd() self.disconnect_ucd()
self.disconnect_ca() self.disconnect_ca()
self._enable_widgets() self._enable_widgets()
self._app.ucd_status_indicator.config(bg="gray") self._app.refresh_connection_indicators()
self._app.ca_status_indicator.config(bg="gray")
self._app.status_var.set("串口连接已断开") self._app.status_var.set("串口连接已断开")
except Exception as exc: # noqa: BLE001 except Exception as exc: # noqa: BLE001
self._log(f"断开连接时发生错误: {exc}", level="info") self._log(f"断开连接时发生错误: {exc}", level="info")
@@ -212,10 +212,7 @@ class ConnectionController:
) )
app.ca_com_combo.config(values=com_ports) app.ca_com_combo.config(values=com_ports)
if hasattr(app, "ucd_status_indicator"): app.refresh_connection_indicators()
app.ucd_status_indicator.config(bg="gray")
if hasattr(app, "ca_status_indicator"):
app.ca_status_indicator.config(bg="gray")
app.update_config() app.update_config()
@@ -254,7 +251,45 @@ def check_com_connections(self: "PQAutomationApp"):
def update_connection_indicator(self: "PQAutomationApp", indicator, connected): def update_connection_indicator(self: "PQAutomationApp", indicator, connected):
indicator.config(bg="green" if connected else "red") _draw_connection_indicator(indicator, "green" if connected else "red")
def refresh_connection_indicators(self: "PQAutomationApp"):
"""根据当前设备状态重画 UCD / CA 指示灯。"""
if hasattr(self, "ucd_status_indicator"):
ucd_connected = bool(getattr(self.ucd, "status", False))
_draw_connection_indicator(
self.ucd_status_indicator,
"green" if ucd_connected else "gray",
)
if hasattr(self, "ca_status_indicator"):
ca_connected = getattr(self, "ca", None) is not None
_draw_connection_indicator(
self.ca_status_indicator,
"green" if ca_connected else "gray",
)
def _draw_connection_indicator(canvas, state: str) -> None:
palette = get_theme_palette()
color_map = {
"green": "#2ECC71",
"red": "#E74C3C",
"gray": "#9AA3AD",
}
fill = color_map.get(state, state)
border = palette["border"]
bg = palette["card_bg"]
try:
canvas.configure(bg=bg, highlightbackground=border, highlightcolor=border)
canvas.delete("all")
# 保持原有视觉:方形状态灯(红/绿/灰)
canvas.create_rectangle(0, 0, 15, 15, fill=fill, outline=border, width=1)
except Exception:
try:
canvas.config(bg=fill)
except Exception:
pass
def check_port_connection(self: "PQAutomationApp", is_ucd=True): def check_port_connection(self: "PQAutomationApp", is_ucd=True):
@@ -323,6 +358,7 @@ __all__ = [
"refresh_com_ports", "refresh_com_ports",
"check_com_connections", "check_com_connections",
"update_connection_indicator", "update_connection_indicator",
"refresh_connection_indicators",
"check_port_connection", "check_port_connection",
"enable_com_widgets", "enable_com_widgets",
"disconnect_com_connections", "disconnect_com_connections",
@@ -338,6 +374,7 @@ class DeviceConnectionMixin:
refresh_com_ports = refresh_com_ports refresh_com_ports = refresh_com_ports
check_com_connections = check_com_connections check_com_connections = check_com_connections
update_connection_indicator = update_connection_indicator update_connection_indicator = update_connection_indicator
refresh_connection_indicators = refresh_connection_indicators
check_port_connection = check_port_connection check_port_connection = check_port_connection
enable_com_widgets = enable_com_widgets enable_com_widgets = enable_com_widgets
disconnect_com_connections = disconnect_com_connections disconnect_com_connections = disconnect_com_connections

View File

@@ -9,7 +9,10 @@ from typing import TYPE_CHECKING
from matplotlib.patches import Rectangle from matplotlib.patches import Rectangle
from matplotlib.lines import Line2D from matplotlib.lines import Line2D
from matplotlib.patches import Circle import matplotlib.colors as mcolors
import numpy as np
from app.views.modern_styles import get_theme_palette
from app.plots.gamut_background import get_cie1976_background from app.plots.gamut_background import get_cie1976_background
from app.tests.color_accuracy import get_accuracy_color_standards from app.tests.color_accuracy import get_accuracy_color_standards
@@ -112,6 +115,9 @@ def _draw_left_panel(ax, color_patches, delta_e_values, font_scale=1.0, dark_mod
spine.set_linewidth(0.9) spine.set_linewidth(0.9)
# ============================================================ # ============================================================
# 子图CIE 1976 u'v' 色度图(目标 vs 实测) # 子图CIE 1976 u'v' 色度图(目标 vs 实测)
# ============================================================ # ============================================================
@@ -121,12 +127,14 @@ def _draw_uv_diagram(ax, color_patches, measurements, standards, font_scale=1.0,
ax.clear() ax.clear()
try: try:
bg, bbox = get_cie1976_background() bg, bbox = get_cie1976_background()
if bg.shape[-1] == 4:
bg = bg[:, :, :3]
xmin, xmax, ymin, ymax = bbox xmin, xmax, ymin, ymax = bbox
ax.imshow( ax.imshow(
bg, bg,
extent=(xmin, xmax, ymin, ymax), extent=(xmin, xmax, ymin, ymax),
origin="lower", origin="lower",
interpolation="bicubic", interpolation="bilinear",
zorder=0, zorder=0,
aspect="auto", aspect="auto",
) )
@@ -181,8 +189,10 @@ def _draw_uv_diagram(ax, color_patches, measurements, standards, font_scale=1.0,
s_u, s_v = _xy_to_uv(sx, sy) s_u, s_v = _xy_to_uv(sx, sy)
# face = get_patch_color_from_xy(name, (sx, sy)).strip().upper() # face = get_patch_color_from_xy(name, (sx, sy)).strip().upper()
face = _COLOR_MAP.get(name, "#888888") face = _COLOR_MAP.get(name, "#FFFFFF")
print(name, face) # face = get_patch_color_from_xy(name, (mx, my))
# face = "#FF0000"
# 目标点Target 空心方框 # 目标点Target 空心方框
ax.scatter( ax.scatter(
@@ -300,17 +310,24 @@ def _draw_result_judgement(ax, accuracy_data, font_scale=1.0, dark_mode=False):
def plot_accuracy(self: "PQAutomationApp", accuracy_data, test_type): def plot_accuracy(self: "PQAutomationApp", accuracy_data, test_type):
"""绘制色准测试结果 - Calman 风格(色块 + CIE 1976 u'v' + 统计)。""" """绘制色准测试结果 - Calman 风格(色块 + CIE 1976 u'v' + 统计)。"""
palette = get_theme_palette()
fig = self.accuracy_fig
fig.clear()
try: try:
from app.views.theme_manager import is_dark from app.views.theme_manager import is_dark
dark_mode = is_dark() dark_mode = is_dark()
except Exception: except Exception:
dark_mode = False dark_mode = False
fig.patch.set_facecolor("#1B1F24" if dark_mode else "#FFFFFF") fig = self.accuracy_fig
fig.clear()
try:
fig.set_layout_engine(None)
except Exception:
try:
fig.set_tight_layout(False)
except Exception:
pass
fig.patch.set_facecolor(palette["bg"])
# 根据当前画布像素尺寸动态缩放字体,避免窗口缩小时文字挤压重叠。 # 根据当前画布像素尺寸动态缩放字体,避免窗口缩小时文字挤压重叠。
font_scale = 1.0 font_scale = 1.0
@@ -341,13 +358,12 @@ def plot_accuracy(self: "PQAutomationApp", accuracy_data, test_type):
else: else:
title = f"{test_type_name} - 色准测试(全 29色 | Gamma {target_gamma}" title = f"{test_type_name} - 色准测试(全 29色 | Gamma {target_gamma}"
title_color = "#F3F5F7" if dark_mode else "#111"
fig.suptitle( fig.suptitle(
title, title,
fontsize=max(8, 11 * font_scale), fontsize=max(8, 11 * font_scale),
y=0.975, y=0.975,
fontweight="bold", fontweight="bold",
color=title_color, color=palette["fg"],
) )
gs = fig.add_gridspec( gs = fig.add_gridspec(
@@ -362,6 +378,8 @@ def plot_accuracy(self: "PQAutomationApp", accuracy_data, test_type):
ax_left = fig.add_subplot(gs[0, 0]) ax_left = fig.add_subplot(gs[0, 0])
ax_uv = fig.add_subplot(gs[0, 1]) ax_uv = fig.add_subplot(gs[0, 1])
ax_judge = fig.add_subplot(gs[1, :]) ax_judge = fig.add_subplot(gs[1, :])
for ax in (ax_left, ax_uv, ax_judge):
ax.set_facecolor(palette["card_bg"])
# 兼容外部对 self.accuracy_ax 的引用 # 兼容外部对 self.accuracy_ax 的引用
self.accuracy_ax = ax_judge self.accuracy_ax = ax_judge

View File

@@ -4,6 +4,7 @@ Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_cct 原样搬迁。
""" """
import numpy as np import numpy as np
from app.views.modern_styles import get_theme_palette
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -11,11 +12,36 @@ if TYPE_CHECKING:
from pqAutomationApp import PQAutomationApp from pqAutomationApp import PQAutomationApp
def _is_dark_palette(palette: dict[str, str]) -> bool:
"""根据主题背景色亮度判断是否深色主题。"""
bg = palette.get("bg", "#FFFFFF").lstrip("#")
try:
r = int(bg[0:2], 16)
g = int(bg[2:4], 16)
b = int(bg[4:6], 16)
except Exception:
return False
return (r * 299 + g * 587 + b * 114) / 1000 < 128
def plot_cct(self: "PQAutomationApp", test_type): def plot_cct(self: "PQAutomationApp", test_type):
"""绘制 x 和 y 坐标分离图 - 每个点标注纵坐标值""" """绘制 x 和 y 坐标分离图 - 每个点标注纵坐标值"""
palette = get_theme_palette()
dark_mode = _is_dark_palette(palette)
x_line_color = "#2F8BFF" if dark_mode else "#0A4BFF"
y_line_color = "#FF4D4D" if dark_mode else "#D90429"
ideal_line_color = "#00C853" if dark_mode else "#198754"
x_tol_color = "#FF7070" if dark_mode else "#C0392B"
y_tol_color = "#FFB74D" if dark_mode else "#D68910"
grid_color = "#566070" if dark_mode else "#B8BDC3"
axis_text = "#EDF2FA" if dark_mode else palette["fg"]
axis_sub_text = "#C8D2E0" if dark_mode else "#222222"
legend_bg = "#131821" if dark_mode else "#FFFFFF"
legend_edge = "#A4B2C6" if dark_mode else palette["border"]
self.cct_fig.clear() self.cct_fig.clear()
self.cct_fig.patch.set_facecolor(palette["bg"])
gray_data = self.results.get_intermediate_data("shared", "gray") gray_data = self.results.get_intermediate_data("shared", "gray")
if not gray_data: if not gray_data:
@@ -31,7 +57,7 @@ def plot_cct(self: "PQAutomationApp", test_type):
ha="center", ha="center",
va="center", va="center",
fontsize=14, fontsize=14,
color="red", color=palette["danger"],
) )
ax.axis("off") ax.axis("off")
self.cct_canvas.draw() self.cct_canvas.draw()
@@ -111,12 +137,20 @@ def plot_cct(self: "PQAutomationApp", test_type):
# 为所有测试类型创建子图 # 为所有测试类型创建子图
ax1 = self.cct_fig.add_subplot(211) ax1 = self.cct_fig.add_subplot(211)
ax2 = self.cct_fig.add_subplot(212) ax2 = self.cct_fig.add_subplot(212)
for ax in (ax1, ax2):
ax.set_facecolor(palette["card_bg"])
for spine in ax.spines.values():
spine.set_color(palette["border"])
ax.tick_params(labelsize=8, colors=axis_sub_text)
ax.xaxis.label.set_color(axis_text)
ax.yaxis.label.set_color(axis_text)
# ========== 上图x coordinates ========== # ========== 上图x coordinates ==========
ax1.plot( ax1.plot(
grayscale, grayscale,
x_measured, x_measured,
"b-o", color=x_line_color,
marker="o",
label="屏本体", label="屏本体",
linewidth=2, linewidth=2,
markersize=4, markersize=4,
@@ -133,13 +167,13 @@ def plot_cct(self: "PQAutomationApp", test_type):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=7, fontsize=7,
color="blue", color=x_line_color,
bbox=dict( bbox=dict(
boxstyle="round,pad=0.2", boxstyle="round,pad=0.2",
facecolor="white", facecolor=palette["card_bg"],
edgecolor="blue", edgecolor=x_line_color,
alpha=0.8, alpha=0.92 if dark_mode else 0.85,
linewidth=0.5, linewidth=0.8,
), ),
) )
@@ -147,7 +181,7 @@ def plot_cct(self: "PQAutomationApp", test_type):
full_grayscale = np.linspace(0, 100, 100) full_grayscale = np.linspace(0, 100, 100)
ax1.axhline( ax1.axhline(
y=x_ideal, y=x_ideal,
color="green", color=ideal_line_color,
linestyle="--", linestyle="--",
linewidth=1.5, linewidth=1.5,
label=f"x-ideal ({x_ideal:.4f})", label=f"x-ideal ({x_ideal:.4f})",
@@ -155,30 +189,34 @@ def plot_cct(self: "PQAutomationApp", test_type):
) )
ax1.axhline( ax1.axhline(
y=x_low, y=x_low,
color="red", color=x_tol_color,
linestyle=":", linestyle=":",
linewidth=1, linewidth=1,
alpha=0.7, alpha=0.95 if dark_mode else 0.7,
label=f"x-low ({x_low:.4f})", label=f"x-low ({x_low:.4f})",
zorder=2, zorder=2,
) )
ax1.axhline( ax1.axhline(
y=x_high, y=x_high,
color="red", color=x_tol_color,
linestyle=":", linestyle=":",
linewidth=1, linewidth=1,
alpha=0.7, alpha=0.95 if dark_mode else 0.7,
label=f"x-high ({x_high:.4f})", label=f"x-high ({x_high:.4f})",
zorder=2, zorder=2,
) )
ax1.fill_between( ax1.fill_between(
full_grayscale, x_low, x_high, alpha=0.15, color="blue", zorder=1 full_grayscale,
x_low,
x_high,
alpha=0.22 if dark_mode else 0.15,
color=x_line_color,
zorder=1,
) )
ax1.set_xlabel("灰阶 (%)", fontsize=9) ax1.set_xlabel("灰阶 (%)", fontsize=9, color=axis_text)
ax1.set_ylabel("CIE x", fontsize=9) ax1.set_ylabel("CIE x", fontsize=9, color=axis_text)
ax1.grid(True, linestyle="--", alpha=0.3) ax1.grid(True, linestyle="--", alpha=0.45 if dark_mode else 0.3, color=grid_color)
ax1.tick_params(labelsize=8)
ax1.set_xlim(0, 105) ax1.set_xlim(0, 105)
# 纵坐标范围由用户参数控制 # 纵坐标范围由用户参数控制
@@ -211,7 +249,8 @@ def plot_cct(self: "PQAutomationApp", test_type):
ax2.plot( ax2.plot(
grayscale, grayscale,
y_measured, y_measured,
"r-o", color=y_line_color,
marker="o",
label="屏本体", label="屏本体",
linewidth=2, linewidth=2,
markersize=4, markersize=4,
@@ -228,19 +267,19 @@ def plot_cct(self: "PQAutomationApp", test_type):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=7, fontsize=7,
color="red", color=y_line_color,
bbox=dict( bbox=dict(
boxstyle="round,pad=0.2", boxstyle="round,pad=0.2",
facecolor="white", facecolor=palette["card_bg"],
edgecolor="red", edgecolor=y_line_color,
alpha=0.8, alpha=0.92 if dark_mode else 0.85,
linewidth=0.5, linewidth=0.8,
), ),
) )
ax2.axhline( ax2.axhline(
y=y_ideal, y=y_ideal,
color="green", color=ideal_line_color,
linestyle="--", linestyle="--",
linewidth=1.5, linewidth=1.5,
label=f"y-ideal ({y_ideal:.4f})", label=f"y-ideal ({y_ideal:.4f})",
@@ -248,30 +287,34 @@ def plot_cct(self: "PQAutomationApp", test_type):
) )
ax2.axhline( ax2.axhline(
y=y_low, y=y_low,
color="orange", color=y_tol_color,
linestyle=":", linestyle=":",
linewidth=1, linewidth=1,
alpha=0.7, alpha=0.95 if dark_mode else 0.7,
label=f"y-low ({y_low:.4f})", label=f"y-low ({y_low:.4f})",
zorder=2, zorder=2,
) )
ax2.axhline( ax2.axhline(
y=y_high, y=y_high,
color="orange", color=y_tol_color,
linestyle=":", linestyle=":",
linewidth=1, linewidth=1,
alpha=0.7, alpha=0.95 if dark_mode else 0.7,
label=f"y-high ({y_high:.4f})", label=f"y-high ({y_high:.4f})",
zorder=2, zorder=2,
) )
ax2.fill_between( ax2.fill_between(
full_grayscale, y_low, y_high, alpha=0.15, color="orange", zorder=1 full_grayscale,
y_low,
y_high,
alpha=0.22 if dark_mode else 0.15,
color=y_tol_color,
zorder=1,
) )
ax2.set_xlabel("灰阶 (%)", fontsize=9) ax2.set_xlabel("灰阶 (%)", fontsize=9, color=axis_text)
ax2.set_ylabel("CIE y", fontsize=9) ax2.set_ylabel("CIE y", fontsize=9, color=axis_text)
ax2.grid(True, linestyle="--", alpha=0.3) ax2.grid(True, linestyle="--", alpha=0.45 if dark_mode else 0.3, color=grid_color)
ax2.tick_params(labelsize=8)
ax2.set_xlim(0, 105) ax2.set_xlim(0, 105)
# 纵坐标范围由用户参数控制 # 纵坐标范围由用户参数控制
@@ -307,6 +350,7 @@ def plot_cct(self: "PQAutomationApp", test_type):
fontsize=12, fontsize=12,
y=0.98, y=0.98,
fontweight="bold", fontweight="bold",
color=palette["fg"],
) )
self.cct_fig.subplots_adjust( self.cct_fig.subplots_adjust(
@@ -317,12 +361,25 @@ def plot_cct(self: "PQAutomationApp", test_type):
hspace=0.30, hspace=0.30,
) )
ax1.legend( legend1 = ax1.legend(
fontsize=7, loc="center left", bbox_to_anchor=(1.05, 0.5), framealpha=1.0 fontsize=7,
loc="center left",
bbox_to_anchor=(1.05, 0.5),
framealpha=0.92 if dark_mode else 1.0,
facecolor=legend_bg,
edgecolor=legend_edge,
) )
ax2.legend( legend2 = ax2.legend(
fontsize=7, loc="center left", bbox_to_anchor=(1.05, 0.5), framealpha=1.0 fontsize=7,
loc="center left",
bbox_to_anchor=(1.05, 0.5),
framealpha=0.92 if dark_mode else 1.0,
facecolor=legend_bg,
edgecolor=legend_edge,
) )
for legend in (legend1, legend2):
for text in legend.get_texts():
text.set_color(axis_text)
self.cct_canvas.draw() self.cct_canvas.draw()
self.chart_notebook.select(self.cct_chart_frame) self.chart_notebook.select(self.cct_chart_frame)

View File

@@ -4,6 +4,7 @@ Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_contrast 原样搬迁
""" """
from matplotlib.patches import Rectangle from matplotlib.patches import Rectangle
from app.views.modern_styles import get_theme_palette
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -14,9 +15,12 @@ if TYPE_CHECKING:
def plot_contrast(self: "PQAutomationApp", contrast_data, test_type): def plot_contrast(self: "PQAutomationApp", contrast_data, test_type):
"""绘制对比度测试结果 - 固定布局版本""" """绘制对比度测试结果 - 固定布局版本"""
palette = get_theme_palette()
# 清空并重置 # 清空并重置
self.contrast_ax.clear() self.contrast_ax.clear()
self.contrast_fig.patch.set_facecolor(palette["bg"])
self.contrast_ax.set_facecolor(palette["card_bg"])
self.contrast_ax.set_xlim(0, 1) self.contrast_ax.set_xlim(0, 1)
self.contrast_ax.set_ylim(0, 1) self.contrast_ax.set_ylim(0, 1)
self.contrast_ax.axis("off") self.contrast_ax.axis("off")
@@ -51,6 +55,7 @@ def plot_contrast(self: "PQAutomationApp", contrast_data, test_type):
fontsize=12, fontsize=12,
y=0.98, y=0.98,
fontweight="bold", fontweight="bold",
color=palette["fg"],
) )
# ========== 中央大对比度卡片 ========== # ========== 中央大对比度卡片 ==========
@@ -107,16 +112,16 @@ def plot_contrast(self: "PQAutomationApp", contrast_data, test_type):
"title": "白场亮度", "title": "白场亮度",
"value": f"{max_lum:.2f}", "value": f"{max_lum:.2f}",
"unit": "cd/m²", "unit": "cd/m²",
"color": "#E3F2FD", "color": palette["surface_alt_bg"],
"edge_color": "#2196F3", "edge_color": palette["primary"],
}, },
{ {
"x": start_x + card_width + gap, "x": start_x + card_width + gap,
"title": "黑场亮度", "title": "黑场亮度",
"value": f"{min_lum:.4f}", "value": f"{min_lum:.4f}",
"unit": "cd/m²", "unit": "cd/m²",
"color": "#F3E5F5", "color": palette["card_bg"],
"edge_color": "#9C27B0", "edge_color": palette["secondary"],
}, },
] ]
@@ -142,6 +147,7 @@ def plot_contrast(self: "PQAutomationApp", contrast_data, test_type):
va="top", va="top",
fontsize=10, fontsize=10,
fontweight="bold", fontweight="bold",
color=palette["fg"],
transform=self.contrast_ax.transAxes, transform=self.contrast_ax.transAxes,
) )
@@ -154,6 +160,7 @@ def plot_contrast(self: "PQAutomationApp", contrast_data, test_type):
va="center", va="center",
fontsize=16, fontsize=16,
fontweight="bold", fontweight="bold",
color=palette["fg"],
transform=self.contrast_ax.transAxes, transform=self.contrast_ax.transAxes,
) )
@@ -165,7 +172,7 @@ def plot_contrast(self: "PQAutomationApp", contrast_data, test_type):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=9, fontsize=9,
color="gray", color=palette["muted_fg"],
transform=self.contrast_ax.transAxes, transform=self.contrast_ax.transAxes,
) )

View File

@@ -4,6 +4,7 @@ Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_eotf 原样搬迁。
""" """
import numpy as np import numpy as np
from app.views.modern_styles import get_theme_palette
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -14,15 +15,21 @@ if TYPE_CHECKING:
def plot_eotf(self: "PQAutomationApp", L_bar, results_with_eotf_list, test_type): def plot_eotf(self: "PQAutomationApp", L_bar, results_with_eotf_list, test_type):
"""绘制 EOTF 曲线 + 数据表格HDR 专用,包含实测亮度)""" """绘制 EOTF 曲线 + 数据表格HDR 专用,包含实测亮度)"""
palette = get_theme_palette()
# ========== 1. 清空并重置左侧曲线 ========== # ========== 1. 清空并重置左侧曲线 ==========
self.eotf_ax.clear() self.eotf_ax.clear()
self.eotf_fig.patch.set_facecolor(palette["bg"])
self.eotf_ax.set_facecolor(palette["card_bg"])
self.eotf_ax.set_xlim(0, 105) self.eotf_ax.set_xlim(0, 105)
self.eotf_ax.set_ylim(0, 1.1) self.eotf_ax.set_ylim(0, 1.1)
self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10) self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.eotf_ax.set_ylabel("L_bar", fontsize=10) self.eotf_ax.set_ylabel("L_bar", fontsize=10)
self.eotf_ax.grid(True, linestyle="--", alpha=0.3) self.eotf_ax.grid(True, linestyle="--", alpha=0.3)
self.eotf_ax.tick_params(labelsize=9) self.eotf_ax.tick_params(labelsize=9)
self.eotf_ax.tick_params(colors=palette["fg"])
for spine in self.eotf_ax.spines.values():
spine.set_color(palette["border"])
# 生成横坐标(灰阶百分比) # 生成横坐标(灰阶百分比)
x_values = np.linspace(0, 100, len(L_bar)) x_values = np.linspace(0, 100, len(L_bar))
@@ -120,17 +127,17 @@ def plot_eotf(self: "PQAutomationApp", L_bar, results_with_eotf_list, test_type)
# 表头样式 # 表头样式
for i in range(4): for i in range(4):
cell = table[(0, i)] cell = table[(0, i)]
cell.set_facecolor("#4472C4") cell.set_facecolor(palette["primary"])
cell.set_text_props(weight="bold", color="white") cell.set_text_props(weight="bold", color=palette["select_fg"])
# 数据行交替颜色 # 数据行交替颜色
for i in range(1, len(table_data)): for i in range(1, len(table_data)):
for j in range(4): for j in range(4):
cell = table[(i, j)] cell = table[(i, j)]
if i % 2 == 0: if i % 2 == 0:
cell.set_facecolor("#E7E6E6") cell.set_facecolor(palette["surface_alt_bg"])
else: else:
cell.set_facecolor("#FFFFFF") cell.set_facecolor(palette["card_bg"])
# ========== 3. 总标题 ========== # ========== 3. 总标题 ==========
test_type_name = self.get_test_type_name(test_type) test_type_name = self.get_test_type_name(test_type)
@@ -139,6 +146,7 @@ def plot_eotf(self: "PQAutomationApp", L_bar, results_with_eotf_list, test_type)
fontsize=12, fontsize=12,
y=0.98, y=0.98,
fontweight="bold", fontweight="bold",
color=palette["fg"],
) )
# 选中 EOTF Tab # 选中 EOTF Tab

View File

@@ -4,6 +4,7 @@ Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamma 原样搬迁。
""" """
import numpy as np import numpy as np
from app.views.modern_styles import get_theme_palette
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -11,18 +12,44 @@ if TYPE_CHECKING:
from pqAutomationApp import PQAutomationApp from pqAutomationApp import PQAutomationApp
def _is_dark_palette(palette: dict[str, str]) -> bool:
"""根据主题背景色亮度判断是否深色主题。"""
bg = palette.get("bg", "#FFFFFF").lstrip("#")
try:
r = int(bg[0:2], 16)
g = int(bg[2:4], 16)
b = int(bg[4:6], 16)
except Exception:
return False
return (r * 299 + g * 587 + b * 114) / 1000 < 128
def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_gamma, test_type): def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_gamma, test_type):
"""绘制Gamma曲线 + 数据表格(包含实测亮度)""" """绘制Gamma曲线 + 数据表格(包含实测亮度)"""
palette = get_theme_palette()
dark_mode = _is_dark_palette(palette)
line_actual = "#3FA7FF" if dark_mode else "#0A4BFF"
line_ideal = "#FF6B6B" if dark_mode else "#D62828"
grid_color = "#566070" if dark_mode else "#B8BDC3"
legend_bg = "#131821" if dark_mode else "#FFFFFF"
legend_edge = "#A4B2C6" if dark_mode else palette["border"]
table_edge = "#738196" if dark_mode else palette["border"]
table_body_fg = "#EEF3FA" if dark_mode else palette["fg"]
# ========== 1. 清空并重置左侧曲线 ========== # ========== 1. 清空并重置左侧曲线 ==========
self.gamma_ax.clear() self.gamma_ax.clear()
self.gamma_fig.patch.set_facecolor(palette["bg"])
self.gamma_ax.set_facecolor(palette["card_bg"])
self.gamma_ax.set_xlim(0, 105) self.gamma_ax.set_xlim(0, 105)
self.gamma_ax.set_ylim(0, 1.1) self.gamma_ax.set_ylim(0, 1.1)
self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10) self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10, color=palette["fg"])
self.gamma_ax.set_ylabel("L_bar", fontsize=10) self.gamma_ax.set_ylabel("L_bar", fontsize=10, color=palette["fg"])
self.gamma_ax.grid(True, linestyle="--", alpha=0.3) self.gamma_ax.grid(True, linestyle="--", alpha=0.45 if dark_mode else 0.3, color=grid_color)
self.gamma_ax.tick_params(labelsize=9) self.gamma_ax.tick_params(labelsize=9)
self.gamma_ax.tick_params(colors=palette["fg"])
for spine in self.gamma_ax.spines.values():
spine.set_color(palette["border"])
# 生成横坐标(灰阶百分比) # 生成横坐标(灰阶百分比)
x_values = np.linspace(0, 100, len(L_bar)) x_values = np.linspace(0, 100, len(L_bar))
@@ -46,7 +73,8 @@ def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_g
self.gamma_ax.plot( self.gamma_ax.plot(
x_values, x_values,
L_bar, L_bar,
"b-o", color=line_actual,
marker="o",
label=f"实测 (平均γ={avg_gamma:.2f})", label=f"实测 (平均γ={avg_gamma:.2f})",
linewidth=2, linewidth=2,
markersize=4, markersize=4,
@@ -58,15 +86,24 @@ def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_g
self.gamma_ax.plot( self.gamma_ax.plot(
x_values, x_values,
ideal_L_bar, ideal_L_bar,
"r--", color=line_ideal,
linestyle="--",
label=f"理想 (γ={target_gamma})", label=f"理想 (γ={target_gamma})",
linewidth=2, linewidth=2,
alpha=0.7, alpha=0.9 if dark_mode else 0.7,
zorder=3, zorder=3,
) )
# 图例 # 图例
self.gamma_ax.legend(fontsize=9, loc="upper left", framealpha=0.95) legend = self.gamma_ax.legend(
fontsize=9,
loc="upper left",
framealpha=0.9 if dark_mode else 0.95,
facecolor=legend_bg,
edgecolor=legend_edge,
)
for text in legend.get_texts():
text.set_color(palette["fg"])
# ========== 2. 清空并绘制右侧表格 ========== # ========== 2. 清空并绘制右侧表格 ==========
self.gamma_table_ax.clear() self.gamma_table_ax.clear()
@@ -120,17 +157,22 @@ def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_g
# 表头样式 # 表头样式
for i in range(4): for i in range(4):
cell = table[(0, i)] cell = table[(0, i)]
cell.set_facecolor("#4472C4") cell.set_facecolor(palette["primary"])
cell.set_text_props(weight="bold", color="white") cell.set_text_props(weight="bold", color=palette["select_fg"])
cell.set_edgecolor(table_edge)
cell.set_linewidth(0.8)
# 数据行交替颜色 # 数据行交替颜色
for i in range(1, len(table_data)): for i in range(1, len(table_data)):
for j in range(4): for j in range(4):
cell = table[(i, j)] cell = table[(i, j)]
if i % 2 == 0: if i % 2 == 0:
cell.set_facecolor("#E7E6E6") cell.set_facecolor(palette["surface_alt_bg"])
else: else:
cell.set_facecolor("#FFFFFF") cell.set_facecolor(palette["card_bg"])
cell.set_text_props(color=table_body_fg)
cell.set_edgecolor(table_edge)
cell.set_linewidth(0.6)
# ========== 3. 总标题 ========== # ========== 3. 总标题 ==========
test_type_name = self.get_test_type_name(test_type) test_type_name = self.get_test_type_name(test_type)
@@ -139,6 +181,7 @@ def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_g
fontsize=12, fontsize=12,
y=0.98, y=0.98,
fontweight="bold", fontweight="bold",
color=palette["fg"],
) )
# ========== 4. 绘制到画布 ========== # ========== 4. 绘制到画布 ==========

View File

@@ -178,7 +178,7 @@ def _style_axes(ax, *, title, xlabel, ylabel, xlim, ylim, dark_mode):
ax.set_ylabel(ylabel, fontsize=10, color=text) ax.set_ylabel(ylabel, fontsize=10, color=text)
ax.set_xlim(*xlim) ax.set_xlim(*xlim)
ax.set_ylim(*ylim) ax.set_ylim(*ylim)
ax.set_aspect("equal", adjustable="datalim") ax.set_aspect("equal", adjustable="box")
ax.grid(True, linestyle=":", linewidth=0.7, color=grid, alpha=0.32) ax.grid(True, linestyle=":", linewidth=0.7, color=grid, alpha=0.32)
ax.tick_params(axis="both", labelsize=9, colors=text) ax.tick_params(axis="both", labelsize=9, colors=text)
for spine in ax.spines.values(): for spine in ax.spines.values():
@@ -193,8 +193,10 @@ def _blit_background(ax, background, bbox):
ax.imshow( ax.imshow(
background, background,
extent=(xmin, xmax, ymin, ymax), extent=(xmin, xmax, ymin, ymax),
origin="upper", # canvas.buffer_rgba 行 0 为顶部 # gamut_background._render_chromaticity 已做过 np.flipud
interpolation="bicubic", # 这里必须使用 lower 才能与真实色度坐标方向一致。
origin="lower",
interpolation="bilinear",
zorder=0, zorder=0,
aspect="auto", # 由 _style_axes 的 set_aspect("equal") 控制 aspect="auto", # 由 _style_axes 的 set_aspect("equal") 控制
) )

View File

@@ -9,6 +9,7 @@ import ttkbootstrap as ttk
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from app.views.pq_debug_panel import PQDebugPanel from app.views.pq_debug_panel import PQDebugPanel
from app.views.modern_styles import get_theme_palette
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@@ -19,8 +20,7 @@ if TYPE_CHECKING:
def _result_bg_color() -> str: def _result_bg_color() -> str:
"""根据当前主题返回结果图背景色。""" """根据当前主题返回结果图背景色。"""
try: try:
from app.views.theme_manager import is_dark return get_theme_palette()["bg"]
return "#1B1F24" if is_dark() else "#FFFFFF"
except Exception: except Exception:
return "#FFFFFF" return "#FFFFFF"
@@ -55,6 +55,19 @@ def apply_result_chart_theme(self: "PQAutomationApp"):
pass pass
def _apply_axes_theme(ax, palette, *, title=None, xlabel=None, ylabel=None):
ax.set_facecolor(palette["card_bg"])
for spine in ax.spines.values():
spine.set_color(palette["border"])
if title is not None:
ax.set_title(title, color=palette["fg"])
if xlabel is not None:
ax.set_xlabel(xlabel, color=palette["fg"])
if ylabel is not None:
ax.set_ylabel(ylabel, color=palette["fg"])
ax.tick_params(axis="both", colors=palette["fg"])
def init_gamut_chart(self: "PQAutomationApp"): def init_gamut_chart(self: "PQAutomationApp"):
"""初始化色域图表 - 手动设置subplot位置完全避免重叠""" """初始化色域图表 - 手动设置subplot位置完全避免重叠"""
container = ttk.Frame(self.gamut_chart_frame) container = ttk.Frame(self.gamut_chart_frame)
@@ -154,8 +167,10 @@ def init_gamma_chart(self: "PQAutomationApp"):
"""初始化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)
palette = get_theme_palette()
self.gamma_fig = plt.Figure(figsize=(12, 6), dpi=100, constrained_layout=False) self.gamma_fig = plt.Figure(figsize=(12, 6), dpi=100, constrained_layout=False)
self.gamma_fig.patch.set_facecolor(palette["bg"])
self.gamma_canvas = FigureCanvasTkAgg(self.gamma_fig, master=container) self.gamma_canvas = FigureCanvasTkAgg(self.gamma_fig, master=container)
canvas_widget = self.gamma_canvas.get_tk_widget() canvas_widget = self.gamma_canvas.get_tk_widget()
@@ -163,6 +178,7 @@ def init_gamma_chart(self: "PQAutomationApp"):
# 左侧Gamma 曲线 # 左侧Gamma 曲线
self.gamma_ax = self.gamma_fig.add_axes([0.08, 0.12, 0.50, 0.78]) self.gamma_ax = self.gamma_fig.add_axes([0.08, 0.12, 0.50, 0.78])
_apply_axes_theme(self.gamma_ax, palette, xlabel="灰阶 (%)", ylabel="L_bar")
self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10) self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.gamma_ax.set_ylabel("L_bar", fontsize=10) self.gamma_ax.set_ylabel("L_bar", fontsize=10)
self.gamma_ax.set_xlim(0, 105) self.gamma_ax.set_xlim(0, 105)
@@ -182,10 +198,13 @@ def init_gamma_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="center", va="center",
fontsize=10, fontsize=10,
color="gray", color=palette["muted_fg"],
transform=self.gamma_ax.transAxes, transform=self.gamma_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=1", facecolor="white", edgecolor="gray", alpha=0.8 boxstyle="round,pad=1",
facecolor=palette["card_bg"],
edgecolor=palette["border"],
alpha=0.95,
), ),
) )
@@ -223,17 +242,17 @@ def init_gamma_chart(self: "PQAutomationApp"):
# 表头样式 # 表头样式
for i in range(4): for i in range(4):
cell = table[(0, i)] cell = table[(0, i)]
cell.set_facecolor("#4472C4") cell.set_facecolor(palette["primary"])
cell.set_text_props(weight="bold", color="white", fontsize=7) cell.set_text_props(weight="bold", color=palette["select_fg"], fontsize=7)
# 数据行交替颜色 # 数据行交替颜色
for i in range(1, len(table_data)): for i in range(1, len(table_data)):
for j in range(4): for j in range(4):
cell = table[(i, j)] cell = table[(i, j)]
if i % 2 == 0: if i % 2 == 0:
cell.set_facecolor("#E7E6E6") cell.set_facecolor(palette["surface_alt_bg"])
else: else:
cell.set_facecolor("#FFFFFF") cell.set_facecolor(palette["card_bg"])
# 底部说明 # 底部说明
self.gamma_table_ax.text( self.gamma_table_ax.text(
@@ -246,25 +265,27 @@ def init_gamma_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=7, fontsize=7,
color="gray", color=palette["muted_fg"],
transform=self.gamma_table_ax.transAxes, transform=self.gamma_table_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=0.5", boxstyle="round,pad=0.5",
facecolor="lightyellow", facecolor=palette["surface_alt_bg"],
edgecolor="gray", edgecolor=palette["border"],
alpha=0.8, alpha=0.95,
), ),
) )
self.gamma_fig.suptitle("Gamma曲线 + 数据表格", fontsize=12, y=0.98) self.gamma_fig.suptitle("Gamma曲线 + 数据表格", fontsize=12, y=0.98, color=palette["fg"])
self.gamma_canvas.draw() self.gamma_canvas.draw()
def init_eotf_chart(self: "PQAutomationApp"): def init_eotf_chart(self: "PQAutomationApp"):
"""初始化 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)
palette = get_theme_palette()
self.eotf_fig = plt.Figure(figsize=(12, 6), dpi=100, constrained_layout=False) self.eotf_fig = plt.Figure(figsize=(12, 6), dpi=100, constrained_layout=False)
self.eotf_fig.patch.set_facecolor(palette["bg"])
self.eotf_canvas = FigureCanvasTkAgg(self.eotf_fig, master=container) self.eotf_canvas = FigureCanvasTkAgg(self.eotf_fig, master=container)
canvas_widget = self.eotf_canvas.get_tk_widget() canvas_widget = self.eotf_canvas.get_tk_widget()
@@ -272,6 +293,7 @@ def init_eotf_chart(self: "PQAutomationApp"):
# 左侧EOTF 曲线 # 左侧EOTF 曲线
self.eotf_ax = self.eotf_fig.add_axes([0.08, 0.12, 0.50, 0.78]) self.eotf_ax = self.eotf_fig.add_axes([0.08, 0.12, 0.50, 0.78])
_apply_axes_theme(self.eotf_ax, palette, xlabel="灰阶 (%)", ylabel="L_bar (归一化亮度)")
self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10) self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.eotf_ax.set_ylabel("L_bar (归一化亮度)", fontsize=10) self.eotf_ax.set_ylabel("L_bar (归一化亮度)", fontsize=10)
self.eotf_ax.set_xlim(0, 105) self.eotf_ax.set_xlim(0, 105)
@@ -287,10 +309,13 @@ def init_eotf_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="center", va="center",
fontsize=11, fontsize=11,
color="gray", color=palette["muted_fg"],
transform=self.eotf_ax.transAxes, transform=self.eotf_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=1", facecolor="white", edgecolor="gray", alpha=0.8 boxstyle="round,pad=1",
facecolor=palette["card_bg"],
edgecolor=palette["border"],
alpha=0.95,
), ),
) )
@@ -328,17 +353,17 @@ def init_eotf_chart(self: "PQAutomationApp"):
# 表头样式 # 表头样式
for i in range(4): for i in range(4):
cell = table[(0, i)] cell = table[(0, i)]
cell.set_facecolor("#4472C4") cell.set_facecolor(palette["primary"])
cell.set_text_props(weight="bold", color="white", fontsize=7) cell.set_text_props(weight="bold", color=palette["select_fg"], fontsize=7)
# 数据行交替颜色 # 数据行交替颜色
for i in range(1, len(table_data)): for i in range(1, len(table_data)):
for j in range(4): for j in range(4):
cell = table[(i, j)] cell = table[(i, j)]
if i % 2 == 0: if i % 2 == 0:
cell.set_facecolor("#E7E6E6") cell.set_facecolor(palette["surface_alt_bg"])
else: else:
cell.set_facecolor("#FFFFFF") cell.set_facecolor(palette["card_bg"])
# 底部说明 # 底部说明
self.eotf_table_ax.text( self.eotf_table_ax.text(
@@ -351,25 +376,27 @@ def init_eotf_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=7, fontsize=7,
color="gray", color=palette["muted_fg"],
transform=self.eotf_table_ax.transAxes, transform=self.eotf_table_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=0.5", boxstyle="round,pad=0.5",
facecolor="lightyellow", facecolor=palette["surface_alt_bg"],
edgecolor="gray", edgecolor=palette["border"],
alpha=0.8, alpha=0.95,
), ),
) )
self.eotf_fig.suptitle("EOTF 曲线 + 数据表格", fontsize=12, y=0.98) self.eotf_fig.suptitle("EOTF 曲线 + 数据表格", fontsize=12, y=0.98, color=palette["fg"])
self.eotf_canvas.draw() self.eotf_canvas.draw()
def init_cct_chart(self: "PQAutomationApp"): def init_cct_chart(self: "PQAutomationApp"):
"""初始化色度坐标图表 - 正向横坐标,标题居中最上方""" """初始化色度坐标图表 - 正向横坐标,标题居中最上方"""
container = ttk.Frame(self.cct_chart_frame) container = ttk.Frame(self.cct_chart_frame)
container.pack(expand=True) container.pack(expand=True)
palette = get_theme_palette()
self.cct_fig = plt.Figure(figsize=(8, 6), dpi=100, tight_layout=False) self.cct_fig = plt.Figure(figsize=(8, 6), dpi=100, tight_layout=False)
self.cct_fig.patch.set_facecolor(palette["bg"])
self.cct_canvas = FigureCanvasTkAgg(self.cct_fig, master=container) self.cct_canvas = FigureCanvasTkAgg(self.cct_fig, master=container)
canvas_widget = self.cct_canvas.get_tk_widget() canvas_widget = self.cct_canvas.get_tk_widget()
@@ -378,7 +405,9 @@ def init_cct_chart(self: "PQAutomationApp"):
canvas_widget.pack_propagate(False) canvas_widget.pack_propagate(False)
self.cct_ax1 = self.cct_fig.add_subplot(211) self.cct_ax1 = self.cct_fig.add_subplot(211)
self.cct_ax1.set_facecolor(palette["card_bg"])
self.cct_ax2 = self.cct_fig.add_subplot(212) self.cct_ax2 = self.cct_fig.add_subplot(212)
self.cct_ax2.set_facecolor(palette["card_bg"])
# 上图x coordinates # 上图x coordinates
self.cct_ax1.set_xlabel("灰阶 (%)", fontsize=9) self.cct_ax1.set_xlabel("灰阶 (%)", fontsize=9)
@@ -397,7 +426,7 @@ def init_cct_chart(self: "PQAutomationApp"):
self.cct_ax2.tick_params(labelsize=8) self.cct_ax2.tick_params(labelsize=8)
# 调整标题位置y=0.985(比色域/Gamma略高 # 调整标题位置y=0.985(比色域/Gamma略高
self.cct_fig.suptitle("色度一致性测试", fontsize=12, y=0.985) self.cct_fig.suptitle("色度一致性测试", fontsize=12, y=0.985, color=palette["fg"])
self.cct_fig.subplots_adjust( self.cct_fig.subplots_adjust(
left=0.12, left=0.12,
@@ -413,12 +442,14 @@ def init_contrast_chart(self: "PQAutomationApp"):
"""初始化对比度图表 - 固定大小,居中显示""" """初始化对比度图表 - 固定大小,居中显示"""
container = ttk.Frame(self.contrast_chart_frame) container = ttk.Frame(self.contrast_chart_frame)
container.pack(expand=True) container.pack(expand=True)
palette = get_theme_palette()
self.contrast_fig = plt.Figure( self.contrast_fig = plt.Figure(
figsize=(6, 6), figsize=(6, 6),
dpi=100, dpi=100,
tight_layout=False, tight_layout=False,
) )
self.contrast_fig.patch.set_facecolor(palette["bg"])
self.contrast_canvas = FigureCanvasTkAgg(self.contrast_fig, master=container) self.contrast_canvas = FigureCanvasTkAgg(self.contrast_fig, master=container)
canvas_widget = self.contrast_canvas.get_tk_widget() canvas_widget = self.contrast_canvas.get_tk_widget()
@@ -428,12 +459,13 @@ def init_contrast_chart(self: "PQAutomationApp"):
canvas_widget.pack_propagate(False) canvas_widget.pack_propagate(False)
self.contrast_ax = self.contrast_fig.add_subplot(111) self.contrast_ax = self.contrast_fig.add_subplot(111)
self.contrast_ax.set_facecolor(palette["card_bg"])
self.contrast_ax.set_xlim(0, 1) self.contrast_ax.set_xlim(0, 1)
self.contrast_ax.set_ylim(0, 1) self.contrast_ax.set_ylim(0, 1)
self.contrast_ax.axis("off") self.contrast_ax.axis("off")
# 调整标题位置y=0.985 # 调整标题位置y=0.985
self.contrast_fig.suptitle("对比度测试", fontsize=12, y=0.985) self.contrast_fig.suptitle("对比度测试", fontsize=12, y=0.985, color=palette["fg"])
self.contrast_fig.subplots_adjust( self.contrast_fig.subplots_adjust(
left=0.02, left=0.02,
@@ -448,6 +480,7 @@ def init_accuracy_chart(self: "PQAutomationApp"):
"""初始化色准图表 - 固定大小,居中显示""" """初始化色准图表 - 固定大小,居中显示"""
container = ttk.Frame(self.accuracy_chart_frame) container = ttk.Frame(self.accuracy_chart_frame)
container.pack(expand=True, fill=tk.BOTH) container.pack(expand=True, fill=tk.BOTH)
palette = get_theme_palette()
container.grid_rowconfigure(0, weight=1) container.grid_rowconfigure(0, weight=1)
container.grid_rowconfigure(1, weight=0, minsize=220) container.grid_rowconfigure(1, weight=0, minsize=220)
container.grid_columnconfigure(0, weight=1) container.grid_columnconfigure(0, weight=1)
@@ -464,18 +497,27 @@ def init_accuracy_chart(self: "PQAutomationApp"):
dpi=100, dpi=100,
tight_layout=False, tight_layout=False,
) )
self.accuracy_fig.patch.set_facecolor(palette["bg"])
try:
self.accuracy_fig.set_layout_engine(None)
except Exception:
try:
self.accuracy_fig.set_tight_layout(False)
except Exception:
pass
self.accuracy_canvas = FigureCanvasTkAgg(self.accuracy_fig, master=plot_container) self.accuracy_canvas = FigureCanvasTkAgg(self.accuracy_fig, master=plot_container)
canvas_widget = self.accuracy_canvas.get_tk_widget() canvas_widget = self.accuracy_canvas.get_tk_widget()
canvas_widget.pack(fill=tk.BOTH, expand=True) canvas_widget.pack(fill=tk.BOTH, expand=True)
self.accuracy_ax = self.accuracy_fig.add_subplot(111) self.accuracy_ax = self.accuracy_fig.add_subplot(111)
self.accuracy_ax.set_facecolor(palette["card_bg"])
self.accuracy_ax.set_xlim(0, 1) self.accuracy_ax.set_xlim(0, 1)
self.accuracy_ax.set_ylim(0, 1) self.accuracy_ax.set_ylim(0, 1)
self.accuracy_ax.axis("off") self.accuracy_ax.axis("off")
# 调整标题位置 # 调整标题位置
self.accuracy_fig.suptitle("色准测试", fontsize=12, y=0.985) self.accuracy_fig.suptitle("色准测试", fontsize=12, y=0.985, color=palette["fg"])
self.accuracy_fig.subplots_adjust( self.accuracy_fig.subplots_adjust(
left=0.05, left=0.05,
@@ -616,6 +658,7 @@ def update_accuracy_result_table(self: "PQAutomationApp", accuracy_data, standar
def clear_chart(self: "PQAutomationApp"): def clear_chart(self: "PQAutomationApp"):
"""清空所有图表""" """清空所有图表"""
palette = get_theme_palette()
# ========== 1. 清空色域图表 ========== # ========== 1. 清空色域图表 ==========
if hasattr(self, "gamut_ax_xy") and hasattr(self, "gamut_ax_uv"): if hasattr(self, "gamut_ax_xy") and hasattr(self, "gamut_ax_uv"):
@@ -640,12 +683,17 @@ def clear_chart(self: "PQAutomationApp"):
if hasattr(self, "gamma_ax") and hasattr(self, "gamma_table_ax"): if hasattr(self, "gamma_ax") and hasattr(self, "gamma_table_ax"):
# 清空左侧曲线 # 清空左侧曲线
self.gamma_ax.clear() self.gamma_ax.clear()
self.gamma_fig.patch.set_facecolor(palette["bg"])
self.gamma_ax.set_facecolor(palette["card_bg"])
self.gamma_ax.set_xlim(0, 105) self.gamma_ax.set_xlim(0, 105)
self.gamma_ax.set_ylim(0, 1.1) self.gamma_ax.set_ylim(0, 1.1)
self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10) self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.gamma_ax.set_ylabel("L_bar", fontsize=10) self.gamma_ax.set_ylabel("L_bar", fontsize=10)
self.gamma_ax.grid(True, linestyle="--", alpha=0.3) self.gamma_ax.grid(True, linestyle="--", alpha=0.3)
self.gamma_ax.tick_params(labelsize=9) self.gamma_ax.tick_params(labelsize=9)
self.gamma_ax.tick_params(colors=palette["fg"])
for spine in self.gamma_ax.spines.values():
spine.set_color(palette["border"])
# 左侧提示 # 左侧提示
self.gamma_ax.text( self.gamma_ax.text(
@@ -659,13 +707,13 @@ def clear_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="center", va="center",
fontsize=10, fontsize=10,
color="gray", color=palette["muted_fg"],
transform=self.gamma_ax.transAxes, transform=self.gamma_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=1", boxstyle="round,pad=1",
facecolor="white", facecolor=palette["card_bg"],
edgecolor="gray", edgecolor=palette["border"],
alpha=0.8, alpha=0.95,
), ),
) )
@@ -703,17 +751,17 @@ def clear_chart(self: "PQAutomationApp"):
# 表头样式 # 表头样式
for i in range(4): for i in range(4):
cell = table[(0, i)] cell = table[(0, i)]
cell.set_facecolor("#4472C4") cell.set_facecolor(palette["primary"])
cell.set_text_props(weight="bold", color="white", fontsize=7) cell.set_text_props(weight="bold", color=palette["select_fg"], fontsize=7)
# 数据行交替颜色 # 数据行交替颜色
for i in range(1, len(table_data)): for i in range(1, len(table_data)):
for j in range(4): for j in range(4):
cell = table[(i, j)] cell = table[(i, j)]
if i % 2 == 0: if i % 2 == 0:
cell.set_facecolor("#E7E6E6") cell.set_facecolor(palette["surface_alt_bg"])
else: else:
cell.set_facecolor("#FFFFFF") cell.set_facecolor(palette["card_bg"])
# 底部说明 # 底部说明
self.gamma_table_ax.text( self.gamma_table_ax.text(
@@ -726,29 +774,34 @@ def clear_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=7, fontsize=7,
color="gray", color=palette["muted_fg"],
transform=self.gamma_table_ax.transAxes, transform=self.gamma_table_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=0.5", boxstyle="round,pad=0.5",
facecolor="lightyellow", facecolor=palette["surface_alt_bg"],
edgecolor="gray", edgecolor=palette["border"],
alpha=0.8, alpha=0.95,
), ),
) )
self.gamma_fig.suptitle("Gamma曲线 + 数据表格", fontsize=12, y=0.98) self.gamma_fig.suptitle("Gamma曲线 + 数据表格", fontsize=12, y=0.98, color=palette["fg"])
self.gamma_canvas.draw() self.gamma_canvas.draw()
# ========== 3. 清空EOTF图表4列========== # ========== 3. 清空EOTF图表4列==========
if hasattr(self, "eotf_ax") and hasattr(self, "eotf_table_ax"): if hasattr(self, "eotf_ax") and hasattr(self, "eotf_table_ax"):
# 清空左侧曲线 # 清空左侧曲线
self.eotf_ax.clear() self.eotf_ax.clear()
self.eotf_fig.patch.set_facecolor(palette["bg"])
self.eotf_ax.set_facecolor(palette["card_bg"])
self.eotf_ax.set_xlim(0, 105) self.eotf_ax.set_xlim(0, 105)
self.eotf_ax.set_ylim(0, 1.1) self.eotf_ax.set_ylim(0, 1.1)
self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10) self.eotf_ax.set_xlabel("灰阶 (%)", fontsize=10)
self.eotf_ax.set_ylabel("L_bar (归一化亮度)", fontsize=10) self.eotf_ax.set_ylabel("L_bar (归一化亮度)", fontsize=10)
self.eotf_ax.grid(True, linestyle="--", alpha=0.3) self.eotf_ax.grid(True, linestyle="--", alpha=0.3)
self.eotf_ax.tick_params(labelsize=9) self.eotf_ax.tick_params(labelsize=9)
self.eotf_ax.tick_params(colors=palette["fg"])
for spine in self.eotf_ax.spines.values():
spine.set_color(palette["border"])
# 左侧提示 # 左侧提示
self.eotf_ax.text( self.eotf_ax.text(
@@ -758,13 +811,13 @@ def clear_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="center", va="center",
fontsize=11, fontsize=11,
color="gray", color=palette["muted_fg"],
transform=self.eotf_ax.transAxes, transform=self.eotf_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=1", boxstyle="round,pad=1",
facecolor="white", facecolor=palette["card_bg"],
edgecolor="gray", edgecolor=palette["border"],
alpha=0.8, alpha=0.95,
), ),
) )
@@ -802,17 +855,17 @@ def clear_chart(self: "PQAutomationApp"):
# 表头样式 # 表头样式
for i in range(4): for i in range(4):
cell = table[(0, i)] cell = table[(0, i)]
cell.set_facecolor("#4472C4") cell.set_facecolor(palette["primary"])
cell.set_text_props(weight="bold", color="white", fontsize=7) cell.set_text_props(weight="bold", color=palette["select_fg"], fontsize=7)
# 数据行交替颜色 # 数据行交替颜色
for i in range(1, len(table_data)): for i in range(1, len(table_data)):
for j in range(4): for j in range(4):
cell = table[(i, j)] cell = table[(i, j)]
if i % 2 == 0: if i % 2 == 0:
cell.set_facecolor("#E7E6E6") cell.set_facecolor(palette["surface_alt_bg"])
else: else:
cell.set_facecolor("#FFFFFF") cell.set_facecolor(palette["card_bg"])
# 底部说明 # 底部说明
self.eotf_table_ax.text( self.eotf_table_ax.text(
@@ -825,17 +878,17 @@ def clear_chart(self: "PQAutomationApp"):
ha="center", ha="center",
va="bottom", va="bottom",
fontsize=7, fontsize=7,
color="gray", color=palette["muted_fg"],
transform=self.eotf_table_ax.transAxes, transform=self.eotf_table_ax.transAxes,
bbox=dict( bbox=dict(
boxstyle="round,pad=0.5", boxstyle="round,pad=0.5",
facecolor="lightyellow", facecolor=palette["surface_alt_bg"],
edgecolor="gray", edgecolor=palette["border"],
alpha=0.8, alpha=0.95,
), ),
) )
self.eotf_fig.suptitle("EOTF 曲线 + 数据表格", fontsize=12, y=0.98) self.eotf_fig.suptitle("EOTF 曲线 + 数据表格", fontsize=12, y=0.98, color=palette["fg"])
self.eotf_canvas.draw() self.eotf_canvas.draw()
# ========== 4. 清空色度图表 ========== # ========== 4. 清空色度图表 ==========
@@ -843,8 +896,10 @@ def clear_chart(self: "PQAutomationApp"):
# 过期引用。因此清空时必须同样重建,并更新引用,否则清不干净。 # 过期引用。因此清空时必须同样重建,并更新引用,否则清不干净。
if hasattr(self, "cct_fig") and hasattr(self, "cct_canvas"): if hasattr(self, "cct_fig") and hasattr(self, "cct_canvas"):
self.cct_fig.clear() self.cct_fig.clear()
self.cct_fig.patch.set_facecolor(palette["bg"])
self.cct_ax1 = self.cct_fig.add_subplot(211) self.cct_ax1 = self.cct_fig.add_subplot(211)
self.cct_ax1.set_facecolor(palette["card_bg"])
self.cct_ax1.set_xlabel("灰阶 (%)", fontsize=9) self.cct_ax1.set_xlabel("灰阶 (%)", fontsize=9)
self.cct_ax1.set_ylabel("CIE x", fontsize=9) self.cct_ax1.set_ylabel("CIE x", fontsize=9)
self.cct_ax1.set_xlim(0, 105) self.cct_ax1.set_xlim(0, 105)
@@ -853,6 +908,7 @@ def clear_chart(self: "PQAutomationApp"):
self.cct_ax1.tick_params(labelsize=8) self.cct_ax1.tick_params(labelsize=8)
self.cct_ax2 = self.cct_fig.add_subplot(212) self.cct_ax2 = self.cct_fig.add_subplot(212)
self.cct_ax2.set_facecolor(palette["card_bg"])
self.cct_ax2.set_xlabel("灰阶 (%)", fontsize=9) self.cct_ax2.set_xlabel("灰阶 (%)", fontsize=9)
self.cct_ax2.set_ylabel("CIE y", fontsize=9) self.cct_ax2.set_ylabel("CIE y", fontsize=9)
self.cct_ax2.set_xlim(0, 105) self.cct_ax2.set_xlim(0, 105)
@@ -860,7 +916,7 @@ def clear_chart(self: "PQAutomationApp"):
self.cct_ax2.grid(True, linestyle="--", alpha=0.3) self.cct_ax2.grid(True, linestyle="--", alpha=0.3)
self.cct_ax2.tick_params(labelsize=8) self.cct_ax2.tick_params(labelsize=8)
self.cct_fig.suptitle("色度一致性测试", fontsize=12, y=0.985) self.cct_fig.suptitle("色度一致性测试", fontsize=12, y=0.985, color=palette["fg"])
self.cct_fig.subplots_adjust( self.cct_fig.subplots_adjust(
left=0.12, left=0.12,
right=0.88, right=0.88,
@@ -873,11 +929,13 @@ def clear_chart(self: "PQAutomationApp"):
# ========== 5. 清空对比度图表 ========== # ========== 5. 清空对比度图表 ==========
if hasattr(self, "contrast_ax"): if hasattr(self, "contrast_ax"):
self.contrast_ax.clear() self.contrast_ax.clear()
self.contrast_fig.patch.set_facecolor(palette["bg"])
self.contrast_ax.set_facecolor(palette["card_bg"])
self.contrast_ax.set_xlim(0, 1) self.contrast_ax.set_xlim(0, 1)
self.contrast_ax.set_ylim(0, 1) self.contrast_ax.set_ylim(0, 1)
self.contrast_ax.axis("off") self.contrast_ax.axis("off")
self.contrast_fig.suptitle("对比度测试", fontsize=12, y=0.985) self.contrast_fig.suptitle("对比度测试", fontsize=12, y=0.985, color=palette["fg"])
# 重置布局 # 重置布局
self.contrast_fig.subplots_adjust( self.contrast_fig.subplots_adjust(
@@ -892,12 +950,14 @@ def clear_chart(self: "PQAutomationApp"):
# ========== 6. 清空色准图表 ========== # ========== 6. 清空色准图表 ==========
if hasattr(self, "accuracy_ax"): if hasattr(self, "accuracy_ax"):
self.accuracy_ax.clear() self.accuracy_ax.clear()
self.accuracy_fig.patch.set_facecolor(palette["bg"])
self.accuracy_ax.set_facecolor(palette["card_bg"])
self.accuracy_ax.set_xlim(0, 1) self.accuracy_ax.set_xlim(0, 1)
self.accuracy_ax.set_ylim(0, 1) self.accuracy_ax.set_ylim(0, 1)
self.accuracy_ax.axis("off") self.accuracy_ax.axis("off")
# 标题 # 标题
self.accuracy_fig.suptitle("色准测试", fontsize=12, y=0.985) self.accuracy_fig.suptitle("色准测试", fontsize=12, y=0.985, color=palette["fg"])
# 重置布局 # 重置布局
self.accuracy_fig.subplots_adjust( self.accuracy_fig.subplots_adjust(

View File

@@ -600,7 +600,6 @@ def create_connection_content(self: "PQAutomationApp"):
com_frame, width=15, height=15, bg="gray", highlightthickness=0 com_frame, width=15, height=15, bg="gray", highlightthickness=0
) )
self.ucd_status_indicator.grid(row=0, column=2, padx=(10, 20)) self.ucd_status_indicator.grid(row=0, column=2, padx=(10, 20))
self.ucd_status_indicator.config(bg="gray")
# 添加按钮框架 # 添加按钮框架
button_frame = ttk.Frame(com_frame) button_frame = ttk.Frame(com_frame)
@@ -669,7 +668,8 @@ def create_connection_content(self: "PQAutomationApp"):
com_frame, width=15, height=15, bg="gray", highlightthickness=0 com_frame, width=15, height=15, bg="gray", highlightthickness=0
) )
self.ca_status_indicator.grid(row=1, column=2, padx=(10, 20)) self.ca_status_indicator.grid(row=1, column=2, padx=(10, 20))
self.ca_status_indicator.config(bg="gray")
self.refresh_connection_indicators()
# 添加CA通道设置 # 添加CA通道设置
ttk.Label(com_frame, text="CA通道:").grid( ttk.Label(com_frame, text="CA通道:").grid(
@@ -808,6 +808,11 @@ def _on_toggle_theme(self: "PQAutomationApp") -> None:
toggle_theme() toggle_theme()
# apply_modern_styles() # apply_modern_styles()
_refresh_theme_toggle_label(self) _refresh_theme_toggle_label(self)
if hasattr(self, "refresh_connection_indicators"):
try:
self.refresh_connection_indicators()
except Exception:
pass
if hasattr(self, "apply_result_chart_theme"): if hasattr(self, "apply_result_chart_theme"):
try: try:
self.apply_result_chart_theme() self.apply_result_chart_theme()

View File

@@ -6,6 +6,7 @@ import time
import os import os
import datetime import datetime
import traceback import traceback
import matplotlib
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from app_version import APP_NAME, APP_VERSION, get_app_title from app_version import APP_NAME, APP_VERSION, get_app_title
from drivers.UCD323_Function import UCDController from drivers.UCD323_Function import UCDController
@@ -62,7 +63,6 @@ from app.runner.test_runner import TestRunnerMixin
plt.rcParams["font.family"] = ["sans-serif"] plt.rcParams["font.family"] = ["sans-serif"]
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"] plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
class PQAutomationApp( class PQAutomationApp(
ConfigIOMixin, ConfigIOMixin,
ChartFrameMixin, ChartFrameMixin,
@@ -431,6 +431,11 @@ class PQAutomationApp(
# 更新测试项目和侧边栏 # 更新测试项目和侧边栏
self.update_test_items() self.update_test_items()
if hasattr(self, "refresh_connection_indicators"):
try:
self.refresh_connection_indicators()
except Exception:
pass
self.update_sidebar_selection() self.update_sidebar_selection()
self.on_test_type_change() self.on_test_type_change()
self._switch_signal_format_tabs(test_type) self._switch_signal_format_tabs(test_type)

View File

@@ -1,10 +1,13 @@
{ {
"current_test_type": "sdr_movie", "current_test_type": "screen_module",
"test_types": { "test_types": {
"screen_module": { "screen_module": {
"name": "屏模组性能测试", "name": "屏模组性能测试",
"test_items": [ "test_items": [
"gamma" "gamut",
"gamma",
"cct",
"contrast"
], ],
"timing": "DMT 1920x 1080 @ 60Hz", "timing": "DMT 1920x 1080 @ 60Hz",
"data_range": "Full", "data_range": "Full",
@@ -51,7 +54,7 @@
"y_ideal": 0.329, "y_ideal": 0.329,
"y_tolerance": 0.003 "y_tolerance": 0.003
}, },
"gamut_reference": "BT.709" "gamut_reference": "BT.601"
}, },
"hdr_movie": { "hdr_movie": {
"name": "HDR Movie测试", "name": "HDR Movie测试",