This commit is contained in:
陈横 2025-09-17 11:11:46 +08:00
parent dff3726bbf
commit 9a997c4036
12 changed files with 875 additions and 42 deletions

File diff suppressed because one or more lines are too long

View File

@ -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()

View File

@ -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()

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -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)
# 启动应用程序

View File

@ -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

View File

@ -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
View 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
View 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_())

View File

@ -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:

View File

@ -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():