addRender #2

Merged
Rowland merged 80 commits from addRender into main 2025-09-15 01:22:41 +00:00
7 changed files with 1170 additions and 301 deletions
Showing only changes of commit fb863f8e2b - Show all commits

View File

@ -317,11 +317,10 @@ class InfoPanelManager(DirectObject):
return True
# 更新 registerDataSource 方法以更好地处理不同类型面板
def registerDataSource(self, panel_id, data_callback, update_interval=1.0):
"""
注册数据源定期更新面板内容
data_callback: 返回数据的回调函数
update_interval: 更新间隔
注册数据源定期更新面板内容 - 改进版
"""
if panel_id not in self.panels:
print(f"面板 {panel_id} 不存在")
@ -335,7 +334,8 @@ class InfoPanelManager(DirectObject):
data_source = {
'callback': data_callback,
'interval': update_interval,
'stop': False
'stop': False,
'panel_type': '3d' if self._is3DPanel(panel_id) else '2d' if self._is2DPanel(panel_id) else 'unknown'
}
self.data_sources[panel_id] = data_source
@ -346,9 +346,10 @@ class InfoPanelManager(DirectObject):
return True
# 在 InfoPanelManager 类中修复 _updateDataThread 方法
def _updateDataThread(self, panel_id):
"""
数据更新线程
数据更新线程 - 最终修复版
"""
while panel_id in self.data_sources and not self.data_sources[panel_id]['stop']:
try:
@ -357,7 +358,18 @@ class InfoPanelManager(DirectObject):
# 更新面板内容
if data and panel_id in self.panels:
self.updatePanelContent(panel_id, content=data)
panel_type = self.data_sources[panel_id].get('panel_type', 'unknown')
if panel_type == '2d':
self.updatePanelContent(panel_id, content=data)
elif panel_type == '3d':
self.update3DPanelContent(panel_id, content=data)
else:
# 尝试自动检测
if self._is2DPanel(panel_id):
self.updatePanelContent(panel_id, content=data)
elif self._is3DPanel(panel_id):
self.update3DPanelContent(panel_id, content=data)
# 等待下次更新
interval = self.data_sources[panel_id]['interval']
@ -365,8 +377,29 @@ class InfoPanelManager(DirectObject):
except Exception as e:
print(f"更新面板 {panel_id} 数据时出错: {e}")
import traceback
traceback.print_exc()
time.sleep(1.0) # 出错时等待1秒再重试
# 在 InfoPanelManager 类中添加以下方法
def _is3DPanel(self, panel_id):
"""
判断面板是否为3D面板
"""
if panel_id not in self.panels:
return False
panel_data = self.panels[panel_id]
return 'content_node' in panel_data and 'content_label' not in panel_data
def _is2DPanel(self, panel_id):
"""
判断面板是否为2D面板
"""
if panel_id not in self.panels:
return False
panel_data = self.panels[panel_id]
return 'content_label' in panel_data and 'content_node' not in panel_data
def unregisterDataSource(self, panel_id):
"""
注销数据源
@ -657,10 +690,237 @@ class InfoPanelManager(DirectObject):
return True
def create3DInfoPanel(self, panel_id, position=(0, 0, 0), size=(1.0, 0.6),
bg_color=(0.15, 0.15, 0.15, 0.9), border_color=(0.3, 0.3, 0.3, 1.0),
title_color=(1.0, 1.0, 1.0, 1.0), content_color=(0.9, 0.9, 0.9, 1.0),
visible=True, font=None, bg_image=None):
"""
创建简化版3D信息面板 - 只显示文字无面板背景避免闪烁
"""
# 如果面板已存在,先移除它
if panel_id in self.panels:
self.removePanel(panel_id)
# 确保父节点存在
parent_node = self.parent if self.parent else self.world.render
# 根据面板ID确定标题和内容
title, content = self._getPanelContent(panel_id)
# 创建主节点,便于统一管理
panel_node = parent_node.attachNewNode(f"info_panel_3d_{panel_id}")
panel_node.setPos(position[0], position[1], position[2])
# 直接创建文字节点,不创建面板背景和边框
from panda3d.core import TextNode
# 创建标题文本
title_text_node = TextNode(f'title_{panel_id}')
title_text_node.setText(title)
title_text_node.setTextColor(*title_color)
title_text_node.setAlign(TextNode.ACenter)
if font:
title_text_node.setFont(font)
title_text = panel_node.attachNewNode(title_text_node)
title_text.setScale(0.06)
title_text.setPos(0, 0, size[1] / 4) # 将标题放在上方
# 创建内容文本
content_text_node = TextNode(f'content_{panel_id}')
content_text_node.setText(content)
content_text_node.setTextColor(*content_color)
content_text_node.setAlign(TextNode.ALeft)
content_text_node.setWordwrap(size[0] * 2) # 根据面板宽度设置换行
if font:
content_text_node.setFont(font)
content_text = panel_node.attachNewNode(content_text_node)
content_text.setScale(0.045)
content_text.setPos(-size[0] / 2, 0, size[1] / 4 - 0.1) # 将内容放在标题下方
# 保存引用
self.panels[panel_id] = {
'node': panel_node,
'title_text': title_text,
'content_text': content_text,
'title_node': title_text_node,
'content_node': content_text_node,
'properties': {
'size': size,
'position': position,
'title_color': title_color,
'content_color': content_color,
'font': font
}
}
# 设置GUI类型标记和支持3D编辑的标记
panel_node.setTag("gui_type", "info_panel_3d")
panel_node.setTag("panel_id", panel_id)
panel_node.setTag("supports_3d_position_editing", "1") # 支持3D位置编辑
if not visible:
panel_node.hide()
return panel_node
def update3DPanelContent(self, panel_id, title=None, content=None):
"""
更新3D面板内容
"""
if panel_id not in self.panels:
print(f"面板 {panel_id} 不存在")
return False
panel_data = self.panels[panel_id]
if title is not None and 'title_node' in panel_data:
panel_data['title_node'].setText(title)
if content is not None and 'content_node' in panel_data:
panel_data['content_node'].setText(content)
return True
def update3DPanelProperties(self, panel_id, **properties):
"""
更新3D面板属性
"""
if panel_id not in self.panels:
print(f"面板 {panel_id} 不存在")
return False
panel_data = self.panels[panel_id]
props = panel_data['properties']
# 更新位置
if 'position' in properties:
pos = properties['position']
panel_data['node'].setPos(pos[0], pos[1], pos[2])
props['position'] = pos
# 更新大小
if 'size' in properties:
size = properties['size']
props['size'] = size
# 由于3D面板使用CardMaker创建需要重新创建几何体
print("注意3D面板大小调整需要重新创建面板几何体")
# 更新背景颜色
if 'bg_color' in properties:
bg_color = properties['bg_color']
if 'panel_bg' in panel_data:
from panda3d.core import Material
material = Material()
material.setDiffuse(Vec4(*bg_color))
material.setAmbient(Vec4(*bg_color[:3], 1.0))
panel_data['panel_bg'].setMaterial(material, 1)
props['bg_color'] = bg_color
# 更新边框颜色
if 'border_color' in properties:
border_color = properties['border_color']
from panda3d.core import Material
border_mat = Material()
border_mat.setDiffuse(Vec4(*border_color))
for border in panel_data['borders'].values():
border.setMaterial(border_mat, 1)
props['border_color'] = border_color
# 更新标题颜色
if 'title_color' in properties:
title_color = properties['title_color']
if 'title_node' in panel_data:
panel_data['title_node'].setTextColor(*title_color)
props['title_color'] = title_color
# 更新内容颜色
if 'content_color' in properties:
content_color = properties['content_color']
if 'content_node' in panel_data:
panel_data['content_node'].setTextColor(*content_color)
props['content_color'] = content_color
# 更新标题
if 'title' in properties:
if 'title_node' in panel_data:
panel_data['title_node'].setText(properties['title'])
# 更新内容
if 'content' in properties:
if 'content_node' in panel_data:
panel_data['content_node'].setText(properties['content'])
# 更新字体大小
if 'title_size' in properties:
if 'title_text' in panel_data:
panel_data['title_text'].setScale(properties['title_size'])
props['title_size'] = properties['title_size']
if 'content_size' in properties:
if 'content_text' in panel_data:
panel_data['content_text'].setScale(properties['content_size'])
props['content_size'] = properties['content_size']
return True
def create3DHTTPInfoPanel(self, panel_id, url, method="GET", headers=None, data=None,
position=(0, 0, 0), size=(1.0, 0.6),
bg_color=(0.15, 0.15, 0.15, 0.9),
border_color=(0.3, 0.3, 0.3, 1.0),
title_color=(1.0, 1.0, 1.0, 1.0),
content_color=(0.9, 0.9, 0.9, 1.0),
update_interval=30.0, font=None):
"""
创建3D HTTP信息面板
"""
# 创建面板
domain = urlparse(url).netloc or url[:30]
title = f"HTTP数据: {domain}"
panel_node = self.create3DInfoPanel(
panel_id=panel_id,
position=position,
size=size,
bg_color=bg_color,
border_color=border_color,
title_color=title_color,
content_color=content_color,
font=font
)
# 更新标题
self.update3DPanelContent(panel_id, title=title)
# 立即获取并显示数据
content = fetchHTTPData(url, method, headers, data)
self.update3DPanelContent(panel_id, content=content)
# 注册数据源,定期更新
def http_data_callback():
return fetchHTTPData(url, method, headers, data)
self.registerDataSource(panel_id, http_data_callback, update_interval)
# 保存HTTP请求信息便于后续更新
if panel_id not in self.data_sources:
self.data_sources[panel_id] = {}
self.data_sources[panel_id]['http_info'] = {
'url': url,
'method': method,
'headers': headers,
'data': data
}
return panel_node
# 在 add_methods_to_property_panel 函数中添加以下方法
def add_methods_to_property_panel(property_panel_instance):
# ... (原有代码保持不变)
import types
def createHTTPInfoPanel(self, url, panel_id="http_info", method="GET", headers=None, data=None,
position=(0.8, 0.0), size=(0.4, 0.3), update_interval=30.0):
@ -721,8 +981,100 @@ class InfoPanelManager(DirectObject):
print(f"✗ 更新HTTP信息面板失败: {e}")
return False
def create3DRealtimeDataPanel(self, data_callback=None, update_interval=1.0):
"""创建3D实时数据面板"""
try:
# 确保父节点已设置
if self.info_panel_manager.parent is None and hasattr(self, 'world'):
self.info_panel_manager.setParent(self.world.render)
# 创建3D实时数据面板
panel_node = self.info_panel_manager.create3DInfoPanel(
panel_id="realtime_data_3d",
position=(0, 0, 0),
size=(0.35, 0.3),
bg_color=(0.15, 0.25, 0.35, 0.95), # 蓝色背景
border_color=(0.3, 0.5, 0.7, 1.0), # 蓝色边框
title_color=(0.7, 0.9, 1.0, 1.0), # 浅蓝色标题
content_color=(0.95, 0.95, 0.95, 1.0)
)
# 设置标签
panel_node.setTag("element_type", "info_panel_3d")
panel_node.setTag("is_scene_element", "1")
panel_node.setTag("supports_3d_position_editing", "1") # 支持3D位置编辑
# 如果提供了数据回调函数,则注册数据源
if data_callback:
# 立即显示初始数据
initial_data = data_callback()
self.info_panel_manager.update3DPanelContent("realtime_data_3d", content=initial_data)
# 注册数据源
self.info_panel_manager.registerDataSource("realtime_data_3d", data_callback, update_interval)
else:
# 使用默认数据
default_data = "等待数据..."
self.info_panel_manager.update3DPanelContent("realtime_data_3d", content=default_data)
print("✓ 已创建3D实时数据面板")
return panel_node
except Exception as e:
print(f"✗ 创建3D实时数据面板失败: {e}")
return None
def create3DModelInfoPanel(self, model):
"""为模型创建3D信息面板"""
try:
# 确保父节点已设置
if self.info_panel_manager.parent is None and hasattr(self, 'world'):
self.info_panel_manager.setParent(self.world.render)
# 获取模型信息
model_name = model.getName() if hasattr(model, 'getName') else 'Unknown'
num_children = model.getNumChildren() if hasattr(model, 'getNumChildren') else 0
# 创建面板内容
content = f"模型名称: {model_name}\n子节点数: {num_children}\n类型: {type(model).__name__}"
# 创建或更新面板
panel_node = self.info_panel_manager.create3DInfoPanel(
panel_id="model_info_3d",
position=(2, 0, 0), # 默认放在模型旁边
size=(0.35, 0.25),
bg_color=(0.15, 0.15, 0.25, 0.95), # 蓝紫色背景
border_color=(0.3, 0.3, 0.7, 1.0), # 蓝色边框
title_color=(0.5, 0.8, 1.0, 1.0), # 浅蓝色标题
content_color=(0.95, 0.95, 0.95, 1.0)
)
# 更新面板内容为模型特定信息
self.info_panel_manager.update3DPanelContent("model_info_3d",
title="模型信息",
content=content)
# 设置标签
panel_node.setTag("element_type", "info_panel_3d")
panel_node.setTag("is_scene_element", "1")
panel_node.setTag("supports_3d_position_editing", "1") # 支持3D位置编辑
print(f"✓ 已创建3D模型信息面板: {model_name}")
return panel_node
except Exception as e:
print(f"✗ 创建3D模型信息面板失败: {e}")
return None
# 在绑定方法的部分添加3D面板方法
property_panel_instance.create3DRealtimeDataPanel = types.MethodType(create3DRealtimeDataPanel,
property_panel_instance)
property_panel_instance.create3DModelInfoPanel = types.MethodType(create3DModelInfoPanel,
property_panel_instance)
# 将新方法绑定到实例
import types
# ... (原有绑定保持不变)
property_panel_instance.createHTTPInfoPanel = types.MethodType(createHTTPInfoPanel, property_panel_instance)
property_panel_instance.updateHTTPInfoPanel = types.MethodType(updateHTTPInfoPanel, property_panel_instance)
@ -777,6 +1129,7 @@ def add_methods_to_property_panel(property_panel_instance):
"""
property_panel 实例添加 DirectGUI 信息面板支持
"""
import types
# 添加信息面板管理器作为类属性
if not hasattr(property_panel_instance, 'info_panel_manager'):
@ -982,7 +1335,6 @@ def add_methods_to_property_panel(property_panel_instance):
property_panel_instance.removeInfoPanel = types.MethodType(removeInfoPanel, property_panel_instance)
property_panel_instance.setupInfoPanelManager = types.MethodType(setupInfoPanelManager, property_panel_instance)
def fetchHTTPData(url, method="GET", headers=None, data=None, timeout=5):
"""
获取HTTP数据的通用函数

