342 lines
11 KiB
Python
342 lines
11 KiB
Python
"""
|
||
图标管理工具
|
||
|
||
负责统一管理应用程序中的所有图标:
|
||
- 图标路径解析
|
||
- 图标缓存
|
||
- 图标预加载
|
||
- 图标错误处理
|
||
"""
|
||
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',
|
||
|
||
'up_arrow': 'up_arrows.png',
|
||
'down_arrow': 'down_arrows.png',
|
||
'left_arrow': 'left_arrows.png',
|
||
'right_arrow': 'right_arrows.png',
|
||
|
||
'solid_down_arrows': 'solid_down_arrows.png',
|
||
'solid_right_arrows': 'solid_right_arrows.png',
|
||
|
||
'minimize_icon': 'minimize_icon.png',
|
||
'windowing_icon': 'windowing_icon.png',
|
||
'close_icon': 'close_icon.png',
|
||
|
||
# 弹窗图标
|
||
'success_icon': 'success_icon.png',
|
||
'warning_icon': 'warning_icon.png',
|
||
'fail_icon': 'delete_fail_icon.png',
|
||
|
||
# 属性面板图标
|
||
'property_select_image': 'property_select_image.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()}") |