优化日志显示
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""图表框架相关逻辑(Step 3 重构)。
|
||||
"""图表框架相关逻辑(Step 3 重构)。
|
||||
|
||||
从 pqAutomationApp.PQAutomationApp 中搬迁而来。每个函数第一行 `self = app`
|
||||
以保留原有 `self.xxx` 属性访问不变。
|
||||
@@ -21,7 +21,7 @@ def init_gamut_chart(self):
|
||||
canvas_widget = self.gamut_canvas.get_tk_widget()
|
||||
canvas_widget.pack(expand=True, fill=tk.BOTH)
|
||||
|
||||
# ✅ 恢复原来的大尺寸:0.84 高度
|
||||
# 恢复原来的大尺寸:0.84 高度
|
||||
self.gamut_ax_xy = self.gamut_fig.add_axes(
|
||||
[0.02, 0.08, 0.46, 0.84]
|
||||
) # ← 改回 0.84
|
||||
@@ -47,7 +47,7 @@ def init_gamut_chart(self):
|
||||
self.gamut_canvas.draw()
|
||||
|
||||
def init_gamma_chart(self):
|
||||
"""初始化Gamma曲线图表 - 左侧曲线 + 右侧表格(✅ 4列 + 通用说明)"""
|
||||
"""初始化Gamma曲线图表 - 左侧曲线 + 右侧表格(4列 + 通用说明)"""
|
||||
container = ttk.Frame(self.gamma_chart_frame)
|
||||
container.pack(expand=True, fill=tk.BOTH)
|
||||
|
||||
@@ -156,7 +156,7 @@ def init_gamma_chart(self):
|
||||
self.gamma_canvas.draw()
|
||||
|
||||
def init_eotf_chart(self):
|
||||
"""初始化 EOTF 曲线图表(HDR 专用)- 左侧曲线 + 右侧表格(✅ 4列)"""
|
||||
"""初始化 EOTF 曲线图表(HDR 专用)- 左侧曲线 + 右侧表格(4列)"""
|
||||
container = ttk.Frame(self.eotf_chart_frame)
|
||||
container.pack(expand=True, fill=tk.BOTH)
|
||||
|
||||
@@ -741,7 +741,7 @@ def update_chart_tabs_state(self):
|
||||
|
||||
except Exception as e:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"更新Tab状态失败: {str(e)}")
|
||||
self.log_gui.log(f"更新Tab状态失败: {str(e)}", level="error")
|
||||
|
||||
def create_result_chart_frame(self):
|
||||
"""创建结果图表区域 - 6个独立Tab(Gamma 和 EOTF 分离)"""
|
||||
@@ -790,10 +790,10 @@ def create_result_chart_frame(self):
|
||||
# 绑定Tab切换事件
|
||||
self.chart_notebook.bind("<<NotebookTabChanged>>", self.on_chart_tab_changed)
|
||||
|
||||
# ==================== ✅ 在图表下方创建单步调试面板 ====================
|
||||
# ==================== 在图表下方创建单步调试面板 ====================
|
||||
self.debug_container = ttk.LabelFrame(
|
||||
self.result_frame, # ← 放在 result_frame 内,图表正下方
|
||||
text="🔧 单步调试",
|
||||
text=" 单步调试",
|
||||
padding=10,
|
||||
)
|
||||
# 默认不显示
|
||||
@@ -801,7 +801,7 @@ def create_result_chart_frame(self):
|
||||
# 创建单步调试面板实例
|
||||
self.debug_panel = PQDebugPanel(self.debug_container, self)
|
||||
|
||||
self.log_gui.log("✓ 单步调试面板已创建(放在测试结果图表下方)")
|
||||
self.log_gui.log("单步调试面板已创建(放在测试结果图表下方)", level="success")
|
||||
|
||||
def on_chart_tab_changed(self, event):
|
||||
"""Tab切换时的事件处理"""
|
||||
@@ -810,5 +810,5 @@ def on_chart_tab_changed(self, event):
|
||||
self.chart_notebook.select()
|
||||
)
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"Tab切换事件处理失败: {str(e)}")
|
||||
self.log_gui.log(f"Tab切换事件处理失败: {str(e)}", level="error")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""CCT 参数面板及其处理函数(与主文件重构版本保持同步)。"""
|
||||
"""CCT 参数面板及其处理函数(与主文件重构版本保持同步)。"""
|
||||
|
||||
import time
|
||||
import traceback
|
||||
@@ -10,7 +10,7 @@ import algorithm.pq_algorithm as pq_algorithm
|
||||
|
||||
|
||||
def create_cct_params_frame(self):
|
||||
"""创建色度参数设置区域 - 屏模组、SDR、HDR 独立(✅ 增加色域参考标准选择 + 单步调试按钮)"""
|
||||
"""创建色度参数设置区域 - 屏模组、SDR、HDR 独立(增加色域参考标准选择 + 单步调试按钮)"""
|
||||
|
||||
# ==================== 屏模组色度参数 Frame ====================
|
||||
self.cct_params_frame = ttk.LabelFrame(
|
||||
@@ -84,7 +84,7 @@ def create_cct_params_frame(self):
|
||||
)
|
||||
self.screen_gamut_combo = screen_gamut_combo
|
||||
|
||||
# ==================== ✅ 单步调试按钮(右侧第二行)====================
|
||||
# ==================== 单步调试按钮(右侧第二行)====================
|
||||
ttk.Label(self.cct_params_frame, text="单步调试:").grid(
|
||||
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
||||
)
|
||||
@@ -94,7 +94,7 @@ def create_cct_params_frame(self):
|
||||
text="打开调试面板",
|
||||
command=self.toggle_screen_debug_panel,
|
||||
bootstyle="info-outline",
|
||||
state=tk.DISABLED, # 初始禁用
|
||||
# state=tk.DISABLED, # 初始禁用
|
||||
width=15,
|
||||
)
|
||||
self.screen_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
||||
@@ -201,7 +201,7 @@ def create_cct_params_frame(self):
|
||||
sdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_sdr_gamut_ref_changed)
|
||||
self.sdr_gamut_combo = sdr_gamut_combo
|
||||
|
||||
# ==================== ✅ SDR 单步调试按钮(右侧第二行)====================
|
||||
# ==================== SDR 单步调试按钮(右侧第二行)====================
|
||||
ttk.Label(self.sdr_cct_params_frame, text="单步调试:").grid(
|
||||
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
||||
)
|
||||
@@ -211,7 +211,7 @@ def create_cct_params_frame(self):
|
||||
text="打开调试面板",
|
||||
command=self.toggle_sdr_debug_panel,
|
||||
bootstyle="info-outline",
|
||||
state=tk.DISABLED, # 初始禁用
|
||||
# state=tk.DISABLED, # 初始禁用
|
||||
width=15,
|
||||
)
|
||||
self.sdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
||||
@@ -318,7 +318,7 @@ def create_cct_params_frame(self):
|
||||
hdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_hdr_gamut_ref_changed)
|
||||
self.hdr_gamut_combo = hdr_gamut_combo
|
||||
|
||||
# ==================== ✅ HDR 单步调试按钮(右侧第二行)====================
|
||||
# ==================== HDR 单步调试按钮(右侧第二行)====================
|
||||
ttk.Label(self.hdr_cct_params_frame, text="单步调试:").grid(
|
||||
row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
|
||||
)
|
||||
@@ -328,7 +328,7 @@ def create_cct_params_frame(self):
|
||||
text="打开调试面板",
|
||||
command=self.toggle_hdr_debug_panel,
|
||||
bootstyle="info-outline",
|
||||
state=tk.DISABLED, # 初始禁用
|
||||
# state=tk.DISABLED, # 初始禁用
|
||||
width=15,
|
||||
)
|
||||
self.hdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)
|
||||
@@ -427,7 +427,7 @@ def _handle_cct_focus_out(self, var, default_value, save_func, label):
|
||||
if value == "":
|
||||
var.set(str(default_value))
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"✓ {label} 参数为空,恢复默认值: {default_value}")
|
||||
self.log_gui.log(f"{label} 参数为空,恢复默认值: {default_value}", level="success")
|
||||
else:
|
||||
try:
|
||||
float_val = float(value)
|
||||
@@ -435,19 +435,19 @@ def _handle_cct_focus_out(self, var, default_value, save_func, label):
|
||||
var.set(str(default_value))
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(
|
||||
f"⚠️ {label} 参数超出范围,恢复默认值: {default_value}"
|
||||
)
|
||||
f"{label} 参数超出范围,恢复默认值: {default_value}"
|
||||
, level="error")
|
||||
except ValueError:
|
||||
var.set(str(default_value))
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(
|
||||
f"⚠️ {label} 参数无效,恢复默认值: {default_value}"
|
||||
)
|
||||
f"{label} 参数无效,恢复默认值: {default_value}"
|
||||
, level="error")
|
||||
|
||||
save_func()
|
||||
except Exception as e:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"处理 {label} 参数失败: {str(e)}")
|
||||
self.log_gui.log(f"处理 {label} 参数失败: {str(e)}", level="error")
|
||||
|
||||
|
||||
def on_sdr_cct_param_focus_out(self, var, default_value):
|
||||
@@ -475,7 +475,7 @@ def recalculate_cct(self):
|
||||
try:
|
||||
# 1. 保存新参数
|
||||
self.save_cct_params()
|
||||
self.log_gui.log("✓ 色度参数已更新")
|
||||
self.log_gui.log("色度参数已更新", level="success")
|
||||
|
||||
# 2. 收起配置项
|
||||
if hasattr(self, "config_panel_frame"):
|
||||
@@ -493,7 +493,7 @@ def recalculate_cct(self):
|
||||
|
||||
# 4. 检查是否有数据
|
||||
if not hasattr(self, "results") or not self.results:
|
||||
self.log_gui.log("⚠️ 没有测试数据,无法重新绘制")
|
||||
self.log_gui.log("没有测试数据,无法重新绘制", level="error")
|
||||
messagebox.showwarning("警告", "请先完成测试后再重新计算")
|
||||
return
|
||||
|
||||
@@ -503,14 +503,14 @@ def recalculate_cct(self):
|
||||
gray_data = self.results.get_intermediate_data("cct", "gray")
|
||||
|
||||
if not gray_data or len(gray_data) < 2:
|
||||
self.log_gui.log("⚠️ 没有可用的灰阶数据")
|
||||
self.log_gui.log("没有可用的灰阶数据", level="error")
|
||||
messagebox.showwarning("警告", "没有找到色度测试数据")
|
||||
return
|
||||
|
||||
# 6. 重新计算 CCT
|
||||
self.log_gui.log("=" * 50)
|
||||
self.log_gui.log("开始重新计算色度一致性...")
|
||||
self.log_gui.log("=" * 50)
|
||||
self.log_gui.log("=" * 50, level="separator")
|
||||
self.log_gui.log("开始重新计算色度一致性...", level="info")
|
||||
self.log_gui.log("=" * 50, level="separator")
|
||||
|
||||
cct_values = pq_algorithm.calculate_cct_from_results(gray_data)
|
||||
|
||||
@@ -521,14 +521,14 @@ def recalculate_cct(self):
|
||||
test_type = self.config.current_test_type
|
||||
self.plot_cct(test_type)
|
||||
|
||||
self.log_gui.log("✓ 色度图已重新绘制")
|
||||
self.log_gui.log("=" * 50)
|
||||
self.log_gui.log("色度图已重新绘制", level="success")
|
||||
self.log_gui.log("=" * 50, level="separator")
|
||||
|
||||
messagebox.showinfo("成功", "色度图已根据新参数重新绘制!")
|
||||
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"❌ 重新计算失败: {str(e)}")
|
||||
self.log_gui.log(traceback.format_exc())
|
||||
self.log_gui.log(f"[Error] 重新计算失败: {str(e)}", level="error")
|
||||
self.log_gui.log(traceback.format_exc(), level="error")
|
||||
messagebox.showerror("错误", f"重新计算失败: {str(e)}")
|
||||
|
||||
|
||||
@@ -551,7 +551,7 @@ def recalculate_gamut(self):
|
||||
|
||||
# 3. 检查是否有数据
|
||||
if not hasattr(self, "results") or not self.results:
|
||||
self.log_gui.log("⚠️ 没有测试数据,无法重新绘制")
|
||||
self.log_gui.log("没有测试数据,无法重新绘制", level="error")
|
||||
messagebox.showwarning("警告", "请先完成测试后再重新计算")
|
||||
return
|
||||
|
||||
@@ -559,7 +559,7 @@ def recalculate_gamut(self):
|
||||
rgb_data = self.results.get_intermediate_data("gamut", "rgb")
|
||||
|
||||
if not rgb_data or len(rgb_data) < 3:
|
||||
self.log_gui.log("⚠️ 没有可用的色域数据")
|
||||
self.log_gui.log("没有可用的色域数据", level="error")
|
||||
messagebox.showwarning("警告", "没有找到色域测试数据")
|
||||
return
|
||||
|
||||
@@ -576,9 +576,9 @@ def recalculate_gamut(self):
|
||||
else:
|
||||
reference_standard = "DCI-P3"
|
||||
|
||||
self.log_gui.log("=" * 50)
|
||||
self.log_gui.log(f"开始重新计算色域(参考标准: {reference_standard})...")
|
||||
self.log_gui.log("=" * 50)
|
||||
self.log_gui.log("=" * 50, level="separator")
|
||||
self.log_gui.log(f"开始重新计算色域(参考标准: {reference_standard})...", level="info")
|
||||
self.log_gui.log("=" * 50, level="separator")
|
||||
|
||||
# 7. 重新计算 XY 色域覆盖率
|
||||
xy_points = [[result[0], result[1]] for result in rgb_data]
|
||||
@@ -602,10 +602,10 @@ def recalculate_gamut(self):
|
||||
)
|
||||
reference_standard = "DCI-P3"
|
||||
|
||||
self.log_gui.log(f"✓ 参考标准: {reference_standard}")
|
||||
self.log_gui.log(f"✓ XY 色域覆盖率: {coverage_xy:.1f}%")
|
||||
self.log_gui.log(f"参考标准: {reference_standard}", level="success")
|
||||
self.log_gui.log(f"XY 色域覆盖率: {coverage_xy:.1f}%", level="success")
|
||||
|
||||
# ========== ✅✅✅ 8. 重新计算 UV 色域覆盖率 ==========
|
||||
# ========== ✅✅8. 重新计算 UV 色域覆盖率 ==========
|
||||
# 将 XY 坐标转换为 UV 坐标
|
||||
uv_points = []
|
||||
for x, y in xy_points:
|
||||
@@ -621,7 +621,7 @@ def recalculate_gamut(self):
|
||||
except ZeroDivisionError:
|
||||
continue
|
||||
|
||||
self.log_gui.log(f"✓ 转换后的 UV 点数量: {len(uv_points)}")
|
||||
self.log_gui.log(f"转换后的 UV 点数量: {len(uv_points)}", level="success")
|
||||
|
||||
# 根据参考标准计算 UV 覆盖率
|
||||
if reference_standard == "BT.2020":
|
||||
@@ -641,10 +641,10 @@ def recalculate_gamut(self):
|
||||
uv_points
|
||||
)
|
||||
|
||||
self.log_gui.log(f"✓ UV 色域覆盖率: {coverage_uv:.1f}%")
|
||||
self.log_gui.log(f"UV 色域覆盖率: {coverage_uv:.1f}%", level="success")
|
||||
# ========================================================
|
||||
|
||||
# 9. ✅ 更新结果(同时保存 XY 和 UV 覆盖率)
|
||||
# 9. 更新结果(同时保存 XY 和 UV 覆盖率)
|
||||
self.results.set_test_item_result(
|
||||
"gamut",
|
||||
{
|
||||
@@ -659,13 +659,13 @@ def recalculate_gamut(self):
|
||||
},
|
||||
)
|
||||
|
||||
self.log_gui.log("✓ 测试结果已更新到 results 对象")
|
||||
self.log_gui.log("测试结果已更新到 results 对象", level="success")
|
||||
|
||||
# 10. 重新绘制色域图
|
||||
self.plot_gamut(rgb_data, coverage_xy, test_type)
|
||||
|
||||
self.log_gui.log("✓ 色域图已重新绘制")
|
||||
self.log_gui.log("=" * 50)
|
||||
self.log_gui.log("色域图已重新绘制", level="success")
|
||||
self.log_gui.log("=" * 50, level="separator")
|
||||
|
||||
messagebox.showinfo(
|
||||
"成功",
|
||||
@@ -675,8 +675,8 @@ def recalculate_gamut(self):
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"❌ 重新计算失败: {str(e)}")
|
||||
self.log_gui.log(traceback.format_exc())
|
||||
self.log_gui.log(f"[Error] 重新计算失败: {str(e)}", level="error")
|
||||
self.log_gui.log(traceback.format_exc(), level="error")
|
||||
messagebox.showerror("错误", f"重新计算失败: {str(e)}")
|
||||
|
||||
|
||||
@@ -709,7 +709,7 @@ def reload_cct_params(self):
|
||||
|
||||
except Exception as e:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"重新加载色度参数失败: {str(e)}")
|
||||
self.log_gui.log(f"重新加载色度参数失败: {str(e)}", level="error")
|
||||
|
||||
|
||||
def toggle_cct_params_frame(self):
|
||||
@@ -743,7 +743,7 @@ def toggle_cct_params_frame(self):
|
||||
self.hdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5)
|
||||
else:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log("[ERROR] HDR 色度参数框尚未创建")
|
||||
self.log_gui.log("[ERROR] HDR 色度参数框尚未创建", level="error")
|
||||
|
||||
|
||||
# ---- gamut 参考标准改变回调(统一实现) ----
|
||||
@@ -758,14 +758,14 @@ def _on_gamut_ref_changed(self, test_type, event=None):
|
||||
cfg = _GAMUT_REF_CONFIGS[test_type]
|
||||
try:
|
||||
new_ref = getattr(self, cfg["var_attr"]).get()
|
||||
self.log_gui.log(f"✓ {cfg['label']} 色域参考标准已更改为: {new_ref}")
|
||||
self.log_gui.log(f"{cfg['label']} 色域参考标准已更改为: {new_ref}", level="success")
|
||||
|
||||
if test_type not in self.config.current_test_types:
|
||||
self.config.current_test_types[test_type] = {}
|
||||
self.config.current_test_types[test_type]["gamut_reference"] = new_ref
|
||||
self.save_pq_config()
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"保存 {cfg['label']} 色域参考标准失败: {str(e)}")
|
||||
self.log_gui.log(f"保存 {cfg['label']} 色域参考标准失败: {str(e)}", level="error")
|
||||
|
||||
|
||||
def on_screen_gamut_ref_changed(self, event=None):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""自定义模板结果面板(Step 6 重构)。"""
|
||||
"""自定义模板结果面板(Step 6 重构)。"""
|
||||
|
||||
import threading
|
||||
import time
|
||||
@@ -274,7 +274,7 @@ def _run_custom_row_single_step(self, item_id, row_no):
|
||||
"""后台执行客户模板单步测试"""
|
||||
try:
|
||||
self._dispatch_ui(self.status_var.set, f"单步测试第 {row_no} 行...")
|
||||
self.log_gui.log(f"开始单步测试第 {row_no} 行")
|
||||
self.log_gui.log(f"开始单步测试第 {row_no} 行", level="info")
|
||||
|
||||
self.config.set_current_pattern("custom")
|
||||
|
||||
@@ -295,7 +295,7 @@ def _run_custom_row_single_step(self, item_id, row_no):
|
||||
)
|
||||
|
||||
if row_no > len(converted_params):
|
||||
self.log_gui.log(f"❌ 行号超出 pattern 范围: {row_no}/{len(converted_params)}")
|
||||
self.log_gui.log(f"[Error] 行号超出 pattern 范围: {row_no}/{len(converted_params)}", level="error")
|
||||
self._dispatch_ui(self.status_var.set, "单步测试失败:行号超范围")
|
||||
return
|
||||
|
||||
@@ -335,11 +335,11 @@ def _run_custom_row_single_step(self, item_id, row_no):
|
||||
self._update_custom_result_row, item_id, row_no, row_data
|
||||
)
|
||||
|
||||
self.log_gui.log(f"✓ 第 {row_no} 行单步测试完成并已覆盖")
|
||||
self.log_gui.log(f"第 {row_no} 行单步测试完成并已覆盖", level="success")
|
||||
self._dispatch_ui(self.status_var.set, f"第 {row_no} 行单步测试完成")
|
||||
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"❌ 单步测试失败: {str(e)}")
|
||||
self.log_gui.log(f"[Error] 单步测试失败: {str(e)}", level="error")
|
||||
self._dispatch_ui(self.status_var.set, "单步测试失败")
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ def copy_custom_result_table(self):
|
||||
if hasattr(self, "status_var"):
|
||||
self.status_var.set(f"已复制 {len(items)} 行客户模板数据到剪贴板")
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"✓ 已复制客户模板表格数据({len(items)} 行)")
|
||||
self.log_gui.log(f"已复制客户模板表格数据({len(items)} 行)", level="success")
|
||||
|
||||
|
||||
def fill_custom_result_test_data(self):
|
||||
@@ -465,7 +465,7 @@ def fill_custom_result_test_data(self):
|
||||
if hasattr(self, "status_var"):
|
||||
self.status_var.set("已填充 147 行客户模板测试数据")
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log("✓ 已填充 147 行客户模板测试数据")
|
||||
self.log_gui.log("已填充 147 行客户模板测试数据", level="success")
|
||||
|
||||
|
||||
def clear_custom_template_results(self):
|
||||
@@ -511,7 +511,7 @@ def auto_expand_custom_result_view(self):
|
||||
self.root.update_idletasks()
|
||||
except Exception as e:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"⚠️ 自动扩展客户模板窗口失败: {str(e)}")
|
||||
self.log_gui.log(f"自动扩展客户模板窗口失败: {str(e)}", level="error")
|
||||
|
||||
|
||||
def append_custom_template_result(self, row_no, result_data):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""主布局面板创建函数(Step 6 重构)。"""
|
||||
"""主布局面板创建函数(Step 6 重构)。"""
|
||||
|
||||
import re
|
||||
import tkinter as tk
|
||||
@@ -405,7 +405,7 @@ def create_test_type_frame(self):
|
||||
fill=tk.X, padx=10, pady=10
|
||||
)
|
||||
|
||||
# ✅ 只保留日志按钮
|
||||
# 只保留日志按钮
|
||||
self.log_btn = ttk.Button(
|
||||
self.sidebar_frame,
|
||||
text="测试日志",
|
||||
@@ -515,7 +515,7 @@ def on_screen_module_timing_changed(self, event=None):
|
||||
selected_timing = self.screen_module_timing_var.get()
|
||||
|
||||
# 记录日志
|
||||
self.log_gui.log(f"屏模组信号格式已更改为: {selected_timing}")
|
||||
self.log_gui.log(f"屏模组信号格式已更改为: {selected_timing}", level="info")
|
||||
|
||||
match = re.search(r"(\d+)x(\d+)\s*@\s*(\d+)", selected_timing)
|
||||
if match:
|
||||
@@ -523,28 +523,28 @@ def on_screen_module_timing_changed(self, event=None):
|
||||
height = int(match.group(2))
|
||||
refresh_rate = int(match.group(3))
|
||||
|
||||
self.log_gui.log(f" ├─ 分辨率: {width}x{height}")
|
||||
self.log_gui.log(f" └─ 刷新率: {refresh_rate}Hz")
|
||||
self.log_gui.log(f" ├─ 分辨率: {width}x{height}", level="info")
|
||||
self.log_gui.log(f" └─ 刷新率: {refresh_rate}Hz", level="info")
|
||||
|
||||
# 根据分辨率给出提示
|
||||
if width >= 3840: # 4K及以上
|
||||
self.log_gui.log(" ℹ️ 检测到4K分辨率")
|
||||
self.log_gui.log(" ℹ️ 检测到4K分辨率", level="info")
|
||||
|
||||
if refresh_rate >= 120:
|
||||
self.log_gui.log(" ℹ️ 检测到高刷新率")
|
||||
self.log_gui.log(" ℹ️ 检测到高刷新率", level="info")
|
||||
|
||||
# 更新配置
|
||||
self.config.set_current_timing(selected_timing)
|
||||
|
||||
# 如果正在测试,提示用户
|
||||
if self.testing:
|
||||
self.log_gui.log("⚠️ 警告: 测试进行中,信号格式更改将在下次测试时生效")
|
||||
self.log_gui.log("警告: 测试进行中,信号格式更改将在下次测试时生效", level="error")
|
||||
|
||||
# 保存配置
|
||||
self.save_pq_config()
|
||||
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"❌ 屏模组信号格式更改失败: {str(e)}")
|
||||
self.log_gui.log(f"[Error] 屏模组信号格式更改失败: {str(e)}", level="error")
|
||||
|
||||
|
||||
def update_test_items(self):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""侧边面板(日志 / Local Dimming / 调试)(Step 6 重构)。"""
|
||||
"""侧边面板(日志 / Local Dimming / 调试)(Step 6 重构)。"""
|
||||
|
||||
import traceback
|
||||
import tkinter as tk
|
||||
@@ -141,7 +141,7 @@ def create_local_dimming_panel(self):
|
||||
|
||||
self.ld_clear_btn = ttk.Button(
|
||||
bottom_frame,
|
||||
text="🗑️ 清空记录",
|
||||
text="清空记录",
|
||||
command=self.clear_ld_records,
|
||||
bootstyle="danger-outline",
|
||||
width=12,
|
||||
@@ -187,7 +187,7 @@ DEBUG_PANEL_CONFIGS = {
|
||||
"screen_module": {
|
||||
"window_attr": "debug_window",
|
||||
"btn_attr": "screen_debug_btn",
|
||||
"title": "🔧 单步调试面板",
|
||||
"title": " 单步调试面板",
|
||||
"window_log_prefix": "",
|
||||
"data_log_prefix": "屏模组",
|
||||
"failure_data_label": "调试数据",
|
||||
@@ -200,7 +200,7 @@ DEBUG_PANEL_CONFIGS = {
|
||||
"sdr_movie": {
|
||||
"window_attr": "sdr_debug_window",
|
||||
"btn_attr": "sdr_debug_btn",
|
||||
"title": "🔧 SDR 单步调试面板",
|
||||
"title": " SDR 单步调试面板",
|
||||
"window_log_prefix": "SDR ",
|
||||
"data_log_prefix": "SDR",
|
||||
"failure_data_label": "SDR 调试数据",
|
||||
@@ -213,7 +213,7 @@ DEBUG_PANEL_CONFIGS = {
|
||||
"hdr_movie": {
|
||||
"window_attr": "hdr_debug_window",
|
||||
"btn_attr": "hdr_debug_btn",
|
||||
"title": "🔧 HDR 单步调试面板",
|
||||
"title": " HDR 单步调试面板",
|
||||
"window_log_prefix": "HDR ",
|
||||
"data_log_prefix": "HDR",
|
||||
"failure_data_label": "HDR 调试数据",
|
||||
@@ -238,7 +238,6 @@ def _toggle_debug_panel(self, test_type):
|
||||
if existing is not None and existing.winfo_exists():
|
||||
existing.destroy()
|
||||
btn.config(text="打开调试面板")
|
||||
self.log_gui.log(f"✓ {wlp}单步调试面板已关闭")
|
||||
return
|
||||
|
||||
# 创建新窗口
|
||||
@@ -255,38 +254,40 @@ def _toggle_debug_panel(self, test_type):
|
||||
# 创建调试面板实例(不要对它调用 pack)
|
||||
debug_panel_instance = PQDebugPanel(debug_container, self)
|
||||
|
||||
self.log_gui.log(f"✓ {wlp}单步调试面板实例已创建")
|
||||
|
||||
# 重新启用调试(如果有数据)
|
||||
try:
|
||||
selected_items = self.get_selected_test_items()
|
||||
dlp = cfg["data_log_prefix"]
|
||||
for item_key, debug_key, (cat, sub), data_label, enable_desc in cfg["data_items"]:
|
||||
if item_key not in selected_items:
|
||||
continue
|
||||
data = self.results.get_intermediate_data(cat, sub)
|
||||
if not data:
|
||||
if test_type == "screen_module" and item_key == "gamma":
|
||||
self.log_gui.log(" ✗ 没有可用的灰阶数据")
|
||||
continue
|
||||
self.log_gui.log(f" → 加载 {len(data)} 个{data_label}数据点")
|
||||
debug_panel_instance.enable_debug(test_type, debug_key, data)
|
||||
self.log_gui.log(f"✓ {dlp} {enable_desc}已重新启用")
|
||||
results_obj = getattr(self, "results", None)
|
||||
if results_obj is None:
|
||||
self.log_gui.log(f"{dlp} 暂无可用测试结果,面板已打开", level="warning")
|
||||
else:
|
||||
for item_key, debug_key, (cat, sub), data_label, enable_desc in cfg["data_items"]:
|
||||
if item_key not in selected_items:
|
||||
continue
|
||||
data = results_obj.get_intermediate_data(cat, sub)
|
||||
if not data:
|
||||
if test_type == "screen_module" and item_key == "gamma":
|
||||
self.log_gui.log("[Error] 没有可用的灰阶数据", level="error")
|
||||
continue
|
||||
self.log_gui.log(f" → 加载 {len(data)} 个{data_label}数据点", level="info")
|
||||
debug_panel_instance.enable_debug(test_type, debug_key, data)
|
||||
self.log_gui.log(f"{dlp} {enable_desc}已重新启用", level="success")
|
||||
except Exception as e:
|
||||
self.log_gui.log(f"⚠️ 加载{cfg['failure_data_label']}失败: {str(e)}")
|
||||
self.log_gui.log(traceback.format_exc())
|
||||
self.log_gui.log(f"加载{cfg['failure_data_label']}失败: {str(e)}", level="error")
|
||||
self.log_gui.log(traceback.format_exc(), level="error")
|
||||
|
||||
btn.config(text="关闭调试面板")
|
||||
|
||||
def on_closing():
|
||||
btn.config(text="打开调试面板")
|
||||
getattr(self, win_attr).destroy()
|
||||
self.log_gui.log(f"✓ {wlp}单步调试窗口已关闭")
|
||||
self.log_gui.log(f"{wlp}单步调试窗口已关闭", level="success")
|
||||
|
||||
win.protocol("WM_DELETE_WINDOW", on_closing)
|
||||
win.update_idletasks()
|
||||
|
||||
self.log_gui.log(f"✓ {wlp}单步调试面板已打开(独立窗口)")
|
||||
self.log_gui.log(f"{wlp}单步调试面板已打开(独立窗口)", level="success")
|
||||
|
||||
|
||||
def toggle_screen_debug_panel(self):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""
|
||||
"""
|
||||
PQ 单步调试面板
|
||||
支持屏模组、SDR、HDR 三种测试类型的单步调试功能
|
||||
"""
|
||||
@@ -34,7 +34,7 @@ class PQDebugPanel:
|
||||
# 原始测试数据(用于对比)
|
||||
self.original_data = {}
|
||||
|
||||
# ==================== ✅ 创建主容器并自动 pack ====================
|
||||
# ==================== 创建主容器并自动 pack ====================
|
||||
self.main_container = ttk.Frame(parent)
|
||||
self.main_container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
@@ -600,13 +600,13 @@ class PQDebugPanel:
|
||||
|
||||
if test_type == "screen_module":
|
||||
self.screen_frame.pack(fill=tk.BOTH, expand=True)
|
||||
self.app.log_gui.log("✓ 显示屏模组调试面板")
|
||||
self.app.log_gui.log("显示屏模组调试面板", level="success")
|
||||
elif test_type == "sdr_movie":
|
||||
self.sdr_frame.pack(fill=tk.BOTH, expand=True)
|
||||
self.app.log_gui.log("✓ 显示 SDR 调试面板")
|
||||
self.app.log_gui.log("显示 SDR 调试面板", level="success")
|
||||
elif test_type == "hdr_movie":
|
||||
self.hdr_frame.pack(fill=tk.BOTH, expand=True)
|
||||
self.app.log_gui.log("✓ 显示 HDR 调试面板")
|
||||
self.app.log_gui.log("显示 HDR 调试面板", level="success")
|
||||
|
||||
# ==================== 启用/禁用控制 ====================
|
||||
|
||||
@@ -631,39 +631,39 @@ class PQDebugPanel:
|
||||
if test_item == "gamma":
|
||||
self.screen_gray_combo.config(state="readonly")
|
||||
self.screen_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ 屏模组 Gamma 单步调试已启用")
|
||||
self.app.log_gui.log("屏模组 Gamma 单步调试已启用", level="success")
|
||||
elif test_item == "rgb":
|
||||
self.screen_rgb_combo.config(state="readonly")
|
||||
self.screen_rgb_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ 屏模组 RGB 单步调试已启用")
|
||||
self.app.log_gui.log("屏模组 RGB 单步调试已启用", level="success")
|
||||
|
||||
elif test_type == "sdr_movie":
|
||||
if test_item == "gamma":
|
||||
self.sdr_gray_combo.config(state="readonly")
|
||||
self.sdr_gamma_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ SDR Gamma 单步调试已启用")
|
||||
self.app.log_gui.log("SDR Gamma 单步调试已启用", level="success")
|
||||
elif test_item == "accuracy":
|
||||
self.sdr_color_combo.config(state="readonly")
|
||||
self.sdr_accuracy_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ SDR 色准单步调试已启用")
|
||||
self.app.log_gui.log("SDR 色准单步调试已启用", level="success")
|
||||
elif test_item == "rgb":
|
||||
self.sdr_rgb_combo.config(state="readonly")
|
||||
self.sdr_rgb_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ SDR RGB 单步调试已启用")
|
||||
self.app.log_gui.log("SDR RGB 单步调试已启用", level="success")
|
||||
|
||||
elif test_type == "hdr_movie":
|
||||
if test_item == "eotf":
|
||||
self.hdr_gray_combo.config(state="readonly")
|
||||
self.hdr_eotf_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ HDR EOTF 单步调试已启用")
|
||||
self.app.log_gui.log("HDR EOTF 单步调试已启用", level="success")
|
||||
elif test_item == "accuracy":
|
||||
self.hdr_color_combo.config(state="readonly")
|
||||
self.hdr_accuracy_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ HDR 色准单步调试已启用")
|
||||
self.app.log_gui.log("HDR 色准单步调试已启用", level="success")
|
||||
elif test_item == "rgb":
|
||||
self.hdr_rgb_combo.config(state="readonly")
|
||||
self.hdr_rgb_test_btn.config(state=tk.NORMAL)
|
||||
self.app.log_gui.log("✓ HDR RGB 单步调试已启用")
|
||||
self.app.log_gui.log("HDR RGB 单步调试已启用", level="success")
|
||||
|
||||
def disable_all_debug(self):
|
||||
"""禁用所有单步调试(新测试开始时调用)"""
|
||||
@@ -759,11 +759,11 @@ class PQDebugPanel:
|
||||
def _run_single_step_thread(self, test_type, test_item, selected):
|
||||
"""单步测试线程"""
|
||||
try:
|
||||
self.app.log_gui.log("=" * 50)
|
||||
self.app.log_gui.log("=" * 50, level="info")
|
||||
self.app.log_gui.log(
|
||||
f"开始单步调试: {test_type} - {test_item} - {selected}"
|
||||
)
|
||||
self.app.log_gui.log("=" * 50)
|
||||
, level="info")
|
||||
self.app.log_gui.log("=" * 50, level="info")
|
||||
|
||||
# 禁用按钮
|
||||
self._disable_test_button(test_type, test_item)
|
||||
@@ -796,9 +796,9 @@ class PQDebugPanel:
|
||||
x, y, lv, X, Y, Z = self.app.ca.readAllDisplay()
|
||||
|
||||
self.app.log_gui.log(
|
||||
f"✓ 测量完成: x={x:.4f}, y={y:.4f}, lv={lv:.2f}, "
|
||||
f"测量完成: x={x:.4f}, y={y:.4f}, lv={lv:.2f}, "
|
||||
f"X={X:.4f}, Y={Y:.4f}, Z={Z:.4f}"
|
||||
)
|
||||
, level="success")
|
||||
|
||||
# 对比数据
|
||||
self._compare_and_display(
|
||||
@@ -809,10 +809,10 @@ class PQDebugPanel:
|
||||
self._enable_test_button(test_type, test_item)
|
||||
|
||||
except Exception as e:
|
||||
self.app.log_gui.log(f"❌ 单步测试失败: {str(e)}")
|
||||
self.app.log_gui.log(f"[Error] 单步测试失败: {str(e)}", level="error")
|
||||
import traceback
|
||||
|
||||
self.app.log_gui.log(traceback.format_exc())
|
||||
self.app.log_gui.log(traceback.format_exc(), level="error")
|
||||
self._enable_test_button(test_type, test_item)
|
||||
|
||||
def _setup_signal_format(self, test_type):
|
||||
@@ -842,7 +842,7 @@ class PQDebugPanel:
|
||||
# 获取原始数据
|
||||
key = f"{test_type}_{test_item}"
|
||||
if key not in self.original_data:
|
||||
self.app.log_gui.log("⚠️ 未找到原始测试数据")
|
||||
self.app.log_gui.log("未找到原始测试数据", level="error")
|
||||
return
|
||||
|
||||
original_data_list = self.original_data[key]
|
||||
@@ -856,12 +856,12 @@ class PQDebugPanel:
|
||||
index = self.get_rgb_index(selected)
|
||||
|
||||
if index >= len(original_data_list):
|
||||
self.app.log_gui.log(f"⚠️ 索引超出范围: {index}")
|
||||
self.app.log_gui.log(f"索引超出范围: {index}", level="error")
|
||||
return
|
||||
|
||||
original_data = original_data_list[index]
|
||||
|
||||
# ==================== ✅ 构建对比数据 ====================
|
||||
# ==================== 构建对比数据 ====================
|
||||
comparison = {}
|
||||
|
||||
if test_item == "gamma":
|
||||
@@ -1140,57 +1140,57 @@ class PQDebugPanel:
|
||||
def _get_delta_e_from_results(self, test_type, color_name):
|
||||
"""从原始测试结果中读取 ΔE 值"""
|
||||
try:
|
||||
self.app.log_gui.log(f"[读取 ΔE] 开始:")
|
||||
self.app.log_gui.log(f" test_type = {test_type}")
|
||||
self.app.log_gui.log(f" color_name = {color_name}")
|
||||
self.app.log_gui.log(f"[读取 ΔE] 开始:", level="info")
|
||||
self.app.log_gui.log(f" test_type = {test_type}", level="info")
|
||||
self.app.log_gui.log(f" color_name = {color_name}", level="info")
|
||||
|
||||
# ✅ 正确的访问方式:通过 test_items
|
||||
# 正确的访问方式:通过 test_items
|
||||
if "accuracy" not in self.app.results.test_items:
|
||||
self.app.log_gui.log(" ✗ 未找到 accuracy 测试项")
|
||||
self.app.log_gui.log("[Error] 未找到 accuracy 测试项", level="error")
|
||||
return 0.0
|
||||
|
||||
test_item = self.app.results.test_items["accuracy"]
|
||||
accuracy_result = test_item.final_result
|
||||
|
||||
self.app.log_gui.log(f" accuracy_result = {accuracy_result is not None}")
|
||||
self.app.log_gui.log(f" accuracy_result = {accuracy_result is not None}", level="info")
|
||||
|
||||
if not accuracy_result:
|
||||
self.app.log_gui.log(" ✗ accuracy_result 为空")
|
||||
self.app.log_gui.log("[Error] accuracy_result 为空", level="error")
|
||||
return 0.0
|
||||
|
||||
# 获取色块名称列表和 ΔE 值列表
|
||||
color_patches = accuracy_result.get("color_patches", [])
|
||||
delta_e_values = accuracy_result.get("delta_e_values", [])
|
||||
|
||||
self.app.log_gui.log(f" color_patches 数量: {len(color_patches)}")
|
||||
self.app.log_gui.log(f" delta_e_values 数量: {len(delta_e_values)}")
|
||||
self.app.log_gui.log(f" color_patches 数量: {len(color_patches)}", level="info")
|
||||
self.app.log_gui.log(f" delta_e_values 数量: {len(delta_e_values)}", level="info")
|
||||
|
||||
if color_patches:
|
||||
self.app.log_gui.log(f" 前3个色块: {color_patches[:3]}")
|
||||
self.app.log_gui.log(f" 前3个色块: {color_patches[:3]}", level="info")
|
||||
if delta_e_values:
|
||||
self.app.log_gui.log(f" 前3个ΔE: {delta_e_values[:3]}")
|
||||
self.app.log_gui.log(f" 前3个ΔE: {delta_e_values[:3]}", level="info")
|
||||
|
||||
# 查找对应色块的索引
|
||||
try:
|
||||
index = color_patches.index(color_name)
|
||||
delta_e = delta_e_values[index]
|
||||
self.app.log_gui.log(
|
||||
f" ✓ 找到 {color_name}: index={index}, ΔE={delta_e:.2f}"
|
||||
)
|
||||
f" 找到 {color_name}: index={index}, ΔE={delta_e:.2f}"
|
||||
, level="success")
|
||||
return delta_e
|
||||
except ValueError:
|
||||
self.app.log_gui.log(f" ✗ 未找到色块 '{color_name}'")
|
||||
self.app.log_gui.log(f" 可用色块: {color_patches}")
|
||||
self.app.log_gui.log(f"[Error] 未找到色块 '{color_name}'", level="error")
|
||||
self.app.log_gui.log(f" 可用色块: {color_patches}", level="info")
|
||||
return 0.0
|
||||
except IndexError:
|
||||
self.app.log_gui.log(f" ✗ 索引超出范围: {index}/{len(delta_e_values)}")
|
||||
self.app.log_gui.log(f"[Error] 索引超出范围: {index}/{len(delta_e_values)}", level="error")
|
||||
return 0.0
|
||||
|
||||
except Exception as e:
|
||||
self.app.log_gui.log(f"⚠️ 读取 ΔE 失败: {str(e)}")
|
||||
self.app.log_gui.log(f"读取 ΔE 失败: {str(e)}", level="error")
|
||||
import traceback
|
||||
|
||||
self.app.log_gui.log(traceback.format_exc())
|
||||
self.app.log_gui.log(traceback.format_exc(), level="error")
|
||||
return 0.0
|
||||
|
||||
def _calculate_delta_e_for_color(
|
||||
@@ -1215,5 +1215,5 @@ class PQDebugPanel:
|
||||
return delta_e
|
||||
|
||||
except Exception as e:
|
||||
self.app.log_gui.log(f"⚠️ 计算 ΔE 失败: {str(e)}")
|
||||
self.app.log_gui.log(f"计算 ΔE 失败: {str(e)}", level="error")
|
||||
return 0.0
|
||||
|
||||
@@ -1,31 +1,160 @@
|
||||
import threading
|
||||
from datetime import datetime
|
||||
import tkinter as tk
|
||||
import ttkbootstrap as ttk
|
||||
|
||||
class PQLogGUI(ttk.Frame):
|
||||
VALID_LEVELS = {"info", "success", "warning", "error", "debug", "separator", "blank"}
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._line_count = 0
|
||||
self._max_lines = 1500
|
||||
self.create_widgets()
|
||||
|
||||
def create_widgets(self):
|
||||
log_frame = ttk.LabelFrame(self, text="测试日志")
|
||||
log_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
self.log_text = ttk.Text(log_frame, height=8, width=50)
|
||||
toolbar = ttk.Frame(log_frame)
|
||||
toolbar.pack(fill=tk.X, padx=6, pady=(6, 2))
|
||||
|
||||
self.log_summary_var = tk.StringVar(value="0 条日志")
|
||||
ttk.Label(
|
||||
toolbar,
|
||||
textvariable=self.log_summary_var,
|
||||
bootstyle="secondary",
|
||||
).pack(side=tk.LEFT)
|
||||
|
||||
ttk.Button(
|
||||
toolbar,
|
||||
text="清空日志",
|
||||
command=self.clear_log,
|
||||
bootstyle="secondary-outline",
|
||||
width=10,
|
||||
).pack(side=tk.RIGHT)
|
||||
|
||||
text_container = ttk.Frame(log_frame)
|
||||
text_container.pack(fill=tk.BOTH, expand=True, padx=6, pady=(0, 6))
|
||||
|
||||
self.log_text = tk.Text(
|
||||
text_container,
|
||||
height=10,
|
||||
width=50,
|
||||
wrap=tk.WORD,
|
||||
font=("Consolas", 10),
|
||||
bg="#fbfcfe",
|
||||
fg="#1f2937",
|
||||
relief=tk.FLAT,
|
||||
bd=0,
|
||||
padx=10,
|
||||
pady=8,
|
||||
spacing1=2,
|
||||
spacing3=2,
|
||||
insertbackground="#1f2937",
|
||||
)
|
||||
self.log_text.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
|
||||
|
||||
log_scrollbar = ttk.Scrollbar(log_frame, command=self.log_text.yview)
|
||||
|
||||
log_scrollbar = ttk.Scrollbar(text_container, command=self.log_text.yview)
|
||||
log_scrollbar.pack(fill=tk.Y, side=tk.RIGHT)
|
||||
self.log_text.config(yscrollcommand=log_scrollbar.set)
|
||||
|
||||
|
||||
self._configure_tags()
|
||||
self.log_text.config(state=tk.DISABLED)
|
||||
|
||||
def log(self, message):
|
||||
def log(self, message, level="info"):
|
||||
if threading.current_thread() is not threading.main_thread():
|
||||
self.after(0, self.log, message, level)
|
||||
return
|
||||
|
||||
text = "" if message is None else str(message)
|
||||
normalized_level = self._normalize_level(level, text)
|
||||
self.log_text.config(state=tk.NORMAL)
|
||||
self.log_text.insert(tk.END, message + "\n")
|
||||
self._append_message(text, normalized_level)
|
||||
self.log_text.see(tk.END)
|
||||
self.log_text.config(state=tk.DISABLED)
|
||||
|
||||
def clear_log(self):
|
||||
if threading.current_thread() is not threading.main_thread():
|
||||
self.after(0, self.clear_log)
|
||||
return
|
||||
|
||||
self.log_text.config(state=tk.NORMAL)
|
||||
self.log_text.delete(1.0, tk.END)
|
||||
self.log_text.config(state=tk.DISABLED)
|
||||
self.log_text.config(state=tk.DISABLED)
|
||||
self._line_count = 0
|
||||
self._update_summary()
|
||||
|
||||
def _configure_tags(self):
|
||||
self.log_text.tag_configure("timestamp", foreground="#6b7280")
|
||||
self.log_text.tag_configure("level_info", foreground="#2563eb")
|
||||
self.log_text.tag_configure("level_success", foreground="#0f766e")
|
||||
self.log_text.tag_configure("level_warning", foreground="#b45309")
|
||||
self.log_text.tag_configure("level_error", foreground="#b91c1c")
|
||||
self.log_text.tag_configure("level_debug", foreground="#7c3aed")
|
||||
self.log_text.tag_configure("message", foreground="#1f2937")
|
||||
self.log_text.tag_configure("message_success", foreground="#0f766e")
|
||||
self.log_text.tag_configure("message_warning", foreground="#b45309")
|
||||
self.log_text.tag_configure("message_error", foreground="#991b1b")
|
||||
self.log_text.tag_configure("message_debug", foreground="#6d28d9")
|
||||
self.log_text.tag_configure("separator", foreground="#94a3b8")
|
||||
self.log_text.tag_configure("traceback", foreground="#7f1d1d")
|
||||
self.log_text.tag_configure("blank", spacing1=4, spacing3=4)
|
||||
|
||||
def _append_message(self, message, level):
|
||||
lines = message.splitlines() or [""]
|
||||
for line in lines:
|
||||
self._append_line(line, level)
|
||||
self._trim_excess_lines()
|
||||
self._update_summary()
|
||||
|
||||
def _append_line(self, line, level):
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
rendered = "" if line is None else str(line).strip()
|
||||
|
||||
if level == "blank" or not rendered:
|
||||
self.log_text.insert(tk.END, "\n", ("blank",))
|
||||
self._line_count += 1
|
||||
return
|
||||
|
||||
if level == "separator":
|
||||
self.log_text.insert(tk.END, f"[{timestamp}] ", ("timestamp",))
|
||||
self.log_text.insert(tk.END, "[SECTION] ", ("level_info",))
|
||||
self.log_text.insert(tk.END, rendered + "\n", ("separator",))
|
||||
self._line_count += 1
|
||||
return
|
||||
|
||||
level_tag = f"level_{level}"
|
||||
level_label = level.upper().ljust(7)
|
||||
if level == "error" and rendered.startswith("Traceback"):
|
||||
message_tag = "traceback"
|
||||
elif level in {"success", "warning", "error", "debug"}:
|
||||
message_tag = f"message_{level}"
|
||||
else:
|
||||
message_tag = "message"
|
||||
|
||||
self.log_text.insert(tk.END, f"[{timestamp}] ", ("timestamp",))
|
||||
self.log_text.insert(tk.END, f"[{level_label}] ", (level_tag,))
|
||||
self.log_text.insert(tk.END, rendered + "\n", (message_tag,))
|
||||
self._line_count += 1
|
||||
|
||||
def _normalize_level(self, level, message):
|
||||
normalized = "info" if level is None else str(level).strip().lower()
|
||||
if normalized not in self.VALID_LEVELS:
|
||||
normalized = "info"
|
||||
|
||||
if normalized == "info" and (message is None or str(message).strip() == ""):
|
||||
return "blank"
|
||||
|
||||
return normalized
|
||||
|
||||
def _trim_excess_lines(self):
|
||||
overflow = self._line_count - self._max_lines
|
||||
if overflow <= 0:
|
||||
return
|
||||
|
||||
self.log_text.delete("1.0", f"{overflow + 1}.0")
|
||||
self._line_count = self._max_lines
|
||||
|
||||
def _update_summary(self):
|
||||
self.log_summary_var.set(f"{self._line_count} 条日志")
|
||||
Reference in New Issue
Block a user