View File

@ -877,7 +877,7 @@ class SelectionSystem:
handle_node = children[0]
if not handle_node:
print(f"未找到{axis}轴的处理模型")
#print(f"未找到{axis}轴的处理模型")
return
# 创建或获取材质
@ -985,7 +985,7 @@ class SelectionSystem:
handle_node = children[0]
if not handle_node:
print(f"未找到{axis}轴的处理模型")
# print(f"未找到{axis}轴的处理模型")
return
# 创建或获取材质

View File

@ -3217,7 +3217,7 @@ class GUIManager:
try:
gui_type = gui_element.getTag("gui_type")
if gui_type in ["3d_text", "3d_image", "video_screen","info_panel"]:
if gui_type in ["3d_text", "3d_image", "video_screen","info_panel","info_panel_3d"]:
current_pos = gui_element.getPos()
if axis == "x":
@ -3230,7 +3230,7 @@ class GUIManager:
return False
gui_element.setPos(*new_pos)
print(f"✓ 更新3D GUI元素位置: {axis}={value}")
#print(f"✓ 更新3D GUI元素位置: {axis}={value}")
return True
else:
print(f"✗ 不支持的GUI类型进行3D位置编辑: {gui_type}")
@ -3251,7 +3251,7 @@ class GUIManager:
if value == 0:
value = 0.01
if gui_type in ["3d_text", "3d_image","video_screen","virtual_screen","info_panel"]:
if gui_type in ["3d_text", "3d_image","video_screen","virtual_screen","info_panel","info_panel_3d"]:
# 3D元素处理
if axis == "x":
new_scale = (value, current_scale.getY(), current_scale.getZ())

