Apply Black formatter to the entire codebase for consistent code style. Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
133 lines
4.1 KiB
Python
133 lines
4.1 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
BaseTab - 标签页基类
|
||
|
||
提供所有标签页共享的通用功能,包括:
|
||
- 统一的日志更新方法
|
||
- 线程安全的 GUI 操作
|
||
- 通用工具方法
|
||
"""
|
||
|
||
import logging
|
||
import tkinter as tk
|
||
from tkinter import ttk
|
||
|
||
|
||
class BaseTab(ttk.Frame):
|
||
"""标签页基类
|
||
|
||
提供所有标签页共享的通用功能。
|
||
子类应继承此类并实现 create_widgets 方法。
|
||
"""
|
||
|
||
def __init__(self, parent, config=None, main_window=None):
|
||
"""初始化基类
|
||
|
||
Args:
|
||
parent: 父容器
|
||
config: 配置管理器(可选)
|
||
main_window: 主窗口引用(可选)
|
||
"""
|
||
super().__init__(parent)
|
||
self.config = config
|
||
self.main_window = main_window
|
||
|
||
def _update_log(self, message: str, level: str = "INFO"):
|
||
"""
|
||
线程安全的日志更新方法
|
||
|
||
通过统一的 logging 系统输出日志,自动同时输出到控制台和 GUI。
|
||
|
||
Args:
|
||
message: 日志消息
|
||
level: 日志级别 (INFO, SUCCESS, WARNING, ERROR, DEBUG)
|
||
|
||
Note:
|
||
子类需要设置 self.logger 和 self._gui_handler 才能使用此方法。
|
||
如果 self.logger 未设置,将使用 logging.getLogger(__name__) 作为后备。
|
||
"""
|
||
# 获取 logger(优先使用实例的 logger,否则使用模块 logger)
|
||
logger = getattr(self, "logger", None) or logging.getLogger(__name__)
|
||
|
||
# 将自定义级别映射到 logging 级别
|
||
level_upper = level.upper()
|
||
if level_upper == "SUCCESS":
|
||
# SUCCESS 映射到 INFO,但在 UI 中仍显示为 SUCCESS
|
||
logger.info(message)
|
||
else:
|
||
# 其他级别直接映射
|
||
log_level = getattr(logging, level_upper, logging.INFO)
|
||
logger.log(log_level, message)
|
||
|
||
def _run_on_main_thread(self, callback, *args, **kwargs):
|
||
"""在主线程中执行回调函数(线程安全)
|
||
|
||
Args:
|
||
callback: 要执行的回调函数
|
||
*args: 位置参数
|
||
**kwargs: 关键字参数
|
||
|
||
Note:
|
||
使用 after(0, ...) 确保在主线程中执行。
|
||
"""
|
||
self.after(0, lambda: callback(*args, **kwargs))
|
||
|
||
def _is_admin(self) -> bool:
|
||
"""检查当前用户是否为管理员
|
||
|
||
Returns:
|
||
bool: 如果是管理员返回 True,否则返回 False
|
||
|
||
Note:
|
||
需要 main_window 或 session_manager 支持。
|
||
"""
|
||
# 尝试从 session_manager 获取
|
||
if hasattr(self, "session_manager") and self.session_manager:
|
||
return self.session_manager.is_admin()
|
||
|
||
# 尝试从 main_window 获取
|
||
if self.main_window and hasattr(self.main_window, "session_manager"):
|
||
return self.main_window.session_manager.is_admin()
|
||
|
||
return False
|
||
|
||
def _get_username(self) -> str:
|
||
"""获取当前用户名
|
||
|
||
Returns:
|
||
str: 当前用户名,如果无法获取则返回空字符串
|
||
|
||
Note:
|
||
需要 session_manager 支持。
|
||
"""
|
||
if hasattr(self, "session_manager") and self.session_manager:
|
||
return self.session_manager.get_username() or ""
|
||
|
||
if self.main_window and hasattr(self.main_window, "session_manager"):
|
||
return self.main_window.session_manager.get_username() or ""
|
||
|
||
return ""
|
||
|
||
def set_busy(self, busy: bool):
|
||
"""设置窗口忙碌状态(显示等待光标)
|
||
|
||
Args:
|
||
busy: True 显示等待光标,False 恢复正常光标
|
||
"""
|
||
try:
|
||
cursor = "watch" if busy else "arrow"
|
||
# 获取顶层窗口
|
||
toplevel = self.winfo_toplevel()
|
||
if toplevel:
|
||
toplevel.config(cursor=cursor)
|
||
toplevel.update()
|
||
except tk.TclError:
|
||
# 窗口可能已被销毁
|
||
pass
|
||
|
||
def reload_config(self):
|
||
"""重新加载配置(子类可覆盖此方法)"""
|
||
if self.config and hasattr(self.config, "reload"):
|
||
self.config.reload()
|