diff --git a/core/world.py b/core/world.py index 4860ad50..0538877f 100644 --- a/core/world.py +++ b/core/world.py @@ -288,6 +288,7 @@ 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") print("✓ 相机设置完成") def _setupLighting(self): @@ -321,6 +322,7 @@ class CoreWorld(Panda3DWorld): self.ground.setP(-90) self.ground.setZ(-0.1) self.ground.setColor(0.8, 0.8, 0.8, 1) + # self.ground.setTag("is_scene_element", "1") # 创建支持贴图的材质 mat = Material() diff --git a/scene/scene_manager.py b/scene/scene_manager.py index 3ed0eda8..261b8e73 100644 --- a/scene/scene_manager.py +++ b/scene/scene_manager.py @@ -168,6 +168,7 @@ class SceneManager: # 添加文件标签用于保存/加载 model.setTag("file", model_name) model.setTag("is_model_root", "1") + model.setTag("is_scene_element", "1") # 记录应用的处理选项 if apply_unit_conversion: @@ -914,12 +915,25 @@ class SceneManager: print(f"场景文件不存在: {filename}") return False + tree_widget = self._get_tree_widget() # 清除当前场景 print("\n清除当前场景...") for model in self.models: - if not model.isEmpty(): - model.removeNode() - self.models.clear() + 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) + + # 清除tilesets + for tileset_info in self.tilesets: + tree_widget.delete_item(tileset_info['node']) for light in self.Spotlight: if not light.isEmpty(): @@ -958,6 +972,8 @@ class SceneManager: print("场景加载失败") return False + # tree_widget.create_model_items(scene) + # 遍历场景中的所有模型节点 # 用于存储处理后的灯光节点,避免重复处理 processed_lights = [] # 用于存储处理后的GUI元素,避免重复处理 @@ -1211,6 +1227,7 @@ class SceneManager: # 更新场景树 self.updateSceneTree() + # self._get_tree_widget().create_model_items(scene) print(f"加载完成,GUI元素数量: {len(self.world.gui_elements)}") if len(self.world.gui_elements) > 0: diff --git a/ui/main_window.py b/ui/main_window.py index 1fbc5078..9f935eaf 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -6,7 +6,7 @@ - 停靠窗口设置 - 事件连接和信号处理 """ - +import os import sys from PyQt5.QtGui import QKeySequence, QIcon @@ -69,6 +69,20 @@ class MainWindow(QMainWindow): int(screen.height() / 2 - self.height() / 2), ) + @staticmethod + def get_icon_path(icon_name): + """获取图标文件的完整路径""" + # 假设 icons 文件夹在项目根目录下 + project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + icon_path = os.path.join(project_root, "icons", icon_name) + + # 检查文件是否存在,如果不存在则返回默认值或None + if not os.path.exists(icon_path): + print(f"警告: 图标文件不存在: {icon_path}") + return "" # 返回空字符串,QIcon会处理空路径 + + return icon_path + def setupEmbeddedToolbar(self): """创建Unity风格的内嵌工具栏""" # 创建工具栏容器 @@ -109,8 +123,11 @@ class MainWindow(QMainWindow): # 选择工具 self.selectTool = QToolButton() - self.selectTool.setIcon(QIcon("icons/select_tool.png")) # 使用图标资源 - self.selectTool.setText('选择') + icon_path = self.get_icon_path("select_tool.png") + if icon_path and os.path.exists(icon_path): + self.selectTool.setIcon(QIcon(icon_path)) + else: + self.selectTool.setText('选择') # 如果没有图标则显示文字 self.selectTool.setIconSize(QSize(16, 16)) self.selectTool.setCheckable(True) self.selectTool.setToolTip("选择工具 (Q)") @@ -120,8 +137,11 @@ class MainWindow(QMainWindow): # 移动工具 self.moveTool = QToolButton() - self.moveTool.setIcon(QIcon("icons/move_tool.png")) - self.moveTool.setText('移动') + icon_path = self.get_icon_path("move_tool.png") + if icon_path and os.path.exists(icon_path): + self.moveTool.setIcon(QIcon(icon_path)) + else: + self.moveTool.setText('移动') self.moveTool.setIconSize(QSize(16, 16)) self.moveTool.setCheckable(True) self.moveTool.setToolTip("移动工具 (W)") @@ -131,8 +151,11 @@ class MainWindow(QMainWindow): # 旋转工具 self.rotateTool = QToolButton() - self.rotateTool.setIcon(QIcon("icons/rotate_tool.png")) - self.rotateTool.setText('旋转') + icon_path = self.get_icon_path("rotate_tool.png") + if icon_path and os.path.exists(icon_path): + self.rotateTool.setIcon(QIcon(icon_path)) + else: + self.rotateTool.setText('旋转') self.rotateTool.setIconSize(QSize(16, 16)) self.rotateTool.setCheckable(True) self.rotateTool.setToolTip("旋转工具 (E)") @@ -142,8 +165,11 @@ class MainWindow(QMainWindow): # 缩放工具 self.scaleTool = QToolButton() - self.scaleTool.setIcon(QIcon("icons/scale_tool.png")) - self.scaleTool.setText('缩放') + icon_path = self.get_icon_path("scale_tool.png") + if icon_path and os.path.exists(icon_path): + self.scaleTool.setIcon(QIcon(icon_path)) + else: + self.scaleTool.setText('缩放') self.scaleTool.setIconSize(QSize(16, 16)) self.scaleTool.setCheckable(True) self.scaleTool.setToolTip("缩放工具 (R)") diff --git a/ui/widgets.py b/ui/widgets.py index 4f0fc48f..c1507f18 100644 --- a/ui/widgets.py +++ b/ui/widgets.py @@ -18,7 +18,7 @@ from PyQt5.QtCore import Qt, QUrl, QMimeData from PyQt5.QtGui import QDrag, QPainter, QPixmap, QPen, QBrush from PyQt5.sip import wrapinstance from direct.showbase.ShowBaseGlobal import aspect2d -from panda3d.core import ModelRoot +from panda3d.core import ModelRoot, NodePath from QPanda3D.QPanda3DWidget import QPanda3DWidget from scene import util @@ -1474,12 +1474,9 @@ class CustomTreeWidget(QTreeWidget): def showContextMenu(self, position): """显示右键菜单 - 复用主菜单的创建动作""" - if not self.selectedItems(): - print("没有选中的项目,不显示右键菜单") - return - - item = self.selectedItems()[0] - print(f"为项目 '{item.text(0)}' 显示右键菜单") + if self.selectedItems(): + item = self.selectedItems()[0] + print(f"为项目 '{item.text(0)}' 显示右键菜单") # 创建右键菜单 menu = QMenu(self) @@ -2187,6 +2184,62 @@ class CustomTreeWidget(QTreeWidget): except Exception as e: print(e) + def _findSceneRoot(self): + """查找场景根节点""" + for i in range(self.topLevelItemCount()): + top_item = self.topLevelItem(i) + if top_item.data(0, Qt.UserRole + 1) == "SCENE_ROOT": + return top_item + return None + + def create_model_items(self, model): + if not model: + print("传入的参数model为空") + return + # 创建根节点项 + # root_item = QTreeWidgetItem(self) + # root_item.setText(0, model.getName() or "Unnamed Node") + # root_item.setText(1, model.node().getTypeName()) + # root_item.setIcon(0, self.item_icons.get('model', self.item_icons['default'])) + + # 存储NodePath引用以便后续操作 + # root_item.setData(0, Qt.UserRole, model) + root_item = self._findSceneRoot() + + # 递归添加子节点 + self._add_children_recursive(root_item, model) + + return root_item + + def _add_children_recursive(self, parent_item, node_path: NodePath): + """递归添加子节点到树项""" + print(f'开始递归添加子节点') + # 获取所有子节点 + children = node_path.getChildren() + + for i in range(children.getNumPaths()): + child_node: NodePath = children.getPath(i) + + # 过滤条件 + if not child_node.hasTag("is_scene_element"): + print(f"不存在------------------------{child_node.hasTag('is_scene_element')}") + continue + + print(f"存在------------------------{child_node.getName()}") + # 创建子项 + child_item = QTreeWidgetItem(parent_item) + child_item.setText(0, child_node.getName() or f"Child_{i}") + + # 存储NodePath引用 + child_item.setData(0, Qt.UserRole, child_node) + + # 添加额外信息(可选) + # self._add_node_info(child_item, child_node) + + # 递归处理子节点的子节点 + if child_node.getNumChildren() > 0: + self._add_children_recursive(child_item, child_node) + # ==================== 辅助方法 ==================== def _findSceneRoot(self): """查找场景根节点"""