View File

@ -830,6 +830,7 @@ def createNewProject(parent_window):
def saveProject(appw):
"""保存项目 - 代理到project_manager"""
world = appw.centralWidget().world
return world.project_manager.saveProject(appw)

View File

@ -384,19 +384,26 @@ class MainWindow(QMainWindow):
self.createSamplePanelAction = self.infoPanelMenu.addAction('创建示例面板')
self.createSamplePanelAction.triggered.connect(self.onCreateSampleInfoPanel)
# 添加更多面板创建选项
self.createSystemStatusPanelAction = self.infoPanelMenu.addAction('创建系统状态面板')
self.createSystemStatusPanelAction.triggered.connect(self.onCreateSystemStatusPanel)
# self.createSystemStatusPanelAction = self.infoPanelMenu.addAction('创建系统状态面板')
# self.createSystemStatusPanelAction.triggered.connect(self.onCreateSystemStatusPanel)
#
# self.createSensorDataPanelAction = self.infoPanelMenu.addAction('创建传感器数据面板')
# self.createSensorDataPanelAction.triggered.connect(self.onCreateSensorDataPanel)
#
# self.createSceneInfoPanelAction = self.infoPanelMenu.addAction('创建场景信息面板')
# self.createSceneInfoPanelAction.triggered.connect(self.onCreateSceneInfoPanel)
self.createSensorDataPanelAction = self.infoPanelMenu.addAction('创建传感器数据面板')
self.createSensorDataPanelAction.triggered.connect(self.onCreateSensorDataPanel)
self.createSceneInfoPanelAction = self.infoPanelMenu.addAction('创建场景信息面板')
self.createSceneInfoPanelAction.triggered.connect(self.onCreateSceneInfoPanel)
self.infoPanelMenu.addSeparator()
self.create3DSamplePanelAction = self.infoPanelMenu.addAction('创建3D实例面板')
self.create3DSamplePanelAction.triggered.connect(self.onCreate3DSampleInfoPanel)
#
# self.create3DSystemStatusPanelAction = self.infoPanelMenu.addAction('创建3D系统状态面板')
# self.create3DSystemStatusPanelAction.triggered.connect(self.onCreate3DSystemStatusPanel)
# 添加分隔符和批量创建选项
self.infoPanelMenu.addSeparator()
self.createAllPanelsAction = self.infoPanelMenu.addAction('创建所有面板')
self.createAllPanelsAction.triggered.connect(self.onCreateAllInfoPanels)
# self.infoPanelMenu.addSeparator()
# self.createAllPanelsAction = self.infoPanelMenu.addAction('创建所有面板')
# self.createAllPanelsAction.triggered.connect(self.onCreateAllInfoPanels)
@ -1131,7 +1138,7 @@ class MainWindow(QMainWindow):
# 立即显示加载中信息
info_manager.updatePanelContent(unique_id, content="正在获取天气数据...")
info_manager.registerDataSource(unique_id, self.getRealWeatherData, update_interval=5.0) # 每10分钟更新一次
info_manager.registerDataSource(unique_id, self.getRealWeatherData, update_interval=5.0)
# # 立即显示示例数据
# sample_data = self.getSampleWeatherData()
@ -1225,6 +1232,142 @@ class MainWindow(QMainWindow):
except Exception as e:
return f"获取示例数据失败: {str(e)}"
# 在 main_window.py 中修改 onCreate3DSampleInfoPanel 方法
def onCreate3DSampleInfoPanel(self):
"""创建3D示例天气信息面板修复透明度问题"""
try:
# 获取中文字体
from panda3d.core import TextNode
font = self.world.getChineseFont() if self.world.getChineseFont() else None
# 创建面板
info_manager = self.world.info_panel_manager
info_manager.setParent(self.world.render)
# 使用唯一的面板ID
import time
unique_id = f"weather_info_3d_{int(time.time())}"
# 创建3D示例面板 - 修复透明度问题
weather_panel = info_manager.create3DInfoPanel(
panel_id=unique_id,
position=(2, 0, 2), # 调整Z坐标避免与其他对象重叠
size=(1, 1),
bg_color=(0.15, 0.25, 0.35, 0.85), # 设置合适的透明度值
border_color=(0.3, 0.5, 0.7, 1.0),
title_color=(0.7, 0.9, 1.0, 1.0),
content_color=(0.95, 0.95, 0.95, 1.0),
font=font
)
# 重要:手动设置面板的透明度渲染模式
# if weather_panel:
# # 确保面板支持透明度
# weather_panel.setTransparency(True)
# # 设置合适的渲染顺序,确保透明对象正确渲染
# weather_panel.setBin("transparent", 0)
# # 启用深度写入,但保持透明度
# weather_panel.setDepthWrite(False)
# 更新面板标题
info_manager.update3DPanelContent(unique_id, title="3D北京天气")
# 添加到场景树
self.addInfoPanelToTree(weather_panel, "3D天气信息面板")
# 显示加载中信息
info_manager.update3DPanelContent(unique_id, content="正在获取天气数据...")
info_manager.registerDataSource(unique_id, self.getRealWeatherData, update_interval=5.0)
print("✓ 3D示例天气信息面板已创建")
except Exception as e:
print(f"✗ 创建3D示例天气信息面板失败: {e}")
import traceback
traceback.print_exc()
QMessageBox.critical(self, "错误", f"创建3D示例天气信息面板时出错: {str(e)}")
def onCreate3DSystemStatusPanel(self):
"""创建3D系统状态信息面板"""
try:
# 获取中文字体
from panda3d.core import TextNode
font = self.world.getChineseFont() if self.world.getChineseFont() else None
# 创建面板
info_manager = self.world.info_panel_manager
info_manager.setParent(self.world.render)
# 使用唯一的面板ID
import time
unique_id = f"system_status_3d_{int(time.time())}"
panel = info_manager.create3DInfoPanel(
panel_id=unique_id,
position=(2, 0, 0),
size=(0.8, 1.2),
bg_color=(0.25, 0.15, 0.15, 0.95), # 红色背景
border_color=(0.7, 0.3, 0.3, 1.0), # 红色边框
title_color=(1.0, 0.5, 0.5, 1.0), # 浅红色标题
content_color=(0.95, 0.95, 0.95, 1.0),
font=font
)
# 添加到场景树
self.addInfoPanelToTree(panel, "3D系统状态信息面板")
# 立即显示初始数据
initial_data = self.getSystemStatusData()
info_manager.update3DPanelContent(unique_id, content=initial_data)
# 注册数据源每5秒更新一次
info_manager.registerDataSource(unique_id, self.getSystemStatusData, update_interval=5.0)
except Exception as e:
print(f"✗ 创建3D系统状态信息面板失败: {e}")
import traceback
traceback.print_exc()
QMessageBox.critical(self, "错误", f"创建3D系统状态信息面板时出错: {str(e)}")
# 更新 addInfoPanelToTree 方法以支持3D面板
def addInfoPanelToTree(self, panel, panel_name):
"""
将信息面板添加到场景树控件中
"""
if panel and self.treeWidget:
# 找到场景根节点
scene_root = None
for i in range(self.treeWidget.topLevelItemCount()):
item = self.treeWidget.topLevelItem(i)
if item.text(0) == "render":
scene_root = item
break
# 如果找不到场景根节点,使用第一个顶级节点
if not scene_root and self.treeWidget.topLevelItemCount() > 0:
scene_root = self.treeWidget.topLevelItem(0)
if scene_root:
# 根据面板类型确定节点类型
node_type = "INFO_PANEL_3D" if "3d" in panel_name.lower() else "INFO_PANEL"
tree_item = self.treeWidget.add_node_to_tree_widget(
node=panel,
parent_item=scene_root,
node_type=node_type
)
if tree_item:
self.treeWidget.setCurrentItem(tree_item)
self.treeWidget.update_selection_and_properties(panel, tree_item)
print(f"{panel_name}节点已添加到场景树")
return True
else:
print(f"⚠️ {panel_name}节点添加到场景树失败")
else:
print("❌ 未找到场景根节点")
return False
def onCreateSystemStatusPanel(self):
"""创建系统状态信息面板"""
try:
@ -1449,40 +1592,6 @@ class MainWindow(QMainWindow):
except Exception as e:
QMessageBox.critical(self, "错误", f"创建信息面板时出错: {str(e)}")
def addInfoPanelToTree(self, panel, panel_name):
"""
将信息面板添加到场景树控件中
"""
if panel and self.treeWidget:
# 找到场景根节点
scene_root = None
for i in range(self.treeWidget.topLevelItemCount()):
item = self.treeWidget.topLevelItem(i)
if item.text(0) == "render":
scene_root = item
break
# 如果找不到场景根节点,使用第一个顶级节点
if not scene_root and self.treeWidget.topLevelItemCount() > 0:
scene_root = self.treeWidget.topLevelItem(0)
if scene_root:
tree_item = self.treeWidget.add_node_to_tree_widget(
node=panel,
parent_item=scene_root,
node_type="INFO_PANEL"
)
if tree_item:
self.treeWidget.setCurrentItem(tree_item)
self.treeWidget.update_selection_and_properties(panel, tree_item)
print(f"{panel_name}节点已添加到场景树")
return True
else:
print(f"⚠️ {panel_name}节点添加到场景树失败")
else:
print("❌ 未找到场景根节点")
return False
# ==================== 脚本管理事件处理 ====================
def refreshScriptsList(self):

