""" 图标管理工具 负责统一管理应用程序中的所有图标: - 图标路径解析 - 图标缓存 - 图标预加载 - 图标错误处理 """ import os import sys from typing import Dict, Optional from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtCore import QSize class IconManager: """图标管理器类""" def __init__(self): """初始化图标管理器""" self.icon_cache: Dict[str, QIcon] = {} self.icon_directory = self._get_icon_directory() self.default_icon = None # 预定义的图标映射 self.icon_map = { # 主窗口图标 'app_logo': 'logo.png', # 工具栏图标 'select_tool': 'select_tool.png', 'move_tool': 'move_tool.png', 'rotate_tool': 'rotate_tool.png', 'scale_tool': 'scale_tool.png', # 菜单图标(如果有的话) 'new_file': 'new_file.png', 'open_file': 'open_file.png', 'save_file': 'save_file.png', 'exit': 'exit.png', # 对象类型图标 'object_3d': 'object_3d.png', 'light': 'light.png', 'camera': 'camera.png', 'terrain': 'terrain.png', 'script': 'script.png', # 状态图标 'success': 'success.png', 'warning': 'warning.png', 'error': 'error.png', 'info': 'info.png', } # 初始化默认图标 self._create_default_icon() # 预加载常用图标 self._preload_icons() def _get_icon_directory(self) -> str: """获取图标目录的绝对路径""" # 获取当前文件的目录(ui目录) current_dir = os.path.dirname(os.path.abspath(__file__)) # 获取项目根目录(ui的父目录) project_root = os.path.dirname(current_dir) # 拼接icons目录路径 icon_dir = os.path.join(project_root, "icons") print(f"🔍 图标目录路径: {icon_dir}") # 检查目录是否存在 if not os.path.exists(icon_dir): print(f"⚠️ 图标目录不存在: {icon_dir}") # 尝试创建目录 try: os.makedirs(icon_dir, exist_ok=True) print(f"✅ 已创建图标目录: {icon_dir}") except Exception as e: print(f"❌ 创建图标目录失败: {e}") return icon_dir def _create_default_icon(self): """创建默认图标""" # 创建一个简单的默认图标 pixmap = QPixmap(16, 16) pixmap.fill() # 填充为白色 self.default_icon = QIcon(pixmap) def _preload_icons(self): """预加载常用图标""" print("🔄 开始预加载图标...") for icon_name, file_name in self.icon_map.items(): icon_path = os.path.join(self.icon_directory, file_name) if os.path.exists(icon_path): try: icon = QIcon(icon_path) self.icon_cache[icon_name] = icon print(f"✅ 已加载图标: {icon_name} -> {file_name}") except Exception as e: print(f"❌ 加载图标失败: {icon_name} -> {file_name}, 错误: {e}") else: print(f"⚠️ 图标文件不存在: {icon_path}") print(f"📊 预加载完成,共加载 {len(self.icon_cache)} 个图标") def get_icon(self, icon_name: str, size: Optional[QSize] = None) -> QIcon: """ 获取图标 Args: icon_name: 图标名称(可以是预定义名称或文件名) size: 图标尺寸 Returns: QIcon对象 """ # 首先检查缓存 if icon_name in self.icon_cache: icon = self.icon_cache[icon_name] if size: # 如果指定了尺寸,返回指定尺寸的图标 pixmap = icon.pixmap(size) return QIcon(pixmap) return icon # 如果不在缓存中,尝试从映射中获取 if icon_name in self.icon_map: file_name = self.icon_map[icon_name] icon_path = os.path.join(self.icon_directory, file_name) else: # 直接使用文件名 icon_path = os.path.join(self.icon_directory, icon_name) if not icon_name.endswith(('.png', '.jpg', '.jpeg', '.svg', '.ico')): icon_path += '.png' # 默认添加.png扩展名 # 尝试加载图标 if os.path.exists(icon_path): try: icon = QIcon(icon_path) # 缓存图标 self.icon_cache[icon_name] = icon print(f"✅ 动态加载图标: {icon_name} -> {os.path.basename(icon_path)}") if size: pixmap = icon.pixmap(size) return QIcon(pixmap) return icon except Exception as e: print(f"❌ 加载图标失败: {icon_path}, 错误: {e}") else: print(f"⚠️ 图标文件不存在: {icon_path}") # 返回默认图标 return self.default_icon def get_icon_path(self, icon_name: str) -> str: """ 获取图标文件的完整路径 Args: icon_name: 图标名称 Returns: 图标文件的完整路径 """ if icon_name in self.icon_map: file_name = self.icon_map[icon_name] else: file_name = icon_name if not file_name.endswith(('.png', '.jpg', '.jpeg', '.svg', '.ico')): file_name += '.png' icon_path = os.path.join(self.icon_directory, file_name) if os.path.exists(icon_path): return icon_path else: print(f"⚠️ 图标文件不存在: {icon_path}") return "" def has_icon(self, icon_name: str) -> bool: """ 检查图标是否存在 Args: icon_name: 图标名称 Returns: 是否存在 """ return bool(self.get_icon_path(icon_name)) def add_icon(self, icon_name: str, icon_path: str) -> bool: """ 添加新图标到缓存 Args: icon_name: 图标名称 icon_path: 图标文件路径 Returns: 是否添加成功 """ try: if os.path.exists(icon_path): icon = QIcon(icon_path) self.icon_cache[icon_name] = icon print(f"✅ 已添加图标到缓存: {icon_name} -> {icon_path}") return True else: print(f"❌ 图标文件不存在: {icon_path}") return False except Exception as e: print(f"❌ 添加图标失败: {icon_name} -> {icon_path}, 错误: {e}") return False def refresh_cache(self): """刷新图标缓存""" print("🔄 刷新图标缓存...") self.icon_cache.clear() self._preload_icons() def get_available_icons(self) -> list: """获取所有可用的图标列表""" available_icons = [] # 添加预定义的图标 available_icons.extend(self.icon_map.keys()) # 扫描图标目录中的所有图标文件 if os.path.exists(self.icon_directory): for file_name in os.listdir(self.icon_directory): if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.svg', '.ico')): icon_name = os.path.splitext(file_name)[0] if icon_name not in available_icons: available_icons.append(icon_name) return sorted(available_icons) def get_cache_info(self) -> dict: """获取缓存信息""" return { 'cached_icons': len(self.icon_cache), 'icon_directory': self.icon_directory, 'available_icons': len(self.get_available_icons()), 'cache_keys': list(self.icon_cache.keys()) } def debug_info(self): """打印调试信息""" print("=" * 50) print("📋 图标管理器调试信息") print("=" * 50) info = self.get_cache_info() print(f"图标目录: {info['icon_directory']}") print(f"目录存在: {os.path.exists(info['icon_directory'])}") print(f"缓存图标数: {info['cached_icons']}") print(f"可用图标数: {info['available_icons']}") if info['cache_keys']: print("\n已缓存的图标:") for key in info['cache_keys']: print(f" - {key}") print("\n图标目录内容:") if os.path.exists(self.icon_directory): for file_name in os.listdir(self.icon_directory): file_path = os.path.join(self.icon_directory, file_name) size = os.path.getsize(file_path) if os.path.isfile(file_path) else 0 print(f" - {file_name} ({size} bytes)") else: print(" 目录不存在") print("=" * 50) # 全局图标管理器实例 _icon_manager = None def get_icon_manager() -> IconManager: """获取全局图标管理器实例""" global _icon_manager if _icon_manager is None: _icon_manager = IconManager() return _icon_manager def get_icon(icon_name: str, size: Optional[QSize] = None) -> QIcon: """便捷函数:获取图标""" return get_icon_manager().get_icon(icon_name, size) def get_icon_path(icon_name: str) -> str: """便捷函数:获取图标路径""" return get_icon_manager().get_icon_path(icon_name) def has_icon(icon_name: str) -> bool: """便捷函数:检查图标是否存在""" return get_icon_manager().has_icon(icon_name) if __name__ == "__main__": # 测试代码 print("🧪 测试图标管理器...") manager = IconManager() manager.debug_info() # 测试获取图标 logo_icon = manager.get_icon('app_logo') print(f"\n📱 应用图标是否有效: {not logo_icon.isNull()}") move_tool_icon = manager.get_icon('move_tool') print(f"🔧 移动工具图标是否有效: {not move_tool_icon.isNull()}")