1.优化
This commit is contained in:
parent
dff3726bbf
commit
9a997c4036
File diff suppressed because one or more lines are too long
@ -21,8 +21,14 @@ sys.path.insert(0, icons_path)
|
||||
if __name__ == "__main__":
|
||||
args = sys.argv[1:]
|
||||
# args = "/home/tiger/桌面/Test1"
|
||||
# args = "C:/Users/29381/Desktop/1"
|
||||
print(f'Path is {args}')
|
||||
# 将整个列表转换为字符串(包括方括号)
|
||||
args_str = ''.join(args)
|
||||
|
||||
from main import run
|
||||
if args:
|
||||
run(args[0])
|
||||
run(args_str)
|
||||
# run(args)
|
||||
else:
|
||||
run()
|
||||
@ -288,7 +288,8 @@ class CoreWorld(Panda3DWorld):
|
||||
self.cam.setPos(0, -50, 20)
|
||||
self.cam.lookAt(0, 0, 0)
|
||||
self.camLens.setFov(80)
|
||||
# self.cam.setTag("is_scene_element", "1")
|
||||
self.cam.setTag("is_scene_element", "1")
|
||||
self.cam.setTag("tree_item_type", "CAMERA_NODE")
|
||||
print("✓ 相机设置完成")
|
||||
|
||||
def _setupLighting(self):
|
||||
@ -323,6 +324,7 @@ class CoreWorld(Panda3DWorld):
|
||||
self.ground.setZ(-0.1)
|
||||
self.ground.setColor(0.8, 0.8, 0.8, 1)
|
||||
# self.ground.setTag("is_scene_element", "1")
|
||||
# self.ground.setTag("tree_item_type", "SCENE_NODE")
|
||||
|
||||
# 创建支持贴图的材质
|
||||
mat = Material()
|
||||
|
||||
@ -723,6 +723,7 @@ class GUIManager:
|
||||
textNodePath.setTag("is_scene_element", "1")
|
||||
textNodePath.setTag("tree_item_type", "GUI_3DTEXT")
|
||||
textNodePath.setTag("created_by_user", "1")
|
||||
textNodePath.setTag("name", text_name)
|
||||
|
||||
# 添加到GUI元素列表
|
||||
self.gui_elements.append(textNodePath)
|
||||
|
||||
BIN
icons/logo.png
Normal file
BIN
icons/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
4
main.py
4
main.py
@ -105,7 +105,7 @@ class MyWorld(CoreWorld):
|
||||
self.collision_manager = CollisionManager(self)
|
||||
|
||||
# 调试选项
|
||||
self.debug_collision = False # 是否显示碰撞体
|
||||
self.debug_collision = True # 是否显示碰撞体
|
||||
|
||||
# 默认启用模型间碰撞检测(可选)
|
||||
self.enableModelCollisionDetection(enable=True, frequency=0.1, threshold=0.5)
|
||||
@ -850,7 +850,7 @@ def run(args = None):
|
||||
|
||||
# 使用新的UI模块创建主窗口
|
||||
from ui.main_window import setup_main_window
|
||||
|
||||
print(f'Path is {args}')
|
||||
app, main_window = setup_main_window(world, args)
|
||||
|
||||
# 启动应用程序
|
||||
|
||||
@ -217,7 +217,7 @@ class ProjectManager:
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
if not os.path.exists(config_file):
|
||||
if parent_window:
|
||||
QMessageBox.warning(parent_window, "警告", "选择的不是有效的项目文件夹!")
|
||||
QMessageBox.warning(parent_window, "警告", f"选择的不是有效的项目文件夹!{project_path}")
|
||||
else:
|
||||
print("警告: 选择的不是有效的项目文件夹!")
|
||||
return False
|
||||
|
||||
@ -674,7 +674,7 @@ class SceneManager:
|
||||
|
||||
# 根据调试设置决定是否显示碰撞体
|
||||
if hasattr(self.world, 'debug_collision') and self.world.debug_collision:
|
||||
cNodePath.hide()
|
||||
cNodePath.show()
|
||||
else:
|
||||
cNodePath.hide()
|
||||
|
||||
@ -1143,22 +1143,26 @@ class SceneManager:
|
||||
tree_widget = self._get_tree_widget()
|
||||
# 清除当前场景
|
||||
print("\n清除当前场景...")
|
||||
for model in self.models:
|
||||
tree_widget.delete_item(model)
|
||||
# for model in self.models:
|
||||
# tree_widget.delete_item(model)
|
||||
# # 清除灯光
|
||||
# for light_node in self.Spotlight:
|
||||
# tree_widget.delete_item(light_node)
|
||||
#
|
||||
# for light_node in self.Pointlight:
|
||||
# tree_widget.delete_item(light_node)
|
||||
#
|
||||
# for terrain in self.world.terrain_manager.terrains:
|
||||
# tree_widget.delete_item(terrain)
|
||||
#
|
||||
# for gui in self.world.gui_elements:
|
||||
# if not gui.isEmpty():
|
||||
# tree_widget.delete_item(gui)
|
||||
|
||||
# 清除灯光
|
||||
for light_node in self.Spotlight:
|
||||
tree_widget.delete_item(light_node)
|
||||
|
||||
for light_node in self.Pointlight:
|
||||
tree_widget.delete_item(light_node)
|
||||
|
||||
for terrain in self.world.terrain_manager.terrains:
|
||||
tree_widget.delete_item(terrain)
|
||||
|
||||
# 清除tilesets
|
||||
for tileset_info in self.tilesets:
|
||||
tree_widget.delete_item(tileset_info['node'])
|
||||
# # 清除tilesets
|
||||
# for tileset_info in self.tilesets:
|
||||
# tree_widget.delete_item(tileset_info['node'])
|
||||
tree_widget.clear_tree()
|
||||
|
||||
for light in self.Spotlight:
|
||||
if not light.isEmpty():
|
||||
@ -1415,7 +1419,7 @@ class SceneManager:
|
||||
print(f" 发现 {len(gui_data)} 个GUI元素需要重建")
|
||||
|
||||
# 使用gui_manager重新创建GUI元素
|
||||
self._recreateGUIElementsFromData(gui_data)
|
||||
# self._recreateGUIElementsFromData(gui_data)
|
||||
else:
|
||||
print("ℹ️ GUI信息文件为空")
|
||||
except json.JSONDecodeError as e:
|
||||
|
||||
322
ui/icon_manager.py
Normal file
322
ui/icon_manager.py
Normal file
@ -0,0 +1,322 @@
|
||||
"""
|
||||
图标管理工具
|
||||
|
||||
负责统一管理应用程序中的所有图标:
|
||||
- 图标路径解析
|
||||
- 图标缓存
|
||||
- 图标预加载
|
||||
- 图标错误处理
|
||||
"""
|
||||
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()}")
|
||||
405
ui/icon_manager_gui.py
Normal file
405
ui/icon_manager_gui.py
Normal file
@ -0,0 +1,405 @@
|
||||
"""
|
||||
图标管理器GUI工具
|
||||
|
||||
提供图形界面来管理和查看图标:
|
||||
- 显示所有可用图标
|
||||
- 图标预览
|
||||
- 图标信息
|
||||
- 图标刷新
|
||||
"""
|
||||
import os
|
||||
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QListWidget, QListWidgetItem, QLabel, QGroupBox,
|
||||
QTextEdit, QSplitter, QDialog, QDialogButtonBox,
|
||||
QFileDialog, QMessageBox, QScrollArea, QGridLayout)
|
||||
from PyQt5.QtGui import QIcon, QPixmap, QFont
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
|
||||
from ui.icon_manager import get_icon_manager
|
||||
|
||||
|
||||
class IconPreviewWidget(QWidget):
|
||||
"""图标预览控件"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setupUI()
|
||||
|
||||
def setupUI(self):
|
||||
"""设置UI"""
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# 图标显示区域
|
||||
self.icon_label = QLabel()
|
||||
self.icon_label.setAlignment(Qt.AlignCenter)
|
||||
self.icon_label.setStyleSheet("""
|
||||
QLabel {
|
||||
border: 2px dashed #8b5cf6;
|
||||
border-radius: 8px;
|
||||
background-color: #2d2d44;
|
||||
color: #e0e0ff;
|
||||
min-height: 100px;
|
||||
margin: 10px;
|
||||
}
|
||||
""")
|
||||
self.icon_label.setText("选择图标查看预览")
|
||||
layout.addWidget(self.icon_label)
|
||||
|
||||
# 图标信息
|
||||
self.info_label = QLabel()
|
||||
self.info_label.setStyleSheet("""
|
||||
QLabel {
|
||||
background-color: #252538;
|
||||
color: #e0e0ff;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
""")
|
||||
self.info_label.setText("图标信息将在此显示")
|
||||
layout.addWidget(self.info_label)
|
||||
|
||||
def showIcon(self, icon_name: str, icon: QIcon):
|
||||
"""显示图标"""
|
||||
if not icon.isNull():
|
||||
# 显示不同尺寸的图标
|
||||
sizes = [16, 24, 32, 48, 64]
|
||||
pixmaps = []
|
||||
|
||||
# 创建组合图标显示
|
||||
for size in sizes:
|
||||
pixmap = icon.pixmap(QSize(size, size))
|
||||
if not pixmap.isNull():
|
||||
pixmaps.append((size, pixmap))
|
||||
|
||||
if pixmaps:
|
||||
# 创建合成图片显示多个尺寸
|
||||
total_width = sum(size for size, _ in pixmaps) + 20 * (len(pixmaps) - 1)
|
||||
max_height = max(size for size, _ in pixmaps)
|
||||
|
||||
combined_pixmap = QPixmap(total_width, max_height + 40)
|
||||
combined_pixmap.fill(Qt.transparent)
|
||||
|
||||
from PyQt5.QtGui import QPainter, QPen
|
||||
painter = QPainter(combined_pixmap)
|
||||
|
||||
x = 0
|
||||
for size, pixmap in pixmaps:
|
||||
# 绘制图标
|
||||
y = (max_height - size) // 2
|
||||
painter.drawPixmap(x, y, pixmap)
|
||||
|
||||
# 绘制尺寸标签
|
||||
painter.setPen(QPen(Qt.white))
|
||||
painter.drawText(x, max_height + 15, f"{size}x{size}")
|
||||
|
||||
x += size + 20
|
||||
|
||||
painter.end()
|
||||
|
||||
self.icon_label.setPixmap(combined_pixmap)
|
||||
else:
|
||||
self.icon_label.setText("无法加载图标")
|
||||
else:
|
||||
self.icon_label.setText("图标无效")
|
||||
|
||||
# 更新信息
|
||||
info_text = f"图标名称: {icon_name}\n"
|
||||
info_text += f"图标有效: {'是' if not icon.isNull() else '否'}\n"
|
||||
|
||||
# 获取图标管理器信息
|
||||
icon_manager = get_icon_manager()
|
||||
icon_path = icon_manager.get_icon_path(icon_name)
|
||||
if icon_path:
|
||||
info_text += f"文件路径: {icon_path}\n"
|
||||
if os.path.exists(icon_path):
|
||||
size = os.path.getsize(icon_path)
|
||||
info_text += f"文件大小: {size} bytes\n"
|
||||
|
||||
# 获取可用尺寸
|
||||
if not icon.isNull():
|
||||
available_sizes = icon.availableSizes()
|
||||
if available_sizes:
|
||||
sizes_text = ", ".join(f"{s.width()}x{s.height()}" for s in available_sizes)
|
||||
info_text += f"可用尺寸: {sizes_text}\n"
|
||||
|
||||
self.info_label.setText(info_text)
|
||||
|
||||
|
||||
class IconManagerDialog(QDialog):
|
||||
"""图标管理器对话框"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.icon_manager = get_icon_manager()
|
||||
self.setupUI()
|
||||
self.loadIcons()
|
||||
|
||||
def setupUI(self):
|
||||
"""设置UI"""
|
||||
self.setWindowTitle("图标管理器")
|
||||
self.setModal(False)
|
||||
self.resize(800, 600)
|
||||
|
||||
# 设置样式
|
||||
self.setStyleSheet("""
|
||||
QDialog {
|
||||
background-color: #1e1e2e;
|
||||
color: #e0e0ff;
|
||||
}
|
||||
QListWidget {
|
||||
background-color: #252538;
|
||||
color: #e0e0ff;
|
||||
border: 1px solid #3a3a4a;
|
||||
border-radius: 4px;
|
||||
alternate-background-color: #2d2d44;
|
||||
}
|
||||
QListWidget::item {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #3a3a4a;
|
||||
}
|
||||
QListWidget::item:hover {
|
||||
background-color: #3a3a4a;
|
||||
}
|
||||
QListWidget::item:selected {
|
||||
background-color: rgba(139, 92, 246, 100);
|
||||
color: white;
|
||||
}
|
||||
QPushButton {
|
||||
background-color: #8b5cf6;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #7c3aed;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #6d28d9;
|
||||
}
|
||||
QGroupBox {
|
||||
background-color: #252538;
|
||||
border: 1px solid #3a3a4a;
|
||||
border-radius: 6px;
|
||||
margin-top: 1ex;
|
||||
color: #e0e0ff;
|
||||
font-weight: 500;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subline-offset: -2px;
|
||||
padding: 0 8px;
|
||||
color: #c0c0e0;
|
||||
font-weight: 500;
|
||||
}
|
||||
QTextEdit {
|
||||
background-color: #252538;
|
||||
color: #e0e0ff;
|
||||
border: 1px solid #3a3a4a;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
""")
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# 顶部按钮栏
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
self.refresh_btn = QPushButton("刷新图标")
|
||||
self.refresh_btn.clicked.connect(self.refreshIcons)
|
||||
button_layout.addWidget(self.refresh_btn)
|
||||
|
||||
self.add_icon_btn = QPushButton("添加图标")
|
||||
self.add_icon_btn.clicked.connect(self.addIcon)
|
||||
button_layout.addWidget(self.add_icon_btn)
|
||||
|
||||
self.debug_btn = QPushButton("调试信息")
|
||||
self.debug_btn.clicked.connect(self.showDebugInfo)
|
||||
button_layout.addWidget(self.debug_btn)
|
||||
|
||||
button_layout.addStretch()
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
# 主分割器
|
||||
splitter = QSplitter(Qt.Horizontal)
|
||||
|
||||
# 左侧:图标列表
|
||||
left_widget = QWidget()
|
||||
left_layout = QVBoxLayout(left_widget)
|
||||
|
||||
list_group = QGroupBox("可用图标")
|
||||
list_layout = QVBoxLayout(list_group)
|
||||
|
||||
self.icon_list = QListWidget()
|
||||
self.icon_list.itemSelectionChanged.connect(self.onIconSelected)
|
||||
list_layout.addWidget(self.icon_list)
|
||||
|
||||
left_layout.addWidget(list_group)
|
||||
splitter.addWidget(left_widget)
|
||||
|
||||
# 右侧:图标预览
|
||||
right_widget = QWidget()
|
||||
right_layout = QVBoxLayout(right_widget)
|
||||
|
||||
preview_group = QGroupBox("图标预览")
|
||||
preview_layout = QVBoxLayout(preview_group)
|
||||
|
||||
self.preview_widget = IconPreviewWidget()
|
||||
preview_layout.addWidget(self.preview_widget)
|
||||
|
||||
right_layout.addWidget(preview_group)
|
||||
splitter.addWidget(right_widget)
|
||||
|
||||
# 设置分割器比例
|
||||
splitter.setSizes([300, 500])
|
||||
layout.addWidget(splitter)
|
||||
|
||||
# 底部按钮
|
||||
button_box = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
button_box.rejected.connect(self.close)
|
||||
layout.addWidget(button_box)
|
||||
|
||||
def loadIcons(self):
|
||||
"""加载图标列表"""
|
||||
self.icon_list.clear()
|
||||
|
||||
available_icons = self.icon_manager.get_available_icons()
|
||||
|
||||
for icon_name in available_icons:
|
||||
item = QListWidgetItem()
|
||||
|
||||
# 获取图标
|
||||
icon = self.icon_manager.get_icon(icon_name, QSize(24, 24))
|
||||
|
||||
# 设置图标和文本
|
||||
if not icon.isNull():
|
||||
item.setIcon(icon)
|
||||
item.setText(f"🎨 {icon_name}")
|
||||
else:
|
||||
item.setText(f"❌ {icon_name}")
|
||||
|
||||
item.setData(Qt.UserRole, icon_name)
|
||||
self.icon_list.addItem(item)
|
||||
|
||||
print(f"📊 加载了 {len(available_icons)} 个图标")
|
||||
|
||||
def onIconSelected(self):
|
||||
"""当选择图标时"""
|
||||
current_item = self.icon_list.currentItem()
|
||||
if current_item:
|
||||
icon_name = current_item.data(Qt.UserRole)
|
||||
icon = self.icon_manager.get_icon(icon_name)
|
||||
self.preview_widget.showIcon(icon_name, icon)
|
||||
|
||||
def refreshIcons(self):
|
||||
"""刷新图标"""
|
||||
print("🔄 刷新图标缓存...")
|
||||
self.icon_manager.refresh_cache()
|
||||
self.loadIcons()
|
||||
QMessageBox.information(self, "完成", "图标缓存已刷新")
|
||||
|
||||
def addIcon(self):
|
||||
"""添加新图标"""
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
"选择图标文件",
|
||||
"",
|
||||
"图像文件 (*.png *.jpg *.jpeg *.svg *.ico);;所有文件 (*)"
|
||||
)
|
||||
|
||||
if file_path:
|
||||
# 获取文件名作为图标名称
|
||||
file_name = os.path.basename(file_path)
|
||||
icon_name = os.path.splitext(file_name)[0]
|
||||
|
||||
# 复制文件到图标目录
|
||||
import shutil
|
||||
target_path = os.path.join(self.icon_manager.icon_directory, file_name)
|
||||
|
||||
try:
|
||||
shutil.copy2(file_path, target_path)
|
||||
|
||||
# 添加到缓存
|
||||
success = self.icon_manager.add_icon(icon_name, target_path)
|
||||
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", f"图标 '{icon_name}' 已添加")
|
||||
self.loadIcons()
|
||||
else:
|
||||
QMessageBox.warning(self, "失败", "添加图标失败")
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"复制文件失败:\n{str(e)}")
|
||||
|
||||
def showDebugInfo(self):
|
||||
"""显示调试信息"""
|
||||
debug_dialog = QDialog(self)
|
||||
debug_dialog.setWindowTitle("图标管理器调试信息")
|
||||
debug_dialog.resize(600, 400)
|
||||
|
||||
layout = QVBoxLayout(debug_dialog)
|
||||
|
||||
text_edit = QTextEdit()
|
||||
text_edit.setFont(QFont("Consolas", 10))
|
||||
|
||||
# 获取调试信息
|
||||
info = self.icon_manager.get_cache_info()
|
||||
debug_text = "图标管理器调试信息\n"
|
||||
debug_text += "=" * 50 + "\n\n"
|
||||
debug_text += f"图标目录: {info['icon_directory']}\n"
|
||||
debug_text += f"目录存在: {os.path.exists(info['icon_directory'])}\n"
|
||||
debug_text += f"缓存图标数: {info['cached_icons']}\n"
|
||||
debug_text += f"可用图标数: {info['available_icons']}\n\n"
|
||||
|
||||
debug_text += "已缓存的图标:\n"
|
||||
for key in info['cache_keys']:
|
||||
debug_text += f" - {key}\n"
|
||||
|
||||
debug_text += "\n图标目录内容:\n"
|
||||
if os.path.exists(info['icon_directory']):
|
||||
for file_name in os.listdir(info['icon_directory']):
|
||||
file_path = os.path.join(info['icon_directory'], file_name)
|
||||
if os.path.isfile(file_path):
|
||||
size = os.path.getsize(file_path)
|
||||
debug_text += f" - {file_name} ({size} bytes)\n"
|
||||
else:
|
||||
debug_text += " 目录不存在\n"
|
||||
|
||||
text_edit.setPlainText(debug_text)
|
||||
layout.addWidget(text_edit)
|
||||
|
||||
button_box = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
button_box.rejected.connect(debug_dialog.close)
|
||||
layout.addWidget(button_box)
|
||||
|
||||
debug_dialog.exec_()
|
||||
|
||||
|
||||
def show_icon_manager(parent=None):
|
||||
"""显示图标管理器对话框"""
|
||||
dialog = IconManagerDialog(parent)
|
||||
dialog.show()
|
||||
return dialog
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
import sys
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
# 设置全局样式
|
||||
app.setStyleSheet("""
|
||||
QApplication {
|
||||
background-color: #1e1e2e;
|
||||
color: #e0e0ff;
|
||||
}
|
||||
""")
|
||||
|
||||
dialog = IconManagerDialog()
|
||||
dialog.show()
|
||||
|
||||
sys.exit(app.exec_())
|
||||
@ -20,6 +20,7 @@ from PyQt5.QtCore import Qt, QDir, QTimer, QSize, QPoint
|
||||
from direct.showbase.ShowBaseGlobal import aspect2d
|
||||
|
||||
from ui.widgets import CustomPanda3DWidget, CustomFileView, CustomTreeWidget,CustomAssetsTreeWidget, CustomConsoleDockWidget
|
||||
from ui.icon_manager import get_icon_manager, get_icon
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
"""主窗口类"""
|
||||
@ -29,6 +30,11 @@ class MainWindow(QMainWindow):
|
||||
self.world = world
|
||||
self.world.main_window = self # 关键:让world对象能访问主窗口
|
||||
|
||||
# 初始化图标管理器并打印调试信息
|
||||
self.icon_manager = get_icon_manager()
|
||||
print("🔧 图标管理器初始化完成")
|
||||
self.icon_manager.debug_info()
|
||||
|
||||
self.setStyleSheet("""
|
||||
QMainWindow {
|
||||
background-color: #1e1e2e;
|
||||
@ -325,7 +331,13 @@ class MainWindow(QMainWindow):
|
||||
def setupCenterWidget(self):
|
||||
"""设置窗口基本属性"""
|
||||
self.setWindowTitle("引擎编辑器")
|
||||
|
||||
# 使用图标管理器设置窗口图标
|
||||
app_icon = get_icon('app_logo')
|
||||
if not app_icon.isNull():
|
||||
self.setWindowIcon(app_icon)
|
||||
print("✅ 应用图标设置成功")
|
||||
else:
|
||||
print("⚠️ 应用图标设置失败,使用默认图标")
|
||||
# 使用自定义的 Panda3D 部件作为中央部件
|
||||
self.pandaWidget = CustomPanda3DWidget(self.world)
|
||||
self.setCentralWidget(self.pandaWidget)
|
||||
@ -425,9 +437,9 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# 选择工具
|
||||
self.selectTool = QToolButton()
|
||||
icon_path = self.get_icon_path("select_tool.png")
|
||||
if icon_path and os.path.exists(icon_path):
|
||||
self.selectTool.setIcon(QIcon(icon_path))
|
||||
select_icon = get_icon('select_tool', QSize(16, 16))
|
||||
if not select_icon.isNull():
|
||||
self.selectTool.setIcon(select_icon)
|
||||
else:
|
||||
self.selectTool.setText('选择') # 如果没有图标则显示文字
|
||||
self.selectTool.setIconSize(QSize(16, 16))
|
||||
@ -439,9 +451,9 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# 移动工具
|
||||
self.moveTool = QToolButton()
|
||||
icon_path = self.get_icon_path("move_tool.png")
|
||||
if icon_path and os.path.exists(icon_path):
|
||||
self.moveTool.setIcon(QIcon(icon_path))
|
||||
move_icon = get_icon('move_tool', QSize(16, 16))
|
||||
if not move_icon.isNull():
|
||||
self.moveTool.setIcon(move_icon)
|
||||
else:
|
||||
self.moveTool.setText('移动')
|
||||
self.moveTool.setIconSize(QSize(16, 16))
|
||||
@ -453,9 +465,9 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# 旋转工具
|
||||
self.rotateTool = QToolButton()
|
||||
icon_path = self.get_icon_path("rotate_tool.png")
|
||||
if icon_path and os.path.exists(icon_path):
|
||||
self.rotateTool.setIcon(QIcon(icon_path))
|
||||
rotate_icon = get_icon('rotate_tool', QSize(16, 16))
|
||||
if not rotate_icon.isNull():
|
||||
self.rotateTool.setIcon(rotate_icon)
|
||||
else:
|
||||
self.rotateTool.setText('旋转')
|
||||
self.rotateTool.setIconSize(QSize(16, 16))
|
||||
@ -467,9 +479,9 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# 缩放工具
|
||||
self.scaleTool = QToolButton()
|
||||
icon_path = self.get_icon_path("scale_tool.png")
|
||||
if icon_path and os.path.exists(icon_path):
|
||||
self.scaleTool.setIcon(QIcon(icon_path))
|
||||
scale_icon = get_icon('scale_tool', QSize(16, 16))
|
||||
if not scale_icon.isNull():
|
||||
self.scaleTool.setIcon(scale_icon)
|
||||
else:
|
||||
self.scaleTool.setText('缩放')
|
||||
self.scaleTool.setIconSize(QSize(16, 16))
|
||||
@ -637,8 +649,12 @@ class MainWindow(QMainWindow):
|
||||
self.moveAction = self.toolsMenu.addAction('移动工具')
|
||||
self.rotateAction = self.toolsMenu.addAction('旋转工具')
|
||||
self.scaleAction = self.toolsMenu.addAction('缩放工具')
|
||||
self.toolsMenu.addSeparator()
|
||||
self.sunsetAction = self.toolsMenu.addAction('光照编辑')
|
||||
self.pluginAction = self.toolsMenu.addAction('图形编辑')
|
||||
# self.toolsMenu.addSeparator()
|
||||
# self.iconManagerAction = self.toolsMenu.addAction('图标管理器')
|
||||
# self.iconManagerAction.triggered.connect(self.onOpenIconManager)
|
||||
|
||||
# 统一创建菜单 - 关键修改
|
||||
self.createMenu = menubar.addMenu('创建')
|
||||
@ -843,11 +859,21 @@ class MainWindow(QMainWindow):
|
||||
padding: 0px 0px; /* 增加内边距,提供更多的垂直空间 */
|
||||
border-bottom: 0px solid #3a3a4a;
|
||||
}
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
QDockWidget::close-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::float-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 25px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
||||
background-color: #7c3aed; /* 悬停时显示较亮的背景 */
|
||||
@ -887,11 +913,21 @@ class MainWindow(QMainWindow):
|
||||
padding: 0px 0px; /* 增加内边距,提供更多的垂直空间 */
|
||||
border-bottom: 0px solid #3a3a4a;
|
||||
}
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
QDockWidget::close-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::float-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 25px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
||||
background-color: #7c3aed; /* 悬停时显示较亮的背景 */
|
||||
@ -984,11 +1020,21 @@ class MainWindow(QMainWindow):
|
||||
padding: 0px 0px; /* 增加内边距,提供更多的垂直空间 */
|
||||
border-bottom: 0px solid #3a3a4a;
|
||||
}
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
QDockWidget::close-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::float-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 25px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
||||
background-color: #7c3aed; /* 悬停时显示较亮的背景 */
|
||||
@ -1086,11 +1132,21 @@ class MainWindow(QMainWindow):
|
||||
padding: 0px 0px; /* 增加内边距,提供更多的垂直空间 */
|
||||
border-bottom: 0px solid #3a3a4a;
|
||||
}
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
QDockWidget::close-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::float-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 25px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
||||
background-color: #7c3aed; /* 悬停时显示较亮的背景 */
|
||||
@ -1139,11 +1195,21 @@ class MainWindow(QMainWindow):
|
||||
padding: 0px 0px; /* 增加内边距,提供更多的垂直空间 */
|
||||
border-bottom: 0px solid #3a3a4a;
|
||||
}
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
QDockWidget::close-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::float-button {
|
||||
background-color: #8b5cf6;
|
||||
border: none;
|
||||
icon-size: 8px; /* 调整图标大小 */
|
||||
border-radius: 4px; /* 增加圆角 */
|
||||
right: 25px;
|
||||
top: 2px;
|
||||
}
|
||||
QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
||||
background-color: #7c3aed; /* 悬停时显示较亮的背景 */
|
||||
@ -2494,6 +2560,16 @@ class MainWindow(QMainWindow):
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"卸载脚本时出错: {str(e)}")
|
||||
|
||||
def onOpenIconManager(self):
|
||||
"""打开图标管理器"""
|
||||
try:
|
||||
from ui.icon_manager_gui import show_icon_manager
|
||||
self.icon_manager_dialog = show_icon_manager(self)
|
||||
print("🎨 图标管理器已打开")
|
||||
except Exception as e:
|
||||
print(f"❌ 打开图标管理器失败: {e}")
|
||||
QMessageBox.warning(self, "错误", f"打开图标管理器失败:\n{str(e)}")
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""处理窗口关闭事件"""
|
||||
try:
|
||||
|
||||
@ -2217,7 +2217,6 @@ class CustomTreeWidget(QTreeWidget):
|
||||
if not item:
|
||||
print(f"✅ Panda3D节点 '{node_name_for_logging}' 已清理并移除。UI树中未找到对应项。")
|
||||
return
|
||||
|
||||
try:
|
||||
# 2. 过滤受保护节点
|
||||
node_type = item.data(0, Qt.UserRole + 1)
|
||||
@ -2255,6 +2254,24 @@ class CustomTreeWidget(QTreeWidget):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def clear_tree(self):
|
||||
"""清空UI树"""
|
||||
print("Clear")
|
||||
self.clear()
|
||||
# 创建场景根节点
|
||||
sceneRoot = QTreeWidgetItem(self, ['场景'])
|
||||
sceneRoot.setData(0, Qt.UserRole, self.world.render)
|
||||
sceneRoot.setData(0, Qt.UserRole + 1, "SCENE_ROOT")
|
||||
# 添加相机节点
|
||||
cameraItem = QTreeWidgetItem(sceneRoot, ['相机'])
|
||||
cameraItem.setData(0, Qt.UserRole, self.world.cam)
|
||||
cameraItem.setData(0, Qt.UserRole + 1, "CAMERA_NODE")
|
||||
# 添加地板节点
|
||||
if hasattr(self.world, 'ground') and self.world.ground:
|
||||
groundItem = QTreeWidgetItem(sceneRoot, ['地板'])
|
||||
groundItem.setData(0, Qt.UserRole, self.world.ground)
|
||||
groundItem.setData(0,Qt.UserRole + 1, "SCENE_NODE")
|
||||
|
||||
def _cleanup_panda_node_resources(self, panda_node):
|
||||
"""一个集中的辅助函数,用于清理与Panda3D节点相关的所有资源。"""
|
||||
if not panda_node or panda_node.is_empty():
|
||||
|
||||
Loading…
Reference in New Issue
Block a user