File diff suppressed because it is too large Load Diff

View File

@ -696,7 +696,7 @@ class CustomAssetsTreeWidget(QTreeWidget):
if os.path.exists(directory) and directory not in self.watched_directories:
if self.file_watcher.addPath(directory):
self.watched_directories.add(directory)
print(f"开始监控目录:{directory}")
#print(f"开始监控目录:{directory}")
try:
for item in os.listdir(directory):
item_path = os.path.join(directory,item)
@ -1874,6 +1874,8 @@ class CustomTreeWidget(QTreeWidget):
selected_items = self.selectedItems()
if selected_items:
# 执行删除操作
# if selected_items.data(0, Qt.UserRole + 1) == "LIGHT_NODE":
# self._preprocess_light_items_for_deletion(selected_items)
self.delete_items(selected_items)
else:
# 没有选中任何项目,执行默认操作
@ -1881,6 +1883,52 @@ class CustomTreeWidget(QTreeWidget):
else:
super().keyPressEvent(event)
def _preprocess_light_items_for_deletion(self, selected_items):
"""预处理灯光节点删除,特别处理最后一个灯光节点的问题"""
if not selected_items:
return selected_items
# 检查选中的项目中是否包含灯光节点
light_items = []
for item in selected_items:
node_type = item.data(0, Qt.UserRole + 1)
if node_type == "LIGHT_NODE":
light_items.append(item)
# 如果没有灯光节点,直接返回
if not light_items:
return selected_items
# 检查是否只有最后一个灯光节点被选中
processed_items = list(selected_items) # 创建副本
for item in light_items:
panda_node = item.data(0, Qt.UserRole)
if not panda_node:
continue
# 获取灯光类型
if hasattr(panda_node, 'getTag'):
light_type = panda_node.getTag("light_type")
# 检查是否是最后一个Spotlight
if (light_type == "spot_light" and hasattr(self.world, 'Spotlight') and
self.world.Spotlight and self.world.Spotlight[-1] == panda_node and
len(self.world.Spotlight) > 1):
print(f"⚠️ 检测到选中最后一个Spotlight节点: {item.text(0)}")
# 这里可以添加特殊处理逻辑,比如提示用户或阻止删除
# 检查是否是最后一个Pointlight
elif (light_type == "point_light" and hasattr(self.world, 'Pointlight') and
self.world.Pointlight and self.world.Pointlight[-1] == panda_node and
len(self.world.Pointlight) > 1):
print(f"⚠️ 检测到选中最后一个Pointlight节点: {item.text(0)}")
# 这里可以添加特殊处理逻辑,比如提示用户或阻止删除
return processed_items
def delete_items(self, selected_items):
"""删除选中的item - 简化版本"""
if not selected_items: