修改Calman灰阶中结果图显示、修改UI主题样式应用
This commit is contained in:
@@ -272,6 +272,49 @@ def disconnect_com_connections(self: "PQAutomationApp"):
|
|||||||
self.connection.disconnect_all()
|
self.connection.disconnect_all()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_ca_measure_lock(self: "PQAutomationApp"):
|
||||||
|
lock = getattr(self, "_ca_measure_lock", None)
|
||||||
|
if lock is None:
|
||||||
|
lock = threading.RLock()
|
||||||
|
self._ca_measure_lock = lock
|
||||||
|
return lock
|
||||||
|
|
||||||
|
|
||||||
|
def _read_ca_display(self: "PQAutomationApp", mode: int):
|
||||||
|
"""在锁内切换 CA410 Display 模式并立即读取,避免模式串扰。"""
|
||||||
|
if getattr(self, "ca", None) is None:
|
||||||
|
raise RuntimeError("请先连接 CA410 色度计")
|
||||||
|
|
||||||
|
with _get_ca_measure_lock(self):
|
||||||
|
self.ca.set_Display(mode)
|
||||||
|
return self.ca.readAllDisplay()
|
||||||
|
|
||||||
|
|
||||||
|
def read_ca_xyLv(self: "PQAutomationApp"):
|
||||||
|
"""读取 xy/Lv/XYZ(Display 0)。"""
|
||||||
|
return _read_ca_display(self, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def read_ca_tcp_duv(self: "PQAutomationApp"):
|
||||||
|
"""读取 Tcp/duv/Lv/XYZ(Display 1)。"""
|
||||||
|
return _read_ca_display(self, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def read_ca_uvLv(self: "PQAutomationApp"):
|
||||||
|
"""读取 u'/v'/Lv/XYZ(Display 5)。"""
|
||||||
|
return _read_ca_display(self, 5)
|
||||||
|
|
||||||
|
|
||||||
|
def read_ca_xyz(self: "PQAutomationApp"):
|
||||||
|
"""读取 XYZ(Display 7)。"""
|
||||||
|
return _read_ca_display(self, 7)
|
||||||
|
|
||||||
|
|
||||||
|
def read_ca_lambda_pe(self: "PQAutomationApp"):
|
||||||
|
"""读取 λd/Pe/Lv/XYZ(Display 8)。"""
|
||||||
|
return _read_ca_display(self, 8)
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"ConnectionController",
|
"ConnectionController",
|
||||||
# 兼容层
|
# 兼容层
|
||||||
@@ -298,3 +341,10 @@ class DeviceConnectionMixin:
|
|||||||
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
|
||||||
|
_get_ca_measure_lock = _get_ca_measure_lock
|
||||||
|
_read_ca_display = _read_ca_display
|
||||||
|
read_ca_xyLv = read_ca_xyLv
|
||||||
|
read_ca_tcp_duv = read_ca_tcp_duv
|
||||||
|
read_ca_uvLv = read_ca_uvLv
|
||||||
|
read_ca_xyz = read_ca_xyz
|
||||||
|
read_ca_lambda_pe = read_ca_lambda_pe
|
||||||
|
|||||||
@@ -394,8 +394,7 @@ def send_fix_pattern(self: "PQAutomationApp", mode):
|
|||||||
# 测量数据
|
# 测量数据
|
||||||
if mode == "custom":
|
if mode == "custom":
|
||||||
result = []
|
result = []
|
||||||
self.ca.set_Display(1)
|
tcp, duv, lv, X, Y, Z = self.read_ca_tcp_duv()
|
||||||
tcp, duv, lv, X, Y, Z = self.ca.readAllDisplay()
|
|
||||||
|
|
||||||
if should_log_detail:
|
if should_log_detail:
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
@@ -403,8 +402,7 @@ def send_fix_pattern(self: "PQAutomationApp", mode):
|
|||||||
f"X={X:.4f}, Y={Y:.4f}, Z={Z:.4f}"
|
f"X={X:.4f}, Y={Y:.4f}, Z={Z:.4f}"
|
||||||
, level="success")
|
, level="success")
|
||||||
|
|
||||||
self.ca.set_Display(8)
|
lambda_, Pe, lv, X, Y, Z = self.read_ca_lambda_pe()
|
||||||
lambda_, Pe, lv, X, Y, Z = self.ca.readAllDisplay()
|
|
||||||
|
|
||||||
if should_log_detail:
|
if should_log_detail:
|
||||||
self.log_gui.log(
|
self.log_gui.log(
|
||||||
@@ -449,9 +447,7 @@ def send_fix_pattern(self: "PQAutomationApp", mode):
|
|||||||
self.log_gui.log(f"第 {i+1} 行实时结果写入失败: {str(e)}", level="error")
|
self.log_gui.log(f"第 {i+1} 行实时结果写入失败: {str(e)}", level="error")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.ca.set_xyLv_Display()
|
x, y, lv, X, Y, Z = self.read_ca_xyLv()
|
||||||
|
|
||||||
x, y, lv, X, Y, Z = self.ca.readAllDisplay()
|
|
||||||
results.append([x, y, lv, X, Y, Z])
|
results.append([x, y, lv, X, Y, Z])
|
||||||
|
|
||||||
if should_log_detail:
|
if should_log_detail:
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ def _build_ld_result_row(test_item, pattern_label, value, x="--", y="--"):
|
|||||||
|
|
||||||
def _measure_ld_row(self: "PQAutomationApp", test_item, pattern_label):
|
def _measure_ld_row(self: "PQAutomationApp", test_item, pattern_label):
|
||||||
"""读取一次 CA410 数据并包装为表格行。"""
|
"""读取一次 CA410 数据并包装为表格行。"""
|
||||||
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
x, y, lv, _X, _Y, _Z = self.read_ca_xyLv()
|
||||||
if lv is None:
|
if lv is None:
|
||||||
raise RuntimeError(f"{pattern_label} 采集失败")
|
raise RuntimeError(f"{pattern_label} 采集失败")
|
||||||
return _build_ld_result_row(test_item, pattern_label, lv, x, y), lv
|
return _build_ld_result_row(test_item, pattern_label, lv, x, y), lv
|
||||||
@@ -549,7 +549,7 @@ def measure_ld_luminance(self: "PQAutomationApp"):
|
|||||||
|
|
||||||
def measure():
|
def measure():
|
||||||
try:
|
try:
|
||||||
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
x, y, lv, _X, _Y, _Z = self.read_ca_xyLv()
|
||||||
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"采集异常: {str(e)}")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -36,37 +36,188 @@ def _is_dark(color: str) -> bool:
|
|||||||
return (r * 299 + g * 587 + b * 114) / 1000 < 128
|
return (r * 299 + g * 587 + b * 114) / 1000 < 128
|
||||||
|
|
||||||
|
|
||||||
def apply_modern_styles() -> None:
|
def _contrast_text(color: str, *, dark_text: str, light_text: str) -> str:
|
||||||
"""注册或刷新现代化样式集。可在主题切换后再次调用。"""
|
return dark_text if _is_dark(color) else light_text
|
||||||
style = ttk.Style()
|
|
||||||
theme = style.colors # ttkbootstrap.style.Colors
|
|
||||||
|
|
||||||
bg = theme.bg # 主背景
|
|
||||||
fg = theme.fg # 主前景
|
def get_theme_palette() -> dict[str, str]:
|
||||||
|
"""返回当前主题的语义色板,供 ttk / tk 自定义控件共用。"""
|
||||||
|
style = ttk.Style()
|
||||||
|
theme = style.colors
|
||||||
|
|
||||||
|
bg = theme.bg
|
||||||
|
fg = theme.fg
|
||||||
primary = theme.primary
|
primary = theme.primary
|
||||||
secondary = theme.secondary
|
secondary = theme.secondary
|
||||||
|
success = theme.success
|
||||||
info = theme.info
|
info = theme.info
|
||||||
|
warning = theme.warning
|
||||||
|
danger = theme.danger
|
||||||
dark = theme.dark
|
dark = theme.dark
|
||||||
border = theme.border
|
border = theme.border
|
||||||
inputbg = theme.inputbg
|
inputbg = theme.inputbg
|
||||||
|
inputfg = getattr(theme, "inputfg", fg)
|
||||||
|
|
||||||
dark_theme = _is_dark(bg)
|
dark_theme = _is_dark(bg)
|
||||||
|
select_bg = getattr(theme, "selectbg", _mix(primary, bg, 0.30 if dark_theme else 0.12))
|
||||||
|
select_fg = getattr(theme, "selectfg", "#ffffff" if _is_dark(select_bg) else fg)
|
||||||
|
|
||||||
# 卡片背景:在主背景上轻微偏移,营造层级感
|
if dark_theme:
|
||||||
card_bg = _mix(bg, "#ffffff", 0.04) if dark_theme else _mix(bg, "#000000", 0.025)
|
card_bg = _mix(bg, "#ffffff", 0.04)
|
||||||
card_border = _mix(bg, fg, 0.18) if dark_theme else _mix(bg, "#000000", 0.10)
|
card_border = _mix(bg, fg, 0.18)
|
||||||
# 配置项 header 用 secondary 主题色
|
header_fg = _contrast_text(
|
||||||
header_bg = secondary
|
"#444A51",
|
||||||
header_fg = "#ffffff" if _is_dark(secondary) else "#1a1a1a"
|
dark_text="#ffffff",
|
||||||
header_hover_bg = _mix(secondary, "#ffffff", 0.08) if _is_dark(secondary) else _mix(secondary, "#000000", 0.08)
|
light_text="#1a1a1a",
|
||||||
|
)
|
||||||
preview_fg = _mix(header_fg, header_bg, 0.35)
|
sidebar_bg = _mix(dark, bg, 0.18)
|
||||||
sidebar_bg = _mix(dark, bg, 0.18) if dark_theme else _mix(primary, "#000000", 0.10)
|
sidebar_hover = _mix(sidebar_bg, "#ffffff", 0.07)
|
||||||
sidebar_hover = _mix(sidebar_bg, "#ffffff", 0.07) if dark_theme else _mix(sidebar_bg, "#000000", 0.06)
|
sidebar_selected = _mix(sidebar_bg, "#ffffff", 0.14)
|
||||||
sidebar_selected = _mix(sidebar_bg, "#ffffff", 0.14) if dark_theme else _mix(sidebar_bg, "#000000", 0.10)
|
sidebar_fg = _mix(fg, "#ffffff", 0.04)
|
||||||
# 侧栏背景在浅色主题下也偏深,文字颜色需按侧栏亮度自适应,避免“黑字不明显”。
|
|
||||||
sidebar_fg = "#F4F8FD" if _is_dark(sidebar_bg) else _mix(fg, bg, 0.05)
|
|
||||||
sidebar_muted = _mix(sidebar_fg, sidebar_bg, 0.45)
|
sidebar_muted = _mix(sidebar_fg, sidebar_bg, 0.45)
|
||||||
|
muted_fg = _mix(fg, bg, 0.32)
|
||||||
|
disabled_fg = _mix(fg, bg, 0.42)
|
||||||
|
disabled_bg = _mix(inputbg, bg, 0.18)
|
||||||
|
disabled_border = _mix(border, fg, 0.22)
|
||||||
|
readonly_bg = _mix(inputbg, "#ffffff", 0.06)
|
||||||
|
success_fg = _mix(success, "#ffffff", 0.08)
|
||||||
|
warning_fg = _mix(warning, "#ffffff", 0.06)
|
||||||
|
info_fg = _mix(info, "#ffffff", 0.06)
|
||||||
|
statusbar_bg = _mix(bg, "#ffffff", 0.06)
|
||||||
|
tooltip_bg = _mix(inputbg, bg, 0.08)
|
||||||
|
tooltip_fg = inputfg
|
||||||
|
tooltip_border = _mix(border, fg, 0.20)
|
||||||
|
surface_alt_bg = _mix(card_bg, "#ffffff", 0.05)
|
||||||
|
surface_hover_bg = _mix(card_bg, "#ffffff", 0.09)
|
||||||
|
badge_bg = _mix(danger, bg, 0.12)
|
||||||
|
badge_fg = "#ffffff"
|
||||||
|
focus = _mix(primary, "#ffffff", 0.18)
|
||||||
|
config_bg = _mix("#444A51", bg, 0.30)
|
||||||
|
else:
|
||||||
|
card_bg = inputbg
|
||||||
|
card_border = border
|
||||||
|
header_fg = bg
|
||||||
|
config_bg = _mix(primary, bg, 0.25)
|
||||||
|
sidebar_bg = _mix(primary, bg, 0.82)
|
||||||
|
sidebar_hover = _mix(primary, bg, 0.72)
|
||||||
|
sidebar_selected = primary
|
||||||
|
sidebar_fg = fg
|
||||||
|
sidebar_muted = _mix(fg, sidebar_bg, 0.35)
|
||||||
|
muted_fg = _mix(fg, bg, 0.38)
|
||||||
|
disabled_fg = _mix(fg, bg, 0.55)
|
||||||
|
disabled_bg = _mix(bg, border, 0.18)
|
||||||
|
disabled_border = _mix(border, bg, 0.18)
|
||||||
|
readonly_bg = _mix(inputbg, primary, 0.04)
|
||||||
|
success_fg = success
|
||||||
|
warning_fg = _mix(warning, fg, 0.18)
|
||||||
|
info_fg = info
|
||||||
|
statusbar_bg = _mix(bg, dark, 0.04)
|
||||||
|
tooltip_bg = inputbg
|
||||||
|
tooltip_fg = inputfg
|
||||||
|
tooltip_border = border
|
||||||
|
surface_alt_bg = _mix(bg, dark, 0.03)
|
||||||
|
surface_hover_bg = _mix(bg, dark, 0.05)
|
||||||
|
badge_bg = danger
|
||||||
|
badge_fg = "#ffffff"
|
||||||
|
focus = _mix(primary, bg, 0.20)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"bg": bg,
|
||||||
|
"fg": fg,
|
||||||
|
"primary": primary,
|
||||||
|
"secondary": secondary,
|
||||||
|
"success": success,
|
||||||
|
"info": info,
|
||||||
|
"warning": warning,
|
||||||
|
"danger": danger,
|
||||||
|
"border": border,
|
||||||
|
"input_bg": inputbg,
|
||||||
|
"input_fg": inputfg,
|
||||||
|
"select_bg": select_bg,
|
||||||
|
"select_fg": select_fg,
|
||||||
|
"card_bg": card_bg,
|
||||||
|
"card_border": card_border,
|
||||||
|
"header_fg": header_fg,
|
||||||
|
"sidebar_bg": sidebar_bg,
|
||||||
|
"sidebar_hover": sidebar_hover,
|
||||||
|
"sidebar_selected": sidebar_selected,
|
||||||
|
"sidebar_fg": sidebar_fg,
|
||||||
|
"sidebar_muted": sidebar_muted,
|
||||||
|
"muted_fg": muted_fg,
|
||||||
|
"disabled_fg": disabled_fg,
|
||||||
|
"disabled_bg": disabled_bg,
|
||||||
|
"disabled_border": disabled_border,
|
||||||
|
"readonly_bg": readonly_bg,
|
||||||
|
"success_fg": success_fg,
|
||||||
|
"warning_fg": warning_fg,
|
||||||
|
"info_fg": info_fg,
|
||||||
|
"statusbar_bg": statusbar_bg,
|
||||||
|
"tooltip_bg": tooltip_bg,
|
||||||
|
"tooltip_fg": tooltip_fg,
|
||||||
|
"tooltip_border": tooltip_border,
|
||||||
|
"surface_alt_bg": surface_alt_bg,
|
||||||
|
"surface_hover_bg": surface_hover_bg,
|
||||||
|
"badge_bg": badge_bg,
|
||||||
|
"badge_fg": badge_fg,
|
||||||
|
"focus": focus,
|
||||||
|
"config_bg": config_bg,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def apply_listbox_theme(widget) -> None:
|
||||||
|
"""将 tk.Listbox 颜色同步到当前主题。"""
|
||||||
|
palette = get_theme_palette()
|
||||||
|
widget.configure(
|
||||||
|
background=palette["input_bg"],
|
||||||
|
foreground=palette["input_fg"],
|
||||||
|
highlightbackground=palette["border"],
|
||||||
|
highlightcolor=palette["focus"],
|
||||||
|
selectbackground=palette["select_bg"],
|
||||||
|
selectforeground=palette["select_fg"],
|
||||||
|
disabledforeground=palette["disabled_fg"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def apply_tooltip_theme(toplevel, label) -> None:
|
||||||
|
"""将 tooltip 的 tk.Toplevel / Label 同步到当前主题。"""
|
||||||
|
palette = get_theme_palette()
|
||||||
|
toplevel.configure(background=palette["tooltip_border"])
|
||||||
|
label.configure(
|
||||||
|
bg=palette["tooltip_bg"],
|
||||||
|
fg=palette["tooltip_fg"],
|
||||||
|
highlightbackground=palette["tooltip_border"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def apply_modern_styles() -> None:
|
||||||
|
"""注册或刷新现代化样式集。可在主题切换后再次调用。"""
|
||||||
|
style = ttk.Style()
|
||||||
|
palette = get_theme_palette()
|
||||||
|
|
||||||
|
bg = palette["bg"]
|
||||||
|
fg = palette["fg"]
|
||||||
|
primary = palette["primary"]
|
||||||
|
secondary = palette["secondary"]
|
||||||
|
info = palette["info"]
|
||||||
|
card_bg = palette["card_bg"]
|
||||||
|
card_border = palette["card_border"]
|
||||||
|
header_bg = palette["config_bg"]
|
||||||
|
header_fg = palette["header_fg"]
|
||||||
|
dark_theme = _is_dark(bg)
|
||||||
|
header_hover_bg = _mix(secondary, "#ffffff", 0.08) if _is_dark(secondary) else _mix(secondary, "#000000", 0.08)
|
||||||
|
preview_fg = _mix(header_fg, header_bg, 0.35)
|
||||||
|
sidebar_bg = palette["sidebar_bg"]
|
||||||
|
sidebar_hover = palette["sidebar_hover"]
|
||||||
|
sidebar_selected = palette["sidebar_selected"]
|
||||||
|
sidebar_fg = palette["sidebar_fg"]
|
||||||
|
sidebar_muted = palette["sidebar_muted"]
|
||||||
|
muted_fg = palette["muted_fg"]
|
||||||
|
disabled_fg = palette["disabled_fg"]
|
||||||
|
disabled_bg = palette["disabled_bg"]
|
||||||
|
disabled_border = palette["disabled_border"]
|
||||||
|
readonly_bg = palette["readonly_bg"]
|
||||||
|
success_fg = palette["success_fg"]
|
||||||
|
warning_fg = palette["warning_fg"]
|
||||||
|
|
||||||
# ---------------- 卡片 ----------------
|
# ---------------- 卡片 ----------------
|
||||||
style.configure(
|
style.configure(
|
||||||
@@ -134,6 +285,12 @@ def apply_modern_styles() -> None:
|
|||||||
font=("Segoe UI", 9),
|
font=("Segoe UI", 9),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ---------------- 通用文字语义 ----------------
|
||||||
|
style.configure("Muted.TLabel", background=bg, foreground=muted_fg)
|
||||||
|
style.configure("SuccessState.TLabel", background=bg, foreground=success_fg)
|
||||||
|
style.configure("WarningState.TLabel", background=bg, foreground=warning_fg)
|
||||||
|
style.configure("InfoState.TLabel", background=bg, foreground=palette["info_fg"])
|
||||||
|
|
||||||
# ---------------- 顶部工具条 ----------------
|
# ---------------- 顶部工具条 ----------------
|
||||||
style.configure("Toolbar.TFrame", background=bg, borderwidth=0)
|
style.configure("Toolbar.TFrame", background=bg, borderwidth=0)
|
||||||
# 工具条上的次要按钮(清理配置等)
|
# 工具条上的次要按钮(清理配置等)
|
||||||
@@ -168,9 +325,17 @@ def apply_modern_styles() -> None:
|
|||||||
style.configure(
|
style.configure(
|
||||||
"SidebarBrand.TLabel",
|
"SidebarBrand.TLabel",
|
||||||
background=brand_bg,
|
background=brand_bg,
|
||||||
foreground="#ffffff",
|
foreground=palette["badge_fg"],
|
||||||
font=("Segoe UI Semibold", 12),
|
font=("Segoe UI Semibold", 12),
|
||||||
)
|
)
|
||||||
|
style.configure(
|
||||||
|
"SidebarBadge.TLabel",
|
||||||
|
background=palette["badge_bg"],
|
||||||
|
foreground=palette["badge_fg"],
|
||||||
|
font=("微软雅黑", 8, "bold"),
|
||||||
|
anchor="center",
|
||||||
|
padding=(6, 2),
|
||||||
|
)
|
||||||
|
|
||||||
# ---------------- 结果区无边框标题行 ----------------
|
# ---------------- 结果区无边框标题行 ----------------
|
||||||
style.configure("ResultHeader.TFrame", background=bg, borderwidth=0)
|
style.configure("ResultHeader.TFrame", background=bg, borderwidth=0)
|
||||||
@@ -182,7 +347,7 @@ def apply_modern_styles() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# ---------------- 状态栏 ----------------
|
# ---------------- 状态栏 ----------------
|
||||||
statusbar_bg = _mix(bg, "#000000", 0.06) if not dark_theme else _mix(bg, "#ffffff", 0.06)
|
statusbar_bg = palette["statusbar_bg"]
|
||||||
statusbar_fg = _mix(fg, bg, 0.15)
|
statusbar_fg = _mix(fg, bg, 0.15)
|
||||||
style.configure(
|
style.configure(
|
||||||
"StatusBar.TFrame",
|
"StatusBar.TFrame",
|
||||||
@@ -204,6 +369,33 @@ def apply_modern_styles() -> None:
|
|||||||
padding=(10, 4),
|
padding=(10, 4),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ---------------- 深色禁用态 / 只读态增强 ----------------
|
||||||
|
style.map(
|
||||||
|
"TLabel",
|
||||||
|
foreground=[("disabled", disabled_fg)],
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"TButton",
|
||||||
|
foreground=[("disabled", disabled_fg)],
|
||||||
|
background=[("disabled", disabled_bg)],
|
||||||
|
bordercolor=[("disabled", disabled_border)],
|
||||||
|
darkcolor=[("disabled", disabled_bg)],
|
||||||
|
lightcolor=[("disabled", disabled_bg)],
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"TEntry",
|
||||||
|
foreground=[("disabled", disabled_fg)],
|
||||||
|
fieldbackground=[("disabled", disabled_bg), ("readonly", readonly_bg)],
|
||||||
|
bordercolor=[("disabled", disabled_border), ("readonly", disabled_border)],
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"TCombobox",
|
||||||
|
foreground=[("disabled", disabled_fg), ("readonly", fg)],
|
||||||
|
fieldbackground=[("disabled", disabled_bg), ("readonly", readonly_bg)],
|
||||||
|
bordercolor=[("disabled", disabled_border), ("readonly", disabled_border)],
|
||||||
|
arrowcolor=[("disabled", disabled_fg), ("readonly", muted_fg)],
|
||||||
|
)
|
||||||
|
|
||||||
# ---------------- Sidebar 按钮(保留兼容名) ----------------
|
# ---------------- Sidebar 按钮(保留兼容名) ----------------
|
||||||
style.configure(
|
style.configure(
|
||||||
"Sidebar.TButton",
|
"Sidebar.TButton",
|
||||||
@@ -225,7 +417,7 @@ def apply_modern_styles() -> None:
|
|||||||
style.configure(
|
style.configure(
|
||||||
"SidebarSelected.TButton",
|
"SidebarSelected.TButton",
|
||||||
background=sidebar_selected,
|
background=sidebar_selected,
|
||||||
foreground="#ffffff",
|
foreground=_contrast_text(sidebar_selected, dark_text=palette["badge_fg"], light_text=sidebar_fg),
|
||||||
font=("Segoe UI Semibold", 10),
|
font=("Segoe UI Semibold", 10),
|
||||||
padding=(18, 9),
|
padding=(18, 9),
|
||||||
borderwidth=0,
|
borderwidth=0,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import ttkbootstrap as ttk
|
|||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
|
|
||||||
from app.services import ai_image as _svc
|
from app.services import ai_image as _svc
|
||||||
|
from app.views.modern_styles import apply_tooltip_theme, get_theme_palette
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
@@ -26,17 +27,19 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _theme_colors():
|
def _theme_colors():
|
||||||
style = ttk.Style()
|
palette = get_theme_palette()
|
||||||
colors = style.colors
|
|
||||||
return {
|
return {
|
||||||
"bg": colors.bg,
|
"bg": palette["bg"],
|
||||||
"fg": colors.fg,
|
"fg": palette["fg"],
|
||||||
"muted": colors.secondary,
|
"muted": palette["muted_fg"],
|
||||||
"input_bg": colors.inputbg,
|
"input_bg": palette["input_bg"],
|
||||||
"input_fg": colors.inputfg,
|
"input_fg": palette["input_fg"],
|
||||||
"select_bg": colors.selectbg,
|
"select_bg": palette["select_bg"],
|
||||||
"select_fg": colors.selectfg,
|
"select_fg": palette["select_fg"],
|
||||||
"border": colors.border,
|
"border": palette["border"],
|
||||||
|
"tooltip_bg": palette["tooltip_bg"],
|
||||||
|
"tooltip_fg": palette["tooltip_fg"],
|
||||||
|
"tooltip_border": palette["tooltip_border"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -95,8 +98,6 @@ def _show_tree_tooltip(self: "PQAutomationApp", text: str, x_root: int, y_root:
|
|||||||
text="",
|
text="",
|
||||||
justify=tk.LEFT,
|
justify=tk.LEFT,
|
||||||
anchor=tk.W,
|
anchor=tk.W,
|
||||||
bg="#ffffff",
|
|
||||||
fg="#1f2937",
|
|
||||||
relief=tk.SOLID,
|
relief=tk.SOLID,
|
||||||
bd=1,
|
bd=1,
|
||||||
padx=8,
|
padx=8,
|
||||||
@@ -104,6 +105,7 @@ def _show_tree_tooltip(self: "PQAutomationApp", text: str, x_root: int, y_root:
|
|||||||
font=("微软雅黑", 9),
|
font=("微软雅黑", 9),
|
||||||
wraplength=520,
|
wraplength=520,
|
||||||
)
|
)
|
||||||
|
apply_tooltip_theme(tip, label)
|
||||||
label.pack(fill=tk.BOTH, expand=True)
|
label.pack(fill=tk.BOTH, expand=True)
|
||||||
self._ai_image_tooltip = tip
|
self._ai_image_tooltip = tip
|
||||||
self._ai_image_tooltip_label = label
|
self._ai_image_tooltip_label = label
|
||||||
@@ -114,6 +116,7 @@ def _show_tree_tooltip(self: "PQAutomationApp", text: str, x_root: int, y_root:
|
|||||||
|
|
||||||
self._ai_image_tooltip_item = item_id
|
self._ai_image_tooltip_item = item_id
|
||||||
label.configure(text=text)
|
label.configure(text=text)
|
||||||
|
apply_tooltip_theme(tip, label)
|
||||||
tip.geometry(f"+{x_root + 14}+{y_root + 18}")
|
tip.geometry(f"+{x_root + 14}+{y_root + 18}")
|
||||||
tip.deiconify()
|
tip.deiconify()
|
||||||
tip.lift()
|
tip.lift()
|
||||||
@@ -1225,6 +1228,16 @@ def _build_ucd_resized_image(image_path: str, target_w: int, target_h: int) -> s
|
|||||||
return out_path
|
return out_path
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_ai_image_theme(self: "PQAutomationApp"):
|
||||||
|
"""刷新 AI 图片面板中的主题相关控件。"""
|
||||||
|
if hasattr(self, "_apply_ai_image_list_style"):
|
||||||
|
self._apply_ai_image_list_style()
|
||||||
|
tip = getattr(self, "_ai_image_tooltip", None)
|
||||||
|
label = getattr(self, "_ai_image_tooltip_label", None)
|
||||||
|
if tip is not None and label is not None:
|
||||||
|
apply_tooltip_theme(tip, label)
|
||||||
|
|
||||||
|
|
||||||
class AIImagePanelMixin:
|
class AIImagePanelMixin:
|
||||||
"""由 tools/refactor_to_mixins.py 自动生成。
|
"""由 tools/refactor_to_mixins.py 自动生成。
|
||||||
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
||||||
@@ -1249,3 +1262,5 @@ class AIImagePanelMixin:
|
|||||||
_rename_current = _rename_current
|
_rename_current = _rename_current
|
||||||
_show_list_context_menu = _show_list_context_menu
|
_show_list_context_menu = _show_list_context_menu
|
||||||
_send_to_ucd = _send_to_ucd
|
_send_to_ucd = _send_to_ucd
|
||||||
|
_apply_ai_image_list_style = _apply_ai_image_list_style
|
||||||
|
refresh_ai_image_theme = refresh_ai_image_theme
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
|||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
|
|
||||||
from app.tests.color_accuracy import calculate_delta_e_2000
|
from app.tests.color_accuracy import calculate_delta_e_2000
|
||||||
|
from app.views.modern_styles import get_theme_palette
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from pqAutomationApp import PQAutomationApp
|
from pqAutomationApp import PQAutomationApp
|
||||||
@@ -35,10 +36,6 @@ D65_X = 0.3127
|
|||||||
D65_Y = 0.3290
|
D65_Y = 0.3290
|
||||||
TARGET_CCT = 6504
|
TARGET_CCT = 6504
|
||||||
TARGET_GAMMA = 2.2
|
TARGET_GAMMA = 2.2
|
||||||
_DARK_BG = "#2f2f2f"
|
|
||||||
_AX_BG = "#262626"
|
|
||||||
_FG = "#d8d8d8"
|
|
||||||
_GRID = "#5b5b5b"
|
|
||||||
|
|
||||||
DE_FORMULAS = ["2000", "94", "76"]
|
DE_FORMULAS = ["2000", "94", "76"]
|
||||||
|
|
||||||
@@ -60,7 +57,7 @@ def _contrast_fg(gray_value: int) -> str:
|
|||||||
def _set_canvas_patch(canvas: tk.Canvas, color: str, text: str) -> None:
|
def _set_canvas_patch(canvas: tk.Canvas, color: str, text: str) -> None:
|
||||||
"""统一设置色块 Canvas 颜色与文字,避免主题对 Label 背景渲染的干扰。"""
|
"""统一设置色块 Canvas 颜色与文字,避免主题对 Label 背景渲染的干扰。"""
|
||||||
gray = int(color[1:3], 16)
|
gray = int(color[1:3], 16)
|
||||||
canvas.configure(bg=color, highlightbackground="#666666")
|
canvas.configure(bg=color, highlightbackground=get_theme_palette()["border"])
|
||||||
canvas.itemconfigure("patch_bg", fill=color, outline=color)
|
canvas.itemconfigure("patch_bg", fill=color, outline=color)
|
||||||
canvas.itemconfigure("patch_text", text=text, fill=_contrast_fg(gray))
|
canvas.itemconfigure("patch_text", text=text, fill=_contrast_fg(gray))
|
||||||
|
|
||||||
@@ -115,6 +112,7 @@ def _get_calman_palette() -> dict[str, str]:
|
|||||||
"""根据当前主题生成 Calman 调试面板色板。"""
|
"""根据当前主题生成 Calman 调试面板色板。"""
|
||||||
style = ttk.Style()
|
style = ttk.Style()
|
||||||
colors = style.colors
|
colors = style.colors
|
||||||
|
theme_palette = get_theme_palette()
|
||||||
bg = colors.bg
|
bg = colors.bg
|
||||||
fg = colors.fg
|
fg = colors.fg
|
||||||
dark_mode = _is_dark_hex(bg)
|
dark_mode = _is_dark_hex(bg)
|
||||||
@@ -131,22 +129,22 @@ def _get_calman_palette() -> dict[str, str]:
|
|||||||
reading_fg = _mix(fg, "#ffffff", 0.06)
|
reading_fg = _mix(fg, "#ffffff", 0.06)
|
||||||
status_fg = _mix(fg, bg, 0.35)
|
status_fg = _mix(fg, bg, 0.35)
|
||||||
reading_accent = colors.info
|
reading_accent = colors.info
|
||||||
xy_series = "#d7dce4"
|
xy_series = _mix(fg, "#ffffff", 0.10)
|
||||||
d65_mark = "#ffffff"
|
d65_mark = _mix(fg, "#ffffff", 0.04)
|
||||||
else:
|
else:
|
||||||
figure_bg = _mix(bg, "#dfe7ef", 0.45)
|
figure_bg = _mix(bg, "#dfe7ef", 0.45)
|
||||||
axes_bg = _mix(bg, "#eff4f9", 0.72)
|
axes_bg = _mix(bg, "#eff4f9", 0.72)
|
||||||
grid = _mix("#5f6f82", axes_bg, 0.55)
|
grid = _mix("#5f6f82", axes_bg, 0.55)
|
||||||
tree_bg = "#ffffff"
|
tree_bg = theme_palette["input_bg"]
|
||||||
tree_even = "#ffffff"
|
tree_even = theme_palette["input_bg"]
|
||||||
tree_odd = "#f3f7fb"
|
tree_odd = "#f3f7fb"
|
||||||
heading_bg = _mix(colors.primary, "#ffffff", 0.82)
|
heading_bg = _mix(colors.primary, "#ffffff", 0.82)
|
||||||
reading_bg = _mix(bg, "#e7eef5", 0.58)
|
reading_bg = _mix(bg, "#e7eef5", 0.58)
|
||||||
reading_fg = fg
|
reading_fg = fg
|
||||||
status_fg = _mix(fg, bg, 0.25)
|
status_fg = _mix(fg, bg, 0.25)
|
||||||
reading_accent = _mix(colors.info, "#000000", 0.25)
|
reading_accent = _mix(colors.info, "#000000", 0.25)
|
||||||
xy_series = "#1f2a36"
|
xy_series = _mix(fg, bg, 0.18)
|
||||||
d65_mark = "#253142"
|
d65_mark = _mix(fg, bg, 0.28)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"figure_bg": figure_bg,
|
"figure_bg": figure_bg,
|
||||||
@@ -166,31 +164,59 @@ def _get_calman_palette() -> dict[str, str]:
|
|||||||
"tree_heading_bg": heading_bg,
|
"tree_heading_bg": heading_bg,
|
||||||
"tree_heading_fg": reading_fg,
|
"tree_heading_fg": reading_fg,
|
||||||
"tree_select": _mix(colors.info, figure_bg, 0.35),
|
"tree_select": _mix(colors.info, figure_bg, 0.35),
|
||||||
|
"patch_border": theme_palette["border"],
|
||||||
|
"patch_border_alt": _mix(theme_palette["border"], theme_palette["fg"], 0.12),
|
||||||
|
"patch_focus": theme_palette["focus"],
|
||||||
"xy_series": xy_series,
|
"xy_series": xy_series,
|
||||||
"d65_mark": d65_mark,
|
"d65_mark": d65_mark,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _xyY_to_rgb_balance(x: float, y: float, big_y: float) -> tuple[float, float, float]:
|
def _xyY_to_rgb_balance(x: float, y: float, big_y: float) -> tuple[float, float, float]:
|
||||||
"""把 xyY 近似映射到 RGB 比例,并归一到平均值 100。"""
|
"""按 D65 同亮度参考计算 RGB Balance(Calman 常见口径)。"""
|
||||||
if y <= 0 or big_y <= 0:
|
if y <= 0 or big_y <= 0:
|
||||||
return float("nan"), float("nan"), float("nan")
|
return float("nan"), float("nan"), float("nan")
|
||||||
|
|
||||||
big_x = (x * big_y) / y
|
def _xyY_to_xyz(cx: float, cy: float, cy_big: float) -> tuple[float, float, float]:
|
||||||
big_z = ((1.0 - x - y) * big_y) / y
|
if cy <= 0:
|
||||||
|
|
||||||
r = (3.2406 * big_x) + (-1.5372 * big_y) + (-0.4986 * big_z)
|
|
||||||
g = (-0.9689 * big_x) + (1.8758 * big_y) + (0.0415 * big_z)
|
|
||||||
b = (0.0557 * big_x) + (-0.2040 * big_y) + (1.0570 * big_z)
|
|
||||||
|
|
||||||
r = max(r, 0.0)
|
|
||||||
g = max(g, 0.0)
|
|
||||||
b = max(b, 0.0)
|
|
||||||
|
|
||||||
avg = (r + g + b) / 3.0
|
|
||||||
if avg <= 0:
|
|
||||||
return float("nan"), float("nan"), float("nan")
|
return float("nan"), float("nan"), float("nan")
|
||||||
return (r / avg) * 100.0, (g / avg) * 100.0, (b / avg) * 100.0
|
cx_big = (cx * cy_big) / cy
|
||||||
|
cz_big = ((1.0 - cx - cy) * cy_big) / cy
|
||||||
|
return cx_big, cy_big, cz_big
|
||||||
|
|
||||||
|
def _xyz_to_linear_rgb(cx_big: float, cy_big: float, cz_big: float) -> tuple[float, float, float]:
|
||||||
|
rr = (3.2406 * cx_big) + (-1.5372 * cy_big) + (-0.4986 * cz_big)
|
||||||
|
gg = (-0.9689 * cx_big) + (1.8758 * cy_big) + (0.0415 * cz_big)
|
||||||
|
bb = (0.0557 * cx_big) + (-0.2040 * cy_big) + (1.0570 * cz_big)
|
||||||
|
return rr, gg, bb
|
||||||
|
|
||||||
|
mx, my, mz = _xyY_to_xyz(x, y, big_y)
|
||||||
|
tx, ty, tz = _xyY_to_xyz(D65_X, D65_Y, big_y)
|
||||||
|
mr, mg, mb = _xyz_to_linear_rgb(mx, my, mz)
|
||||||
|
tr, tg, tb = _xyz_to_linear_rgb(tx, ty, tz)
|
||||||
|
|
||||||
|
eps = 1e-9
|
||||||
|
if tr <= eps or tg <= eps or tb <= eps:
|
||||||
|
return float("nan"), float("nan"), float("nan")
|
||||||
|
|
||||||
|
rr = (mr / tr) * 100.0
|
||||||
|
gg = (mg / tg) * 100.0
|
||||||
|
bb = (mb / tb) * 100.0
|
||||||
|
|
||||||
|
# 明显异常值视为无效,避免图表被离群点拉坏。
|
||||||
|
if not (math.isfinite(rr) and math.isfinite(gg) and math.isfinite(bb)):
|
||||||
|
return float("nan"), float("nan"), float("nan")
|
||||||
|
if rr < 0 or gg < 0 or bb < 0:
|
||||||
|
return float("nan"), float("nan"), float("nan")
|
||||||
|
|
||||||
|
return rr, gg, bb
|
||||||
|
|
||||||
|
|
||||||
|
def _target_gamma_loglog_curve(pct: int) -> float:
|
||||||
|
"""Calman风格目标曲线:低灰阶从 1.8 过渡并逐步逼近 2.2。"""
|
||||||
|
if pct <= 0:
|
||||||
|
return 1.8
|
||||||
|
return TARGET_GAMMA - 0.4 * math.exp(-pct / 6.0)
|
||||||
|
|
||||||
|
|
||||||
def _style_axes(self: "PQAutomationApp", ax, title: str) -> None:
|
def _style_axes(self: "PQAutomationApp", ax, title: str) -> None:
|
||||||
@@ -480,6 +506,7 @@ def create_calman_panel(self: "PQAutomationApp") -> None:
|
|||||||
self.calman_actual_patch_cells = []
|
self.calman_actual_patch_cells = []
|
||||||
self.calman_target_patch_canvases = []
|
self.calman_target_patch_canvases = []
|
||||||
self.calman_target_hexes = []
|
self.calman_target_hexes = []
|
||||||
|
patch_palette = _get_calman_palette()
|
||||||
for idx, pct in enumerate(self.calman_levels):
|
for idx, pct in enumerate(self.calman_levels):
|
||||||
rgb = _pct_to_gray_rgb(pct)
|
rgb = _pct_to_gray_rgb(pct)
|
||||||
color = _rgb_to_hex(rgb)
|
color = _rgb_to_hex(rgb)
|
||||||
@@ -493,7 +520,7 @@ def create_calman_panel(self: "PQAutomationApp") -> None:
|
|||||||
bd=1,
|
bd=1,
|
||||||
relief="solid",
|
relief="solid",
|
||||||
highlightthickness=1,
|
highlightthickness=1,
|
||||||
highlightbackground="#808080",
|
highlightbackground=patch_palette["patch_border_alt"],
|
||||||
cursor="hand2",
|
cursor="hand2",
|
||||||
)
|
)
|
||||||
actual_cell.grid(row=0, column=idx, padx=1, pady=1, sticky=tk.NSEW)
|
actual_cell.grid(row=0, column=idx, padx=1, pady=1, sticky=tk.NSEW)
|
||||||
@@ -520,7 +547,7 @@ def create_calman_panel(self: "PQAutomationApp") -> None:
|
|||||||
bd=1,
|
bd=1,
|
||||||
relief="solid",
|
relief="solid",
|
||||||
highlightthickness=1,
|
highlightthickness=1,
|
||||||
highlightbackground="#9c9c9c",
|
highlightbackground=patch_palette["patch_border"],
|
||||||
cursor="hand2",
|
cursor="hand2",
|
||||||
)
|
)
|
||||||
cell.grid(row=1, column=idx, padx=1, pady=1, sticky=tk.NSEW)
|
cell.grid(row=1, column=idx, padx=1, pady=1, sticky=tk.NSEW)
|
||||||
@@ -722,7 +749,7 @@ def send_patch(self: "PQAutomationApp", pct: int) -> None:
|
|||||||
def _measure_once(self: "PQAutomationApp", pct: int) -> dict | None:
|
def _measure_once(self: "PQAutomationApp", pct: int) -> dict | None:
|
||||||
"""采集一次 CA410,并组装一条记录(含 CCT/Gamma/ΔE2000)。"""
|
"""采集一次 CA410,并组装一条记录(含 CCT/Gamma/ΔE2000)。"""
|
||||||
try:
|
try:
|
||||||
x, y, lv, X, Y, Z = self.ca.readAllDisplay()
|
x, y, lv, X, Y, Z = self.read_ca_xyLv()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._dispatch_ui(self.log_gui.log, f"CA410 采集异常: {exc}", "error")
|
self._dispatch_ui(self.log_gui.log, f"CA410 采集异常: {exc}", "error")
|
||||||
return None
|
return None
|
||||||
@@ -974,20 +1001,21 @@ def clear_results(self: "PQAutomationApp") -> None:
|
|||||||
|
|
||||||
def _highlight_patch(self: "PQAutomationApp", pct: int) -> None:
|
def _highlight_patch(self: "PQAutomationApp", pct: int) -> None:
|
||||||
"""高亮当前选中色块。"""
|
"""高亮当前选中色块。"""
|
||||||
|
palette = _get_calman_palette()
|
||||||
try:
|
try:
|
||||||
idx = self.calman_levels.index(pct)
|
idx = self.calman_levels.index(pct)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return
|
return
|
||||||
for i, cell in enumerate(self.calman_patch_cells):
|
for i, cell in enumerate(self.calman_patch_cells):
|
||||||
if i == idx:
|
if i == idx:
|
||||||
cell.configure(highlightbackground="#1f6fb2", highlightthickness=2)
|
cell.configure(highlightbackground=palette["patch_focus"], highlightthickness=2)
|
||||||
else:
|
else:
|
||||||
cell.configure(highlightbackground="#9c9c9c", highlightthickness=1)
|
cell.configure(highlightbackground=palette["patch_border"], highlightthickness=1)
|
||||||
for i, cell in enumerate(self.calman_actual_cells):
|
for i, cell in enumerate(self.calman_actual_cells):
|
||||||
if i == idx:
|
if i == idx:
|
||||||
cell.configure(highlightbackground="#1f6fb2", highlightthickness=2)
|
cell.configure(highlightbackground=palette["patch_focus"], highlightthickness=2)
|
||||||
else:
|
else:
|
||||||
cell.configure(highlightbackground="#808080", highlightthickness=1)
|
cell.configure(highlightbackground=palette["patch_border_alt"], highlightthickness=1)
|
||||||
|
|
||||||
total_cols = len(self.calman_levels) + 1 # 含 metric 列
|
total_cols = len(self.calman_levels) + 1 # 含 metric 列
|
||||||
col_index = idx + 1
|
col_index = idx + 1
|
||||||
@@ -1082,10 +1110,18 @@ def _redraw_calman_charts(self: "PQAutomationApp") -> None:
|
|||||||
pcts = [r["pct"] for r in recs]
|
pcts = [r["pct"] for r in recs]
|
||||||
de_vals = [r["de2000"] if r["de2000"] == r["de2000"] else 0 for r in recs]
|
de_vals = [r["de2000"] if r["de2000"] == r["de2000"] else 0 for r in recs]
|
||||||
lum_vals = [r["Y"] if r["Y"] == r["Y"] else 0 for r in recs]
|
lum_vals = [r["Y"] if r["Y"] == r["Y"] else 0 for r in recs]
|
||||||
rgb_r = [r["rgb_r"] for r in recs if r["rgb_r"] == r["rgb_r"]]
|
rgb_recs = [
|
||||||
rgb_g = [r["rgb_g"] for r in recs if r["rgb_g"] == r["rgb_g"]]
|
r for r in recs
|
||||||
rgb_b = [r["rgb_b"] for r in recs if r["rgb_b"] == r["rgb_b"]]
|
if (
|
||||||
rgb_pcts = [r["pct"] for r in recs if r["rgb_r"] == r["rgb_r"]]
|
r.get("rgb_r") == r.get("rgb_r")
|
||||||
|
and r.get("rgb_g") == r.get("rgb_g")
|
||||||
|
and r.get("rgb_b") == r.get("rgb_b")
|
||||||
|
)
|
||||||
|
]
|
||||||
|
rgb_pcts = [r["pct"] for r in rgb_recs]
|
||||||
|
rgb_r = [r["rgb_r"] for r in rgb_recs]
|
||||||
|
rgb_g = [r["rgb_g"] for r in rgb_recs]
|
||||||
|
rgb_b = [r["rgb_b"] for r in rgb_recs]
|
||||||
gamma_pcts = [r["pct"] for r in recs if r["gamma"] == r["gamma"]]
|
gamma_pcts = [r["pct"] for r in recs if r["gamma"] == r["gamma"]]
|
||||||
gamma_vals = [r["gamma"] for r in recs if r["gamma"] == r["gamma"]]
|
gamma_vals = [r["gamma"] for r in recs if r["gamma"] == r["gamma"]]
|
||||||
cct_vals = [r["cct"] for r in recs if r["cct"] == r["cct"]]
|
cct_vals = [r["cct"] for r in recs if r["cct"] == r["cct"]]
|
||||||
@@ -1123,6 +1159,16 @@ def _redraw_calman_charts(self: "PQAutomationApp") -> None:
|
|||||||
a1.set_ylim(bottom=0)
|
a1.set_ylim(bottom=0)
|
||||||
a1.set_xlabel("", fontsize=8)
|
a1.set_xlabel("", fontsize=8)
|
||||||
|
|
||||||
|
rgb_ylim_low = 95.0
|
||||||
|
rgb_ylim_high = 105.0
|
||||||
|
if rgb_recs:
|
||||||
|
rgb_values = rgb_r + rgb_g + rgb_b
|
||||||
|
rgb_min = min(rgb_values + [100.0])
|
||||||
|
rgb_max = max(rgb_values + [100.0])
|
||||||
|
pad = max(0.8, (rgb_max - rgb_min) * 0.15)
|
||||||
|
rgb_ylim_low = min(95.0, rgb_min - pad)
|
||||||
|
rgb_ylim_high = max(105.0, rgb_max + pad)
|
||||||
|
|
||||||
# RGB Balance 线图
|
# RGB Balance 线图
|
||||||
a2 = self.calman_ax_rgb_line
|
a2 = self.calman_ax_rgb_line
|
||||||
a2.clear()
|
a2.clear()
|
||||||
@@ -1133,36 +1179,38 @@ def _redraw_calman_charts(self: "PQAutomationApp") -> None:
|
|||||||
a2.plot(rgb_pcts, rgb_b, "-", color="#4a73ff", linewidth=1.2)
|
a2.plot(rgb_pcts, rgb_b, "-", color="#4a73ff", linewidth=1.2)
|
||||||
a2.axhline(100, color="#9e9e9e", lw=0.8, ls="--")
|
a2.axhline(100, color="#9e9e9e", lw=0.8, ls="--")
|
||||||
a2.set_xlim(-2, 102)
|
a2.set_xlim(-2, 102)
|
||||||
a2.set_ylim(95, 105)
|
a2.set_ylim(rgb_ylim_low, rgb_ylim_high)
|
||||||
a2.set_xlabel("", fontsize=8)
|
a2.set_xlabel("", fontsize=8)
|
||||||
|
|
||||||
# RGB Balance 条图(用最后一个点)
|
# RGB Balance 条图(用最后一个点)
|
||||||
a3 = self.calman_ax_rgb_bar
|
a3 = self.calman_ax_rgb_bar
|
||||||
a3.clear()
|
a3.clear()
|
||||||
_style_axes(self, a3, "RGB Balance")
|
_style_axes(self, a3, "RGB Balance")
|
||||||
if recs:
|
if rgb_recs:
|
||||||
last = recs[-1]
|
last = rgb_recs[-1]
|
||||||
bars = [
|
bars = [
|
||||||
last["rgb_r"] if last["rgb_r"] == last["rgb_r"] else 100,
|
last["rgb_r"],
|
||||||
last["rgb_g"] if last["rgb_g"] == last["rgb_g"] else 100,
|
last["rgb_g"],
|
||||||
last["rgb_b"] if last["rgb_b"] == last["rgb_b"] else 100,
|
last["rgb_b"],
|
||||||
]
|
]
|
||||||
a3.bar([0, 1, 2], bars, color=["#ff4d4d", "#4caf50", "#4a73ff"], width=0.7)
|
a3.bar([0, 1, 2], bars, color=["#ff4d4d", "#4caf50", "#4a73ff"], width=0.7)
|
||||||
a3.set_xticks([0, 1, 2], ["R", "G", "B"])
|
a3.set_xticks([0, 1, 2], ["R", "G", "B"])
|
||||||
else:
|
else:
|
||||||
a3.set_xticks([0, 1, 2], ["R", "G", "B"])
|
a3.set_xticks([0, 1, 2], ["R", "G", "B"])
|
||||||
a3.set_ylim(95, 105)
|
a3.set_ylim(rgb_ylim_low, rgb_ylim_high)
|
||||||
a3.set_xlabel("", fontsize=8)
|
a3.set_xlabel("", fontsize=8)
|
||||||
|
|
||||||
# Gamma
|
# Gamma
|
||||||
a4 = self.calman_ax_gamma
|
a4 = self.calman_ax_gamma
|
||||||
a4.clear()
|
a4.clear()
|
||||||
_style_axes(self, a4, "Gamma Log/Log")
|
_style_axes(self, a4, "Gamma Log/Log")
|
||||||
|
target_pcts = list(self.calman_levels)
|
||||||
|
target_vals = [_target_gamma_loglog_curve(p) for p in target_pcts]
|
||||||
|
a4.plot(target_pcts, target_vals, "-", color="#f4ff00", linewidth=1.8)
|
||||||
if gamma_pcts:
|
if gamma_pcts:
|
||||||
a4.plot(gamma_pcts, gamma_vals, "-", color="#ffe24d", linewidth=1.3)
|
a4.plot(gamma_pcts, gamma_vals, "-", color="#8f8f8f", linewidth=2.0)
|
||||||
a4.axhline(TARGET_GAMMA, color="#9e9e9e", lw=0.8, ls="--")
|
|
||||||
a4.set_xlim(-2, 102)
|
a4.set_xlim(-2, 102)
|
||||||
a4.set_ylim(1.6, 2.8)
|
a4.set_ylim(1.8, 2.8)
|
||||||
a4.set_xlabel("", fontsize=8)
|
a4.set_xlabel("", fontsize=8)
|
||||||
|
|
||||||
self.calman_canvas.draw_idle()
|
self.calman_canvas.draw_idle()
|
||||||
@@ -1232,14 +1280,20 @@ def _refresh_metric_table(self: "PQAutomationApp") -> None:
|
|||||||
"""重绘下方矩阵表。"""
|
"""重绘下方矩阵表。"""
|
||||||
_apply_calman_tree_style(self)
|
_apply_calman_tree_style(self)
|
||||||
palette = _get_calman_palette()
|
palette = _get_calman_palette()
|
||||||
|
ref_white_y = self.calman_results.get(100, {}).get("Y")
|
||||||
|
|
||||||
|
def _target_y_abs(pctx):
|
||||||
|
if pctx is None:
|
||||||
|
return "-"
|
||||||
|
if ref_white_y is None or ref_white_y != ref_white_y or ref_white_y <= 0:
|
||||||
|
return "-"
|
||||||
|
return _safe_float(ref_white_y * ((pctx / 100.0) ** TARGET_GAMMA), "{:.3f}")
|
||||||
|
|
||||||
metrics = [
|
metrics = [
|
||||||
("x CIE31", lambda r: _safe_float(r.get("x")) if r else "-"),
|
("x CIE31", lambda r: _safe_float(r.get("x")) if r else "-"),
|
||||||
("y CIE31", lambda r: _safe_float(r.get("y")) if r else "-"),
|
("y CIE31", lambda r: _safe_float(r.get("y")) if r else "-"),
|
||||||
("Y", lambda r: _safe_float(r.get("Y"), "{:.3f}") if r else "-"),
|
("Y", lambda r: _safe_float(r.get("Y"), "{:.3f}") if r else "-"),
|
||||||
(
|
("Target Y", lambda _r, pctx=None: _target_y_abs(pctx)),
|
||||||
"Target Y",
|
|
||||||
lambda _r, pctx=None: _safe_float((pctx / 100.0) ** TARGET_GAMMA, "{:.4f}") if pctx and pctx > 0 else ("0.0000" if pctx == 0 else "-"),
|
|
||||||
),
|
|
||||||
("Gamma Log/Log", lambda r: _safe_float(r.get("gamma"), "{:.3f}") if r else "-"),
|
("Gamma Log/Log", lambda r: _safe_float(r.get("gamma"), "{:.3f}") if r else "-"),
|
||||||
("CCT", lambda r: _safe_float(r.get("cct"), "{:.0f}") if r else "-"),
|
("CCT", lambda r: _safe_float(r.get("cct"), "{:.0f}") if r else "-"),
|
||||||
("dE 2000", lambda r: _safe_float(r.get("de2000"), "{:.3f}") if r else "-"),
|
("dE 2000", lambda r: _safe_float(r.get("de2000"), "{:.3f}") if r else "-"),
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import colour
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from app.data_range_converter import convert_pattern_params
|
from app.data_range_converter import convert_pattern_params
|
||||||
|
from app.views.modern_styles import get_theme_palette
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
@@ -28,37 +29,12 @@ def create_custom_template_result_panel(self: "PQAutomationApp"):
|
|||||||
|
|
||||||
table_container = tk.Frame(
|
table_container = tk.Frame(
|
||||||
self.custom_result_frame,
|
self.custom_result_frame,
|
||||||
bg="#000000",
|
|
||||||
highlightthickness=1,
|
highlightthickness=1,
|
||||||
highlightbackground="#5a5a5a",
|
|
||||||
)
|
)
|
||||||
table_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
table_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||||
|
self.custom_result_table_container = table_container
|
||||||
|
|
||||||
style = ttk.Style()
|
_apply_custom_result_theme(self)
|
||||||
style.configure(
|
|
||||||
"CustomResult.Treeview",
|
|
||||||
background="#000000",
|
|
||||||
fieldbackground="#000000",
|
|
||||||
foreground="#ffffff",
|
|
||||||
rowheight=28,
|
|
||||||
borderwidth=0,
|
|
||||||
)
|
|
||||||
style.configure(
|
|
||||||
"CustomResult.Treeview.Heading",
|
|
||||||
background="#2f2f2f",
|
|
||||||
foreground="#f5f5f5",
|
|
||||||
font=("Microsoft YaHei", 10, "bold"),
|
|
||||||
relief="flat",
|
|
||||||
)
|
|
||||||
style.map(
|
|
||||||
"CustomResult.Treeview",
|
|
||||||
background=[("selected", "#1f4e79")],
|
|
||||||
foreground=[("selected", "#ffffff")],
|
|
||||||
)
|
|
||||||
style.map(
|
|
||||||
"CustomResult.Treeview.Heading",
|
|
||||||
background=[("active", "#3b3b3b")],
|
|
||||||
)
|
|
||||||
|
|
||||||
columns = (
|
columns = (
|
||||||
"Pattern",
|
"Pattern",
|
||||||
@@ -157,6 +133,70 @@ def create_custom_template_result_panel(self: "PQAutomationApp"):
|
|||||||
table_container.grid_columnconfigure(0, weight=1)
|
table_container.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
|
||||||
|
def _apply_custom_result_theme(self: "PQAutomationApp"):
|
||||||
|
palette = get_theme_palette()
|
||||||
|
container = getattr(self, "custom_result_table_container", None)
|
||||||
|
if container is not None:
|
||||||
|
container.configure(
|
||||||
|
bg=palette["input_bg"],
|
||||||
|
highlightbackground=palette["border"],
|
||||||
|
highlightcolor=palette["border"],
|
||||||
|
)
|
||||||
|
|
||||||
|
style = ttk.Style()
|
||||||
|
style.configure(
|
||||||
|
"CustomResult.Treeview",
|
||||||
|
background=palette["input_bg"],
|
||||||
|
fieldbackground=palette["input_bg"],
|
||||||
|
foreground=palette["input_fg"],
|
||||||
|
rowheight=28,
|
||||||
|
borderwidth=0,
|
||||||
|
)
|
||||||
|
style.configure(
|
||||||
|
"CustomResult.Treeview.Heading",
|
||||||
|
background=palette["surface_alt_bg"],
|
||||||
|
foreground=palette["muted_fg"],
|
||||||
|
font=("Microsoft YaHei", 10, "bold"),
|
||||||
|
relief="flat",
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"CustomResult.Treeview",
|
||||||
|
background=[("selected", palette["select_bg"])],
|
||||||
|
foreground=[("selected", palette["select_fg"])],
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"CustomResult.Treeview.Heading",
|
||||||
|
background=[("active", palette["surface_hover_bg"])],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_custom_template_theme(self: "PQAutomationApp"):
|
||||||
|
"""刷新客户模板结果表的主题色。"""
|
||||||
|
_apply_custom_result_theme(self)
|
||||||
|
|
||||||
|
|
||||||
|
def _set_custom_template_tab_visible(self: "PQAutomationApp", visible: bool):
|
||||||
|
"""控制客户模板结果 TAB 的显示与隐藏。"""
|
||||||
|
if not hasattr(self, "chart_notebook") or not hasattr(self, "custom_template_tab_frame"):
|
||||||
|
return
|
||||||
|
|
||||||
|
tab_id = str(self.custom_template_tab_frame)
|
||||||
|
current_tabs = list(self.chart_notebook.tabs())
|
||||||
|
|
||||||
|
if visible:
|
||||||
|
if tab_id not in current_tabs:
|
||||||
|
self.chart_notebook.add(self.custom_template_tab_frame, text="客户模板结果显示")
|
||||||
|
self.chart_notebook.select(self.custom_template_tab_frame)
|
||||||
|
return
|
||||||
|
|
||||||
|
if tab_id in current_tabs:
|
||||||
|
current_selected = self.chart_notebook.select()
|
||||||
|
self.chart_notebook.forget(self.custom_template_tab_frame)
|
||||||
|
remaining_tabs = list(self.chart_notebook.tabs())
|
||||||
|
if current_selected == tab_id and remaining_tabs:
|
||||||
|
self.chart_notebook.select(remaining_tabs[0])
|
||||||
|
|
||||||
|
|
||||||
def show_custom_result_context_menu(self: "PQAutomationApp", event):
|
def show_custom_result_context_menu(self: "PQAutomationApp", event):
|
||||||
"""显示客户模板结果右键菜单"""
|
"""显示客户模板结果右键菜单"""
|
||||||
if not hasattr(self, "custom_result_tree") or not hasattr(
|
if not hasattr(self, "custom_result_tree") or not hasattr(
|
||||||
@@ -322,11 +362,9 @@ def _run_custom_row_single_step(self: "PQAutomationApp", item_id, row_no):
|
|||||||
time.sleep(self.pattern_settle_time)
|
time.sleep(self.pattern_settle_time)
|
||||||
|
|
||||||
# 测量:显示模式1读取 Tcp/duv/Lv,显示模式8读取 λd/Pe/Lv 与 XYZ。
|
# 测量:显示模式1读取 Tcp/duv/Lv,显示模式8读取 λd/Pe/Lv 与 XYZ。
|
||||||
self.ca.set_Display(1)
|
tcp, duv, lv, _, _, _ = self.read_ca_tcp_duv()
|
||||||
tcp, duv, lv, _, _, _ = self.ca.readAllDisplay()
|
|
||||||
|
|
||||||
self.ca.set_Display(8)
|
lambda_d, pe, lv, X, Y, Z = self.read_ca_lambda_pe()
|
||||||
lambda_d, pe, lv, X, Y, Z = self.ca.readAllDisplay()
|
|
||||||
|
|
||||||
xy = colour.XYZ_to_xy(np.array([X, Y, Z]))
|
xy = colour.XYZ_to_xy(np.array([X, Y, Z]))
|
||||||
u_prime, v_prime, _ = colour.XYZ_to_CIE1976UCS(np.array([X, Y, Z]))
|
u_prime, v_prime, _ = colour.XYZ_to_CIE1976UCS(np.array([X, Y, Z]))
|
||||||
@@ -532,9 +570,6 @@ def append_custom_template_result(self: "PQAutomationApp", row_no, result_data):
|
|||||||
def start_custom_template_test(self: "PQAutomationApp"):
|
def start_custom_template_test(self: "PQAutomationApp"):
|
||||||
"""开始客户模板测试(SDR)"""
|
"""开始客户模板测试(SDR)"""
|
||||||
|
|
||||||
if hasattr(self, "chart_notebook") and hasattr(self, "custom_template_tab_frame"):
|
|
||||||
self.chart_notebook.select(self.custom_template_tab_frame)
|
|
||||||
|
|
||||||
if self.ca is None or self.ucd is None:
|
if self.ca is None or self.ucd is None:
|
||||||
messagebox.showerror("错误", "请先连接CA410和信号发生器")
|
messagebox.showerror("错误", "请先连接CA410和信号发生器")
|
||||||
return
|
return
|
||||||
@@ -569,8 +604,10 @@ def start_custom_template_test(self: "PQAutomationApp"):
|
|||||||
self.custom_btn.config(state=tk.NORMAL)
|
self.custom_btn.config(state=tk.NORMAL)
|
||||||
self.status_var.set("测试已取消")
|
self.status_var.set("测试已取消")
|
||||||
self.set_custom_result_table_locked(False)
|
self.set_custom_result_table_locked(False)
|
||||||
|
_set_custom_template_tab_visible(self, False)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
_set_custom_template_tab_visible(self, True)
|
||||||
self.set_custom_result_table_locked(True)
|
self.set_custom_result_table_locked(True)
|
||||||
|
|
||||||
self.test_thread = threading.Thread(target=self.run_custom_sdr_test, args=([],))
|
self.test_thread = threading.Thread(target=self.run_custom_sdr_test, args=([],))
|
||||||
@@ -923,6 +960,7 @@ class CustomTemplatePanelMixin:
|
|||||||
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
||||||
"""
|
"""
|
||||||
create_custom_template_result_panel = create_custom_template_result_panel
|
create_custom_template_result_panel = create_custom_template_result_panel
|
||||||
|
_set_custom_template_tab_visible = _set_custom_template_tab_visible
|
||||||
show_custom_result_context_menu = show_custom_result_context_menu
|
show_custom_result_context_menu = show_custom_result_context_menu
|
||||||
set_custom_result_table_locked = set_custom_result_table_locked
|
set_custom_result_table_locked = set_custom_result_table_locked
|
||||||
start_custom_row_single_step = start_custom_row_single_step
|
start_custom_row_single_step = start_custom_row_single_step
|
||||||
@@ -937,3 +975,4 @@ class CustomTemplatePanelMixin:
|
|||||||
update_custom_button_visibility = update_custom_button_visibility
|
update_custom_button_visibility = update_custom_button_visibility
|
||||||
export_custom_template_excel = export_custom_template_excel
|
export_custom_template_excel = export_custom_template_excel
|
||||||
export_custom_template_charts = export_custom_template_charts
|
export_custom_template_charts = export_custom_template_charts
|
||||||
|
refresh_custom_template_theme = refresh_custom_template_theme
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ def create_gamma_pattern_panel(self: "PQAutomationApp"):
|
|||||||
ttk.Label(
|
ttk.Label(
|
||||||
title_row,
|
title_row,
|
||||||
text="(Gamma / CCT / 对比度 / EOTF 共用此列表)",
|
text="(Gamma / CCT / 对比度 / EOTF 共用此列表)",
|
||||||
foreground="#888",
|
style="Muted.TLabel",
|
||||||
).pack(side=tk.LEFT, padx=(8, 0))
|
).pack(side=tk.LEFT, padx=(8, 0))
|
||||||
|
|
||||||
# ===== 预设管理行 =====
|
# ===== 预设管理行 =====
|
||||||
@@ -207,7 +207,7 @@ def create_gamma_pattern_panel(self: "PQAutomationApp"):
|
|||||||
).pack(side=tk.LEFT, padx=2)
|
).pack(side=tk.LEFT, padx=2)
|
||||||
|
|
||||||
self._gamma_active_label = ttk.Label(
|
self._gamma_active_label = ttk.Label(
|
||||||
preset_row1, text="", foreground="#0a8", font=("微软雅黑", 9, "bold")
|
preset_row1, text="", style="SuccessState.TLabel", font=("微软雅黑", 9, "bold")
|
||||||
)
|
)
|
||||||
self._gamma_active_label.pack(side=tk.LEFT, padx=(10, 0))
|
self._gamma_active_label.pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ def create_gamma_pattern_panel(self: "PQAutomationApp"):
|
|||||||
|
|
||||||
# 描述行
|
# 描述行
|
||||||
self._gamma_meta_label = ttk.Label(
|
self._gamma_meta_label = ttk.Label(
|
||||||
preset_box, text="", foreground="#666", font=("微软雅黑", 9)
|
preset_box, text="", style="Muted.TLabel", font=("微软雅黑", 9)
|
||||||
)
|
)
|
||||||
self._gamma_meta_label.pack(anchor=tk.W, pady=(6, 0))
|
self._gamma_meta_label.pack(anchor=tk.W, pady=(6, 0))
|
||||||
|
|
||||||
@@ -350,7 +350,7 @@ def create_gamma_pattern_panel(self: "PQAutomationApp"):
|
|||||||
paste_frame.pack(fill=tk.X, pady=(10, 0))
|
paste_frame.pack(fill=tk.X, pady=(10, 0))
|
||||||
ttk.Label(
|
ttk.Label(
|
||||||
paste_frame, text="每行:R,G,B 或 R G B\n或:灰度% (如 50%)",
|
paste_frame, text="每行:R,G,B 或 R G B\n或:灰度% (如 50%)",
|
||||||
foreground="#888", justify=tk.LEFT,
|
style="Muted.TLabel", justify=tk.LEFT,
|
||||||
).pack(anchor=tk.W)
|
).pack(anchor=tk.W)
|
||||||
ttk.Button(
|
ttk.Button(
|
||||||
paste_frame, text="从剪贴板导入",
|
paste_frame, text="从剪贴板导入",
|
||||||
@@ -363,7 +363,7 @@ def create_gamma_pattern_panel(self: "PQAutomationApp"):
|
|||||||
bottom.pack(fill=tk.X, pady=(10, 0))
|
bottom.pack(fill=tk.X, pady=(10, 0))
|
||||||
|
|
||||||
self._gamma_validate_label = ttk.Label(
|
self._gamma_validate_label = ttk.Label(
|
||||||
bottom, text="", foreground="#666", justify=tk.LEFT
|
bottom, text="", style="Muted.TLabel", justify=tk.LEFT
|
||||||
)
|
)
|
||||||
self._gamma_validate_label.pack(anchor=tk.W)
|
self._gamma_validate_label.pack(anchor=tk.W)
|
||||||
|
|
||||||
@@ -435,16 +435,16 @@ def _update_active_label(self: "PQAutomationApp"):
|
|||||||
current = self._gamma_current_preset
|
current = self._gamma_current_preset
|
||||||
if active and current == active and not self._gamma_dirty:
|
if active and current == active and not self._gamma_dirty:
|
||||||
self._gamma_active_label.config(
|
self._gamma_active_label.config(
|
||||||
text=f"✔ 当前激活:{active}", foreground="#0a8"
|
text=f"✔ 当前激活:{active}", style="SuccessState.TLabel"
|
||||||
)
|
)
|
||||||
elif active:
|
elif active:
|
||||||
extra = "(有未保存改动)" if self._gamma_dirty else ""
|
extra = "(有未保存改动)" if self._gamma_dirty else ""
|
||||||
self._gamma_active_label.config(
|
self._gamma_active_label.config(
|
||||||
text=f"● 激活:{active} 编辑中:{current or '-'}{extra}",
|
text=f"● 激活:{active} 编辑中:{current or '-'}{extra}",
|
||||||
foreground="#a60" if self._gamma_dirty else "#888",
|
style="WarningState.TLabel" if self._gamma_dirty else "Muted.TLabel",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._gamma_active_label.config(text="● 未激活任何预设", foreground="#888")
|
self._gamma_active_label.config(text="● 未激活任何预设", style="Muted.TLabel")
|
||||||
|
|
||||||
|
|
||||||
def _on_preset_selected(self: "PQAutomationApp"):
|
def _on_preset_selected(self: "PQAutomationApp"):
|
||||||
@@ -1023,11 +1023,11 @@ def _run_validation(self: "PQAutomationApp"):
|
|||||||
|
|
||||||
if not msgs:
|
if not msgs:
|
||||||
text = f"✔ 校验通过(共 {len(params)} 点)"
|
text = f"✔ 校验通过(共 {len(params)} 点)"
|
||||||
color = "#0a8"
|
style_name = "SuccessState.TLabel"
|
||||||
else:
|
else:
|
||||||
text = f"共 {len(params)} 点 | " + " ".join(msgs)
|
text = f"共 {len(params)} 点 | " + " ".join(msgs)
|
||||||
color = "#a60" if any(m.startswith("⚠") for m in msgs) else "#666"
|
style_name = "WarningState.TLabel" if any(m.startswith("⚠") for m in msgs) else "Muted.TLabel"
|
||||||
self._gamma_validate_label.config(text=text, foreground=color)
|
self._gamma_validate_label.config(text=text, style=style_name)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|||||||
@@ -757,13 +757,10 @@ def create_test_type_frame(self: "PQAutomationApp"):
|
|||||||
# 测试版水印标签(版本 x.x.0.0 时显示)
|
# 测试版水印标签(版本 x.x.0.0 时显示)
|
||||||
from app_version import is_beta_version, APP_VERSION
|
from app_version import is_beta_version, APP_VERSION
|
||||||
if is_beta_version():
|
if is_beta_version():
|
||||||
beta_lbl = tk.Label(
|
beta_lbl = ttk.Label(
|
||||||
self.sidebar_frame,
|
self.sidebar_frame,
|
||||||
text=f"[测试版] v{APP_VERSION}",
|
text=f"[测试版] v{APP_VERSION}",
|
||||||
foreground="#ffffff",
|
style="SidebarBadge.TLabel",
|
||||||
background="#cc3300",
|
|
||||||
font=("微软雅黑", 8, "bold"),
|
|
||||||
anchor="center",
|
|
||||||
)
|
)
|
||||||
beta_lbl.pack(fill=tk.X, side=tk.BOTTOM, padx=4, pady=(6, 4))
|
beta_lbl.pack(fill=tk.X, side=tk.BOTTOM, padx=4, pady=(6, 4))
|
||||||
|
|
||||||
@@ -809,6 +806,7 @@ def _on_toggle_theme(self: "PQAutomationApp") -> None:
|
|||||||
"""切换主题:重新应用 ttk 样式并刷新所有自定义样式相关的标签。"""
|
"""切换主题:重新应用 ttk 样式并刷新所有自定义样式相关的标签。"""
|
||||||
from app.views.theme_manager import toggle_theme
|
from app.views.theme_manager import toggle_theme
|
||||||
toggle_theme()
|
toggle_theme()
|
||||||
|
# apply_modern_styles()
|
||||||
_refresh_theme_toggle_label(self)
|
_refresh_theme_toggle_label(self)
|
||||||
if hasattr(self, "apply_result_chart_theme"):
|
if hasattr(self, "apply_result_chart_theme"):
|
||||||
try:
|
try:
|
||||||
@@ -820,6 +818,21 @@ def _on_toggle_theme(self: "PQAutomationApp") -> None:
|
|||||||
self.log_gui.refresh_log_theme()
|
self.log_gui.refresh_log_theme()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
if hasattr(self, "refresh_ai_image_theme"):
|
||||||
|
try:
|
||||||
|
self.refresh_ai_image_theme()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if hasattr(self, "refresh_single_step_theme"):
|
||||||
|
try:
|
||||||
|
self.refresh_single_step_theme()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if hasattr(self, "refresh_custom_template_theme"):
|
||||||
|
try:
|
||||||
|
self.refresh_custom_template_theme()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
if hasattr(self, "refresh_calman_theme"):
|
if hasattr(self, "refresh_calman_theme"):
|
||||||
try:
|
try:
|
||||||
self.refresh_calman_theme()
|
self.refresh_calman_theme()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def create_pantone_baseline_panel(self: "PQAutomationApp"):
|
|||||||
ttk.Label(config_row, textvariable=self.pantone_progress_var).pack(
|
ttk.Label(config_row, textvariable=self.pantone_progress_var).pack(
|
||||||
side=tk.RIGHT, padx=(8, 0)
|
side=tk.RIGHT, padx=(8, 0)
|
||||||
)
|
)
|
||||||
ttk.Label(config_row, textvariable=self.pantone_status_var, foreground="#666").pack(
|
ttk.Label(config_row, textvariable=self.pantone_status_var, style="Muted.TLabel").pack(
|
||||||
side=tk.RIGHT
|
side=tk.RIGHT
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -336,7 +336,7 @@ def _launch_worker(self: "PQAutomationApp", start_index, settle):
|
|||||||
end_state = "paused"
|
end_state = "paused"
|
||||||
break
|
break
|
||||||
|
|
||||||
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
x, y, lv, _X, _Y, _Z = self.read_ca_xyLv()
|
||||||
if lv is None:
|
if lv is None:
|
||||||
raise RuntimeError(f"第 {i + 1} 组 CA410 采集失败")
|
raise RuntimeError(f"第 {i + 1} 组 CA410 采集失败")
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ def create_local_dimming_panel(self: "PQAutomationApp"):
|
|||||||
window_frame,
|
window_frame,
|
||||||
text="点击按钮发送对应百分比的白色窗口(黑色背景 + 居中白色矩形)",
|
text="点击按钮发送对应百分比的白色窗口(黑色背景 + 居中白色矩形)",
|
||||||
font=("", 9),
|
font=("", 9),
|
||||||
foreground="#28a745",
|
style="SuccessState.TLabel",
|
||||||
).pack(pady=(0, 8))
|
).pack(pady=(0, 8))
|
||||||
|
|
||||||
# 第一行:1%, 2%, 5%, 10%, 18%
|
# 第一行:1%, 2%, 5%, 10%, 18%
|
||||||
@@ -96,7 +96,7 @@ def create_local_dimming_panel(self: "PQAutomationApp"):
|
|||||||
pattern_frame,
|
pattern_frame,
|
||||||
text="手动发送棋盘格、瞬时峰值、黑场图案,再点击采集当前亮度",
|
text="手动发送棋盘格、瞬时峰值、黑场图案,再点击采集当前亮度",
|
||||||
font=("", 9),
|
font=("", 9),
|
||||||
foreground="#28a745",
|
style="SuccessState.TLabel",
|
||||||
).pack(pady=(0, 8))
|
).pack(pady=(0, 8))
|
||||||
|
|
||||||
pattern_row = ttk.Frame(pattern_frame)
|
pattern_row = ttk.Frame(pattern_frame)
|
||||||
@@ -155,7 +155,7 @@ def create_local_dimming_panel(self: "PQAutomationApp"):
|
|||||||
measure_btn_frame,
|
measure_btn_frame,
|
||||||
text="亮度: -- cd/m² | x: -- | y: --",
|
text="亮度: -- cd/m² | x: -- | y: --",
|
||||||
font=("Consolas", 10),
|
font=("Consolas", 10),
|
||||||
foreground="#007bff",
|
style="InfoState.TLabel",
|
||||||
)
|
)
|
||||||
self.ld_result_label.pack(side=tk.LEFT, padx=(10, 0))
|
self.ld_result_label.pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ from tkinter import filedialog, messagebox
|
|||||||
import ttkbootstrap as ttk
|
import ttkbootstrap as ttk
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
from app.views.modern_styles import apply_listbox_theme
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -59,7 +61,7 @@ def create_single_step_panel(self: "PQAutomationApp"):
|
|||||||
ttk.Label(
|
ttk.Label(
|
||||||
title_row,
|
title_row,
|
||||||
text="录入目标色块,发送纯色色块并采集 xyY / ΔE2000。",
|
text="录入目标色块,发送纯色色块并采集 xyY / ΔE2000。",
|
||||||
foreground="#666",
|
style="Muted.TLabel",
|
||||||
).pack(side=tk.LEFT, padx=(12, 0))
|
).pack(side=tk.LEFT, padx=(12, 0))
|
||||||
|
|
||||||
left = ttk.LabelFrame(root, text="样本列表", padding=8)
|
left = ttk.LabelFrame(root, text="样本列表", padding=8)
|
||||||
@@ -73,11 +75,8 @@ def create_single_step_panel(self: "PQAutomationApp"):
|
|||||||
activestyle="none",
|
activestyle="none",
|
||||||
font=("微软雅黑", 9),
|
font=("微软雅黑", 9),
|
||||||
highlightthickness=1,
|
highlightthickness=1,
|
||||||
highlightbackground="#d8d8d8",
|
|
||||||
highlightcolor="#4a90e2",
|
|
||||||
selectbackground="#2b6cb0",
|
|
||||||
selectforeground="#ffffff",
|
|
||||||
)
|
)
|
||||||
|
apply_listbox_theme(self.single_step_listbox)
|
||||||
self.single_step_listbox.pack(fill=tk.BOTH, expand=True)
|
self.single_step_listbox.pack(fill=tk.BOTH, expand=True)
|
||||||
self.single_step_listbox.bind(
|
self.single_step_listbox.bind(
|
||||||
"<<ListboxSelect>>", lambda e: _on_sample_select(self)
|
"<<ListboxSelect>>", lambda e: _on_sample_select(self)
|
||||||
@@ -154,7 +153,7 @@ def create_single_step_panel(self: "PQAutomationApp"):
|
|||||||
ttk.Label(
|
ttk.Label(
|
||||||
form_frame,
|
form_frame,
|
||||||
textvariable=self.single_step_status_var,
|
textvariable=self.single_step_status_var,
|
||||||
foreground="#666",
|
style="Muted.TLabel",
|
||||||
).grid(row=2, column=2, columnspan=4, sticky=tk.W, pady=4)
|
).grid(row=2, column=2, columnspan=4, sticky=tk.W, pady=4)
|
||||||
|
|
||||||
action_row = ttk.Frame(form_frame)
|
action_row = ttk.Frame(form_frame)
|
||||||
@@ -444,7 +443,7 @@ def _measure_current_sample(self: "PQAutomationApp"):
|
|||||||
|
|
||||||
def worker():
|
def worker():
|
||||||
try:
|
try:
|
||||||
x, y, lv, _X, _Y, _Z = self.ca.readAllDisplay()
|
x, y, lv, _X, _Y, _Z = self.read_ca_xyLv()
|
||||||
if lv is None:
|
if lv is None:
|
||||||
raise RuntimeError("CA410 未返回有效亮度")
|
raise RuntimeError("CA410 未返回有效亮度")
|
||||||
self._dispatch_ui(self.single_step_measured_x_var.set, f"{x:.4f}")
|
self._dispatch_ui(self.single_step_measured_x_var.set, f"{x:.4f}")
|
||||||
@@ -556,6 +555,12 @@ def _export_results_csv(self: "PQAutomationApp"):
|
|||||||
messagebox.showerror("导出失败", f"写入 CSV 失败: {exc}")
|
messagebox.showerror("导出失败", f"写入 CSV 失败: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_single_step_theme(self: "PQAutomationApp"):
|
||||||
|
"""刷新单步调试中 tk.Listbox 的主题色。"""
|
||||||
|
if hasattr(self, "single_step_listbox"):
|
||||||
|
apply_listbox_theme(self.single_step_listbox)
|
||||||
|
|
||||||
|
|
||||||
class SingleStepPanelMixin:
|
class SingleStepPanelMixin:
|
||||||
"""由 tools/refactor_to_mixins.py 自动生成。
|
"""由 tools/refactor_to_mixins.py 自动生成。
|
||||||
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
||||||
@@ -575,3 +580,4 @@ class SingleStepPanelMixin:
|
|||||||
_commit_result = _commit_result
|
_commit_result = _commit_result
|
||||||
_clear_results = _clear_results
|
_clear_results = _clear_results
|
||||||
_export_results_csv = _export_results_csv
|
_export_results_csv = _export_results_csv
|
||||||
|
refresh_single_step_theme = refresh_single_step_theme
|
||||||
|
|||||||
@@ -802,7 +802,7 @@ class PQDebugPanel:
|
|||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
|
|
||||||
# 测量数据
|
# 测量数据
|
||||||
x, y, lv, X, Y, Z = self.app.ca.readAllDisplay()
|
x, y, lv, X, Y, Z = self.app.read_ca_xyLv()
|
||||||
|
|
||||||
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}, "
|
||||||
|
|||||||
@@ -19,20 +19,44 @@ from app.views.modern_styles import apply_modern_styles
|
|||||||
|
|
||||||
_PREFS_PATH = Path("settings/ui_preferences.json")
|
_PREFS_PATH = Path("settings/ui_preferences.json")
|
||||||
|
|
||||||
# 浅色主题:沿用旧的 yeti(首发布兼容)
|
# 浅色主题:自定义轻量蓝灰色板,恢复旧版浅色观感
|
||||||
LIGHT_THEME = "yeti"
|
LIGHT_THEME = "calman_light"
|
||||||
# 深色主题:自定义 Calman 风格
|
# 深色主题:自定义 Calman 风格
|
||||||
DARK_THEME = "calman_dark"
|
DARK_THEME = "calman_dark"
|
||||||
|
|
||||||
|
_LEGACY_LIGHT_THEMES = {"yeti"}
|
||||||
|
|
||||||
|
|
||||||
|
_CALMAN_LIGHT_COLORS = {
|
||||||
|
"primary": "#1755a6",
|
||||||
|
"secondary": "#2B6CB0",
|
||||||
|
"success": "#2F9E44",
|
||||||
|
"info": "#247BA0",
|
||||||
|
"warning": "#C98700",
|
||||||
|
"danger": "#CC3300",
|
||||||
|
"light": "#F7FAFC",
|
||||||
|
"dark": "#1F2A36",
|
||||||
|
"bg": "#F5F8FB",
|
||||||
|
"fg": "#1F2933",
|
||||||
|
"selectbg": "#2B6CB0",
|
||||||
|
"selectfg": "#FFFFFF",
|
||||||
|
"border": "#C8D4E3",
|
||||||
|
"inputfg": "#243240",
|
||||||
|
"inputbg": "#FFFFFF",
|
||||||
|
"active": "#D9E6F2",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Calman 风格深色主题色板(参考实测截图取色)
|
# Calman 风格深色主题色板
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
_CALMAN_DARK_COLORS = {
|
_CALMAN_DARK_COLORS = {
|
||||||
"primary": "#343A41", # 主色改为炭灰,避免大面积亮蓝
|
# "primary": "#2A2F36",
|
||||||
"secondary": "#444A51", # 中性深灰(用于 header / 分组背景)
|
# "secondary": "#444A51",
|
||||||
|
"primary": "#6FAFCC",
|
||||||
|
"secondary": "#AEAEAE",
|
||||||
"success": "#4FB960",
|
"success": "#4FB960",
|
||||||
"info": "#6FAFCC", # 降低饱和度,只做少量点缀
|
"info": "#6FAFCC",
|
||||||
"warning": "#F2A93B",
|
"warning": "#F2A93B",
|
||||||
"danger": "#E0524A",
|
"danger": "#E0524A",
|
||||||
"light": "#BFC6CE", # 高亮文本
|
"light": "#BFC6CE", # 高亮文本
|
||||||
@@ -51,14 +75,27 @@ _CALMAN_DARK_COLORS = {
|
|||||||
def register_themes() -> None:
|
def register_themes() -> None:
|
||||||
"""把自定义深色主题注册到 ttkbootstrap(可重复调用,幂等)。"""
|
"""把自定义深色主题注册到 ttkbootstrap(可重复调用,幂等)。"""
|
||||||
style = Style()
|
style = Style()
|
||||||
|
if LIGHT_THEME not in style.theme_names():
|
||||||
|
light_def = ThemeDefinition(
|
||||||
|
name=LIGHT_THEME,
|
||||||
|
themetype="light",
|
||||||
|
colors=_CALMAN_LIGHT_COLORS,
|
||||||
|
)
|
||||||
|
style.register_theme(light_def)
|
||||||
if DARK_THEME in style.theme_names():
|
if DARK_THEME in style.theme_names():
|
||||||
return
|
return
|
||||||
theme_def = ThemeDefinition(
|
dark_def = ThemeDefinition(
|
||||||
name=DARK_THEME,
|
name=DARK_THEME,
|
||||||
themetype="dark",
|
themetype="dark",
|
||||||
colors=_CALMAN_DARK_COLORS,
|
colors=_CALMAN_DARK_COLORS,
|
||||||
)
|
)
|
||||||
style.register_theme(theme_def)
|
style.register_theme(dark_def)
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_theme_name(name: Optional[str]) -> str:
|
||||||
|
if not name or name in _LEGACY_LIGHT_THEMES:
|
||||||
|
return LIGHT_THEME
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
@@ -101,7 +138,7 @@ def apply_initial_theme() -> str:
|
|||||||
返回最终生效的主题名。
|
返回最终生效的主题名。
|
||||||
"""
|
"""
|
||||||
register_themes()
|
register_themes()
|
||||||
name = get_saved_theme() or LIGHT_THEME
|
name = _normalize_theme_name(get_saved_theme())
|
||||||
style = Style()
|
style = Style()
|
||||||
if name not in style.theme_names():
|
if name not in style.theme_names():
|
||||||
name = LIGHT_THEME
|
name = LIGHT_THEME
|
||||||
@@ -113,6 +150,7 @@ def apply_initial_theme() -> str:
|
|||||||
def set_theme(name: str) -> str:
|
def set_theme(name: str) -> str:
|
||||||
"""切换到指定主题,持久化偏好,并刷新自定义样式。"""
|
"""切换到指定主题,持久化偏好,并刷新自定义样式。"""
|
||||||
register_themes()
|
register_themes()
|
||||||
|
name = _normalize_theme_name(name)
|
||||||
style = Style()
|
style = Style()
|
||||||
if name not in style.theme_names():
|
if name not in style.theme_names():
|
||||||
name = LIGHT_THEME
|
name = LIGHT_THEME
|
||||||
|
|||||||
@@ -388,50 +388,31 @@ class PQAutomationApp(
|
|||||||
if hasattr(self, "log_gui"):
|
if hasattr(self, "log_gui"):
|
||||||
self.log_gui.log(f"切换信号格式失败: {str(e)}", level="error")
|
self.log_gui.log(f"切换信号格式失败: {str(e)}", level="error")
|
||||||
|
|
||||||
def _switch_chart_tabs_by_test_type(self, test_type):
|
def _sync_custom_template_tab_visibility(self, test_type):
|
||||||
"""按测试类型切换 Gamma/EOTF 与客户模板结果 Tab。"""
|
"""按测试类型与客户模板结果状态同步客户模板 Tab 可见性。"""
|
||||||
if not hasattr(self, "chart_notebook"):
|
if not hasattr(self, "_set_custom_template_tab_visible"):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 客户模板结果 Tab 只属于 SDR Movie。
|
||||||
|
if test_type != "sdr_movie":
|
||||||
|
self._set_custom_template_tab_visible(False)
|
||||||
|
return
|
||||||
|
|
||||||
|
has_custom_rows = False
|
||||||
|
tree = getattr(self, "custom_result_tree", None)
|
||||||
|
if tree is not None:
|
||||||
try:
|
try:
|
||||||
def _safe_insert_tab(frame, text, target_pos=1):
|
has_custom_rows = len(tree.get_children()) > 0
|
||||||
"""安全插入 Tab:有目标位置则插入,否则追加到末尾。"""
|
except Exception:
|
||||||
tabs = list(self.chart_notebook.tabs())
|
has_custom_rows = False
|
||||||
if not tabs or target_pos >= len(tabs):
|
|
||||||
self.chart_notebook.add(frame, text=text)
|
|
||||||
return
|
|
||||||
before_tab_id = tabs[target_pos]
|
|
||||||
self.chart_notebook.insert(before_tab_id, frame, text=text)
|
|
||||||
|
|
||||||
current_tabs = list(self.chart_notebook.tabs())
|
# SDR 下仅在客户模板测试进行中,或已有客户模板结果时显示。
|
||||||
gamma_tab_id = str(self.gamma_chart_frame)
|
show_tab = has_custom_rows or (
|
||||||
eotf_tab_id = str(self.eotf_chart_frame)
|
getattr(self, "testing", False)
|
||||||
|
and getattr(self, "test_type_var", None) is not None
|
||||||
if test_type == "hdr_movie":
|
and self.test_type_var.get() == "sdr_movie"
|
||||||
if gamma_tab_id in current_tabs:
|
)
|
||||||
self.chart_notebook.forget(self.gamma_chart_frame)
|
self._set_custom_template_tab_visible(show_tab)
|
||||||
if eotf_tab_id not in current_tabs:
|
|
||||||
_safe_insert_tab(self.eotf_chart_frame, "EOTF 曲线", target_pos=1)
|
|
||||||
else:
|
|
||||||
if eotf_tab_id in current_tabs:
|
|
||||||
self.chart_notebook.forget(self.eotf_chart_frame)
|
|
||||||
if gamma_tab_id not in current_tabs:
|
|
||||||
_safe_insert_tab(self.gamma_chart_frame, "Gamma 曲线", target_pos=1)
|
|
||||||
|
|
||||||
custom_tab_id = str(self.custom_template_tab_frame)
|
|
||||||
current_tabs = list(self.chart_notebook.tabs())
|
|
||||||
|
|
||||||
if test_type == "sdr_movie":
|
|
||||||
if custom_tab_id not in current_tabs:
|
|
||||||
self.chart_notebook.add(self.custom_template_tab_frame, text="客户模板结果显示")
|
|
||||||
else:
|
|
||||||
if custom_tab_id in current_tabs:
|
|
||||||
self.chart_notebook.forget(self.custom_template_tab_frame)
|
|
||||||
|
|
||||||
self.chart_notebook.update_idletasks()
|
|
||||||
except Exception as e:
|
|
||||||
if hasattr(self, "log_gui"):
|
|
||||||
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):
|
||||||
"""切换测试类型"""
|
"""切换测试类型"""
|
||||||
@@ -453,7 +434,7 @@ class PQAutomationApp(
|
|||||||
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)
|
||||||
self._switch_chart_tabs_by_test_type(test_type)
|
self._sync_custom_template_tab_visibility(test_type)
|
||||||
self.sync_gamut_toolbar()
|
self.sync_gamut_toolbar()
|
||||||
self._restore_charts_for_type(test_type)
|
self._restore_charts_for_type(test_type)
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
"test_items": [
|
"test_items": [
|
||||||
"gamma"
|
"gamma"
|
||||||
],
|
],
|
||||||
"timing": "OVT 1280x 720 @ 120Hz",
|
"timing": "DMT 1920x 1080 @ 60Hz",
|
||||||
"data_range": "Full",
|
"data_range": "Full",
|
||||||
"color_format": "RGB",
|
"color_format": "RGB",
|
||||||
"bpc": 8,
|
"bpc": 8,
|
||||||
"colorimetry": "DCI-P3",
|
"colorimetry": "sRGB",
|
||||||
"patterns": {
|
"patterns": {
|
||||||
"gamut": "rgb",
|
"gamut": "rgb",
|
||||||
"gamma": "gray",
|
"gamma": "gray",
|
||||||
@@ -22,15 +22,18 @@
|
|||||||
"x_tolerance": 0.003,
|
"x_tolerance": 0.003,
|
||||||
"y_ideal": 0.329,
|
"y_ideal": 0.329,
|
||||||
"y_tolerance": 0.003
|
"y_tolerance": 0.003
|
||||||
},
|
}
|
||||||
"gamut_reference": "DCI-P3"
|
|
||||||
},
|
},
|
||||||
"sdr_movie": {
|
"sdr_movie": {
|
||||||
"name": "SDR Movie测试",
|
"name": "SDR Movie测试",
|
||||||
"test_items": [
|
"test_items": [
|
||||||
|
"gamut",
|
||||||
|
"gamma",
|
||||||
|
"cct",
|
||||||
|
"contrast",
|
||||||
"accuracy"
|
"accuracy"
|
||||||
],
|
],
|
||||||
"timing": "DMT 1680x 1050 @ 60Hz",
|
"timing": "DMT 1920x 1080 @ 60Hz",
|
||||||
"data_range": "Full",
|
"data_range": "Full",
|
||||||
"color_format": "RGB",
|
"color_format": "RGB",
|
||||||
"bpc": 8,
|
"bpc": 8,
|
||||||
@@ -48,7 +51,7 @@
|
|||||||
"y_ideal": 0.329,
|
"y_ideal": 0.329,
|
||||||
"y_tolerance": 0.003
|
"y_tolerance": 0.003
|
||||||
},
|
},
|
||||||
"gamut_reference": "DCI-P3"
|
"gamut_reference": "BT.709"
|
||||||
},
|
},
|
||||||
"hdr_movie": {
|
"hdr_movie": {
|
||||||
"name": "HDR Movie测试",
|
"name": "HDR Movie测试",
|
||||||
|
|||||||
Reference in New Issue
Block a user