#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 主题管理器 - 负责检测系统主题并管理应用主题切换 """ from PyQt5.QtWidgets import QApplication from PyQt5.QtGui import QPalette, QColor from PyQt5.QtCore import QObject, pyqtSignal import platform import subprocess import os class ThemeManager(QObject): """主题管理器类""" # 主题切换信号 theme_changed = pyqtSignal(bool) # True表示深色模式,False表示浅色模式 def __init__(self): super().__init__() self._is_dark_theme = False self._auto_detect = True self._detection_timer = None def is_dark_theme(self): """检测是否为深色主题""" if self._auto_detect: return self._detect_system_theme() return self._is_dark_theme def _detect_system_theme(self): """检测系统主题""" try: # macOS系统主题检测 if platform.system() == 'Darwin': return self._detect_macos_theme() # Windows系统主题检测 elif platform.system() == 'Windows': return self._detect_windows_theme() # Linux系统主题检测 else: return self._detect_linux_theme() except Exception as e: print(f"主题检测失败: {e}") return False def _detect_macos_theme(self): """检测macOS系统主题""" try: # 使用osascript命令检测macOS主题 result = subprocess.run([ 'osascript', '-e', 'tell application "System Events" to tell appearance preferences to return dark mode' ], capture_output=True, text=True, timeout=5) if result.returncode == 0: return 'true' in result.stdout.lower() # 备用方法:检测系统设置 result = subprocess.run([ 'defaults', 'read', '-g', 'AppleInterfaceStyle' ], capture_output=True, text=True, timeout=5) if result.returncode == 0: return 'dark' in result.stdout.lower() except (subprocess.TimeoutExpired, subprocess.SubprocessError, FileNotFoundError): pass # 使用Qt的调色板检测作为备用方法 return self._detect_by_palette() def _detect_windows_theme(self): """检测Windows系统主题""" try: # Windows 10/11 注册表检测 import winreg key_path = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize' value_name = 'AppsUseLightTheme' try: with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path) as key: value, _ = winreg.QueryValueEx(key, value_name) return value == 0 # 0表示深色模式 except (OSError, FileNotFoundError): pass except ImportError: pass # 使用Qt的调色板检测作为备用方法 return self._detect_by_palette() def _detect_linux_theme(self): """检测Linux系统主题""" try: # 检测GTK主题 result = subprocess.run([ 'gsettings', 'get', 'org.gnome.desktop.interface', 'gtk-theme' ], capture_output=True, text=True, timeout=5) if result.returncode == 0: theme_name = result.stdout.strip().strip("'") return any(dark_name in theme_name.lower() for dark_name in ['dark', 'night']) # 检测颜色方案 result = subprocess.run([ 'gsettings', 'get', 'org.gnome.desktop.interface', 'color-scheme' ], capture_output=True, text=True, timeout=5) if result.returncode == 0: return 'dark' in result.stdout.lower() except (subprocess.TimeoutExpired, subprocess.SubprocessError, FileNotFoundError): pass # 使用Qt的调色板检测作为备用方法 return self._detect_by_palette() def _detect_by_palette(self): """使用Qt调色板检测主题""" app = QApplication.instance() if app is None: return False palette = app.palette() # 检测背景色和文本色的亮度 window_color = palette.color(QPalette.Window) text_color = palette.color(QPalette.WindowText) # 计算亮度 def get_luminance(color): return (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255 window_luminance = get_luminance(window_color) text_luminance = get_luminance(text_color) # 如果背景比文本暗,则为深色主题 return window_luminance < text_luminance def get_theme_stylesheet(self, is_dark=None): """获取主题样式表""" if is_dark is None: is_dark = self.is_dark_theme() if is_dark: return self._get_dark_stylesheet() else: return self._get_light_stylesheet() def _get_dark_stylesheet(self): """深色主题样式表 - Apple设计风格""" return """ /* Apple设计风格深色主题样式 */ /* 全局文字颜色和字体 - 使用Apple系统字体 */ QWidget { color: #f0f0f0; font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Helvetica', 'Arial', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', sans-serif; font-size: 13px; } /* 主窗口 - Apple深色背景 */ QMainWindow { background-color: #2c2c2e; } /* 菜单栏 - Apple深色风格 */ QMenuBar { background-color: #2c2c2e; border: none; border-bottom: 1px solid #404040; font-size: 13px; color: #f0f0f0; padding: 4px 0; } QMenuBar::item { background-color: transparent; padding: 6px 12px; color: #f0f0f0; border-radius: 4px; margin: 0 1px; } QMenuBar::item:selected { background-color: #404040; color: #f0f0f0; } QMenuBar::item:pressed { background-color: #505050; color: #f0f0f0; } /* 菜单 - Apple深色风格 */ QMenu { background-color: #2c2c2e; border: 1px solid #404040; border-radius: 8px; font-size: 13px; color: #f0f0f0; padding: 4px 0; margin: 2px; } QMenu::item { color: #f0f0f0; background-color: transparent; border-radius: 4px; margin: 0 4px; padding: 4px 20px; } QMenu::item:selected { background-color: #0a84ff; color: #ffffff; } QMenu::item:pressed { background-color: #0066cc; color: #ffffff; } QMenu::separator { height: 1px; background-color: #404040; margin: 4px 8px; } /* 功能区 */ QFrame { background-color: #2c2c2e; border: none; } /* 组框 */ QGroupBox { font-size: 12px; font-weight: normal; color: #f0f0f0; background-color: #2c2c2e; border: none; border-radius: 8px; margin-top: 5px; padding-top: 5px; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px 0 5px; color: #a0a0a0; } /* 工具按钮 - Apple深色风格 */ QToolButton { border: 1px solid transparent; border-radius: 6px; background-color: #3a3a3c; font-size: 13px; color: #f0f0f0; padding: 6px 12px; } QToolButton:hover { background-color: #4a4a4c; border: 1px solid #5a5a5c; } QToolButton:pressed { background-color: #5a5a5c; border: 1px solid #6a6a6c; } QToolButton:checked { background-color: #0a84ff; border: 1px solid #0a84ff; color: #ffffff; } /* 切换按钮 */ QToolButton[checkable="true"] { border: 1px solid #4a4a4c; border-radius: 6px; background-color: #3a3a3c; font-size: 12px; color: #f0f0f0; padding: 6px 12px; } QToolButton[checkable="true"]:hover { background-color: #4a4a4c; } QToolButton[checkable="true"]:checked { background-color: #0a84ff; border: 1px solid #0a84ff; color: #ffffff; } /* 下拉框 - Apple深色风格 */ QComboBox { background-color: #3a3a3c; border: 1px solid #4a4a4c; border-radius: 6px; color: #f0f0f0; padding: 4px 8px; selection-background-color: #0a84ff; selection-color: #ffffff; } QComboBox:hover { background-color: #4a4a4c; border: 1px solid #5a5a5c; } QComboBox::drop-down { border: none; width: 20px; border-left: 1px solid #4a4a4c; border-top-right-radius: 6px; border-bottom-right-radius: 6px; } QComboBox::down-arrow { image: none; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 6px solid #a0a0a0; margin: 6px; } QComboBox QAbstractItemView { background-color: #2c2c2e; border: 1px solid #4a4a4c; color: #f0f0f0; selection-background-color: #0a84ff; selection-color: #ffffff; } /* 文本编辑区域 - Apple深色风格 */ QTextEdit { background-color: #1c1c1e; border: none; font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Helvetica', 'Arial', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', sans-serif; font-size: 15px; color: #f0f0f0; padding: 32px; line-height: 1.5; selection-background-color: #0066cc; selection-color: #ffffff; } /* 状态栏 - Apple深色风格 */ QStatusBar { background-color: #3a3a3c; border-top: 1px solid #4a4a4c; font-size: 12px; color: #a0a0a0; font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Helvetica', 'Arial', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', sans-serif; padding: 6px 12px; } /* 标签 */ QLabel { color: #f0f0f0; background-color: transparent; } /* 消息框 - Apple深色风格 */ QMessageBox { background-color: #2c2c2e; color: #f0f0f0; border-radius: 12px; } QMessageBox QPushButton { background-color: #3a3a3c; color: #f0f0f0; border: 1px solid #4a4a4c; border-radius: 6px; padding: 6px 16px; min-width: 80px; } QMessageBox QPushButton:hover { background-color: #4a4a4c; border: 1px solid #5a5a5c; } QMessageBox QPushButton:pressed { background-color: #5a5a5c; border: 1px solid #6a6a6c; } QMessageBox QPushButton:default { background-color: #0a84ff; color: #ffffff; border: 1px solid #0a84ff; } QMessageBox QPushButton:default:hover { background-color: #0066cc; border: 1px solid #0066cc; } QMessageBox QPushButton:default:pressed { background-color: #004d99; border: 1px solid #004d99; } /* 滚动条 - Apple深色风格 */ QScrollBar:vertical { background-color: transparent; width: 8px; border: none; } QScrollBar::handle:vertical { background-color: #5a5a5c; border-radius: 4px; min-height: 20px; } QScrollBar::handle:vertical:hover { background-color: #6a6a6c; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { border: none; background: none; } /* 按钮 - Apple深色风格 */ QPushButton { background-color: #3a3a3c; color: #f0f0f0; border: 1px solid #4a4a4c; border-radius: 6px; padding: 6px 16px; font-size: 13px; } QPushButton:hover { background-color: #4a4a4c; border: 1px solid #5a5a5c; } QPushButton:pressed { background-color: #5a5a5c; border: 1px solid #6a6a6c; } QPushButton:default { background-color: #0a84ff; color: #ffffff; border: 1px solid #0a84ff; } QPushButton:default:hover { background-color: #0066cc; border: 1px solid #0066cc; } QPushButton:default:pressed { background-color: #004d99; border: 1px solid #004d99; } """ def _get_light_stylesheet(self): """浅色主题样式表 - Apple设计风格""" return """ /* Apple设计风格浅色主题样式 */ /* 全局文字颜色和字体 - 使用Apple系统字体 */ QWidget { color: #333333; font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Helvetica', 'Arial', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', sans-serif; font-size: 13px; } /* 主窗口 - 纯净白色背景 */ QMainWindow { background-color: #ffffff; } /* 菜单栏 - Apple风格 */ QMenuBar { background-color: #ffffff; border: none; border-bottom: 1px solid #e0e0e0; font-size: 13px; color: #333333; padding: 4px 0; } QMenuBar::item { background-color: transparent; padding: 6px 12px; color: #333333; border-radius: 4px; margin: 0 1px; } QMenuBar::item:selected { background-color: #f0f0f0; color: #333333; } QMenuBar::item:pressed { background-color: #e0e0e0; color: #333333; } /* 菜单 - Apple风格 */ QMenu { background-color: #ffffff; border: 1px solid #d0d0d0; border-radius: 8px; font-size: 13px; color: #333333; padding: 4px 0; margin: 2px; } QMenu::item { color: #333333; background-color: transparent; border-radius: 4px; margin: 0 4px; padding: 4px 20px; } QMenu::item:selected { background-color: #007aff; color: #ffffff; } QMenu::item:pressed { background-color: #0062cc; color: #ffffff; } QMenu::separator { height: 1px; background-color: #e0e0e0; margin: 4px 8px; } /* 功能区 */ QFrame { background-color: #ffffff; border: none; } /* 组框 */ QGroupBox { font-size: 12px; font-weight: normal; color: #333333; background-color: #ffffff; border: none; border-radius: 8px; margin-top: 5px; padding-top: 5px; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px 0 5px; color: #666666; } /* 工具按钮 - Apple风格 */ QToolButton { border: 1px solid transparent; border-radius: 6px; background-color: #f6f6f6; font-size: 13px; color: #333333; padding: 6px 12px; } QToolButton:hover { background-color: #e0e0e0; border: 1px solid #d0d0d0; } QToolButton:pressed { background-color: #d0d0d0; border: 1px solid #c0c0c0; } QToolButton:checked { background-color: #007aff; border: 1px solid #007aff; color: #ffffff; } /* 切换按钮 */ QToolButton[checkable="true"] { border: 1px solid #d0d0d0; border-radius: 6px; background-color: #f6f6f6; font-size: 12px; color: #333333; padding: 6px 12px; } QToolButton[checkable="true"]:hover { background-color: #e0e0e0; } QToolButton[checkable="true"]:checked { background-color: #007aff; border: 1px solid #007aff; color: #ffffff; } /* 下拉框 - Apple风格 */ QComboBox { background-color: #f6f6f6; border: 1px solid #d0d0d0; border-radius: 6px; color: #333333; padding: 4px 8px; selection-background-color: #007aff; selection-color: #ffffff; } QComboBox:hover { background-color: #e0e0e0; border: 1px solid #c0c0c0; } QComboBox::drop-down { border: none; width: 20px; border-left: 1px solid #d0d0d0; border-top-right-radius: 6px; border-bottom-right-radius: 6px; } QComboBox::down-arrow { image: none; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 6px solid #666666; margin: 6px; } QComboBox QAbstractItemView { border: 1px solid #d0d0d0; color: #333333; background-color: #ffffff; selection-background-color: #007aff; selection-color: #ffffff; } /* 文本编辑区域 - Apple风格 */ QTextEdit { background-color: #ffffff; border: none; font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Helvetica', 'Arial', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', sans-serif; font-size: 15px; color: #333333; padding: 32px; line-height: 1.5; selection-background-color: #b3d9ff; selection-color: #333333; } /* 状态栏 - Apple风格 */ QStatusBar { background-color: #f6f6f6; border-top: 1px solid #e0e0e0; font-size: 12px; color: #666666; font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Helvetica', 'Arial', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', sans-serif; padding: 6px 12px; } /* 标签 */ QLabel { color: #333333; background-color: transparent; } /* 消息框 - Apple风格 */ QMessageBox { background-color: #ffffff; color: #333333; border-radius: 12px; } QMessageBox QPushButton { background-color: #f6f6f6; color: #333333; border: 1px solid #d0d0d0; border-radius: 6px; padding: 6px 16px; min-width: 80px; } QMessageBox QPushButton:hover { background-color: #e0e0e0; border: 1px solid #c0c0c0; } QMessageBox QPushButton:pressed { background-color: #d0d0d0; border: 1px solid #a0a0a0; } QMessageBox QPushButton:default { background-color: #007aff; color: #ffffff; border: 1px solid #007aff; } QMessageBox QPushButton:default:hover { background-color: #0062cc; border: 1px solid #0062cc; } QMessageBox QPushButton:default:pressed { background-color: #004a99; border: 1px solid #004a99; } /* 滚动条 - Apple风格 */ QScrollBar:vertical { background-color: transparent; width: 8px; border: none; } QScrollBar::handle:vertical { background-color: #c0c0c0; border-radius: 4px; min-height: 20px; } QScrollBar::handle:vertical:hover { background-color: #a0a0a0; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { border: none; background: none; } /* 按钮 - Apple风格 */ QPushButton { background-color: #f6f6f6; color: #333333; border: 1px solid #d0d0d0; border-radius: 6px; padding: 6px 16px; font-size: 13px; } QPushButton:hover { background-color: #e0e0e0; border: 1px solid #c0c0c0; } QPushButton:pressed { background-color: #d0d0d0; border: 1px solid #a0a0a0; } QPushButton:default { background-color: #007aff; color: #ffffff; border: 1px solid #007aff; } QPushButton:default:hover { background-color: #0062cc; border: 1px solid #0062cc; } QPushButton:default:pressed { background-color: #004a99; border: 1px solid #004a99; } """ def set_dark_theme(self, is_dark): """设置深色主题""" self._is_dark_theme = is_dark self._auto_detect = False self.theme_changed.emit(is_dark) def enable_auto_detection(self, enabled=True): """启用/禁用自动主题检测""" self._auto_detect = enabled if enabled: self.theme_changed.emit(self.is_dark_theme()) def get_current_theme_colors(self): """获取当前主题颜色配置""" is_dark = self.is_dark_theme() if is_dark: return { 'background': '#1e1e1e', 'surface': '#2d2d2d', 'surface_hover': '#3c3c3c', 'text': '#e0e0e0', 'text_secondary': '#b0b0b0', 'border': '#3c3c3c', 'accent': '#0078d4', 'accent_hover': '#106ebe' } else: return { 'background': '#f3f2f1', 'surface': '#ffffff', 'surface_hover': '#f0f0f0', 'text': '#333333', 'text_secondary': '#666666', 'border': '#d0d0d0', 'accent': '#0078d7', 'accent_hover': '#005a9e' } # 全局主题管理器实例 theme_manager = ThemeManager()