This commit is contained in:
Rowland 2026-01-22 10:46:53 +08:00
parent ef9fabd43d
commit 99ef5c0253
5 changed files with 7095 additions and 4490 deletions

2124
demo.py

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,36 @@ Size=878,218
Collapsed=0
DockId=0x0000000B,0
[Window][创建3D文本]
Pos=60,60
Size=88,202
Collapsed=0
[Window][创建GUI按钮]
Pos=60,60
Size=93,226
Collapsed=0
[Window][创建3D图片]
Pos=60,60
Size=88,226
Collapsed=0
[Window][创建点光源]
Pos=60,60
Size=109,274
Collapsed=0
[Window][创建GUI标签]
Pos=60,60
Size=93,226
Collapsed=0
[Window][创建聚光灯]
Pos=60,60
Size=89,250
Collapsed=0
[Docking][Data]
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1850,996 Split=X
DockNode ID=0x00000003 Parent=0x08BD597D SizeRef=1524,996 Split=Y

285
main.py
View File

@ -46,6 +46,7 @@ from direct.showbase.DirectObject import DirectObject
from direct.showbase.ShowBaseGlobal import globalClock, aspect2d
import os
import json
import time
import datetime
from direct.actor.Actor import Actor
from PyQt5.sip import wrapinstance
@ -660,6 +661,290 @@ class MyWorld(CoreWorld):
return self.terrain_manager.modifyTerrainHeight(terrain_info, x, y, radius, strength, operation)
return False
# ==================== 信息面板管理功能代理 ====================
def create2DSamplePanel(self):
"""创建2D示例面板"""
try:
from core.InfoPanelManager import createSampleInfoPanel
result = createSampleInfoPanel(self.render)
return result
except Exception as e:
print(f"创建2D示例面板失败: {e}")
return None
def create3DSamplePanel(self):
"""创建3D实例面板"""
try:
if hasattr(self, 'info_panel_manager') and self.info_panel_manager:
# 创建3D信息面板
panel_id = f"3d_sample_{int(time.time())}"
result = self.info_panel_manager.create3DInfoPanel(
panel_id=panel_id,
position=(0, 0, 2),
size=(1.0, 0.6),
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)
)
# 添加示例内容
if result:
sample_data = {
"标题": "3D信息面板",
"状态": "运行中",
"创建时间": time.strftime("%Y-%m-%d %H:%M:%S"),
"位置": f"X:0, Y:0, Z:2"
}
self.info_panel_manager.updatePanelContent(panel_id, content=sample_data)
return result
return None
except Exception as e:
print(f"创建3D示例面板失败: {e}")
return None
def createWebPanel(self, url="https://www.example.com"):
"""创建Web面板"""
try:
if hasattr(self, 'info_panel_manager') and self.info_panel_manager:
panel_id = f"web_panel_{int(time.time())}"
result = self.info_panel_manager.createHTTPInfoPanel(
panel_id=panel_id,
url=url,
position=(0.8, 0.0),
size=(0.35, 0.4),
update_interval=5.0 # 每5秒更新一次
)
return result
return None
except Exception as e:
print(f"创建Web面板失败: {e}")
return None
# ==================== 3D对象和GUI创建功能代理 ====================
def createEmptyObject(self):
"""创建空对象"""
try:
from panda3d.core import NodePath
# 创建一个空节点
empty_node = NodePath("EmptyObject")
empty_node.reparentTo(self.render)
empty_node.setPos(0, 0, 0)
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(empty_node)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print("✓ 空对象创建成功")
return empty_node
except Exception as e:
print(f"✗ 创建空对象失败: {e}")
return None
def create3DText(self, pos=(0, 0, 0), text="3D Text", scale=1.0):
"""创建3D文本"""
try:
from panda3d.core import TextNode, NodePath
# 创建文本节点
text_node = TextNode("3DText")
text_node.setText(text)
text_node.setAlign(TextNode.ACenter)
text_node.setTextColor(1, 1, 1, 1) # 白色
# 创建节点路径并设置位置
text_np = NodePath(text_node)
text_np.reparentTo(self.render)
text_np.setPos(pos)
text_np.setScale(scale)
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(text_np)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print(f"✓ 3D文本创建成功: {text}")
return text_np
except Exception as e:
print(f"✗ 创建3D文本失败: {e}")
return None
def create3DImage(self, pos=(0, 0, 0), image_path="", size=(1, 1)):
"""创建3D图片"""
try:
from panda3d.core import CardMaker, NodePath
if not image_path or not os.path.exists(image_path):
print("✗ 图片文件不存在")
return None
# 创建卡片几何体
card_maker = CardMaker("3DImage")
card_maker.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2)
card = card_maker.generate()
# 创建节点路径
image_np = NodePath(card)
image_np.reparentTo(self.render)
image_np.setPos(pos)
# 加载纹理
from panda3d.core import Texture, Filename
tex = self.loader.loadTexture(Filename.fromOsSpecific(image_path))
if tex:
image_np.setTexture(tex, 1)
else:
print("✗ 加载纹理失败")
image_np.removeNode()
return None
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(image_np)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print(f"✓ 3D图片创建成功: {os.path.basename(image_path)}")
return image_np
except Exception as e:
print(f"✗ 创建3D图片失败: {e}")
return None
def createCube(self, pos=(0, 0, 0), size=1.0):
"""创建立方体"""
try:
from panda3d.core import NodePath
# 创建立方体模型
cube = self.loader.loadModel("models/environment")
if not cube:
# 如果没有默认模型,创建一个简单的立方体
from panda3d.core import CardMaker
card_maker = CardMaker("Cube")
card_maker.setFrame(-size/2, size/2, -size/2, size/2)
cube = NodePath(card_maker.generate())
cube.reparentTo(self.render)
cube.setPos(pos)
cube.setScale(size)
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(cube)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print("✓ 立方体创建成功")
return cube
except Exception as e:
print(f"✗ 创建立方体失败: {e}")
return None
def createSphere(self, pos=(0, 0, 0), radius=1.0):
"""创建球体"""
try:
from panda3d.core import NodePath
# 创建球体模型
sphere = self.loader.loadModel("models/environment")
if not sphere:
# 如果没有默认模型,创建一个简单的球体
from panda3d.core import CardMaker
card_maker = CardMaker("Sphere")
card_maker.setFrame(-radius, radius, -radius, radius)
sphere = NodePath(card_maker.generate())
sphere.reparentTo(self.render)
sphere.setPos(pos)
sphere.setScale(radius)
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(sphere)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print("✓ 球体创建成功")
return sphere
except Exception as e:
print(f"✗ 创建球体失败: {e}")
return None
def createCylinder(self, pos=(0, 0, 0), radius=1.0, height=2.0):
"""创建圆柱体"""
try:
from panda3d.core import NodePath
# 创建圆柱体模型
cylinder = self.loader.loadModel("models/environment")
if not cylinder:
# 如果没有默认模型,创建一个简单的圆柱体
from panda3d.core import CardMaker
card_maker = CardMaker("Cylinder")
card_maker.setFrame(-radius, radius, -height/2, height/2)
cylinder = NodePath(card_maker.generate())
cylinder.reparentTo(self.render)
cylinder.setPos(pos)
cylinder.setScale(radius, radius, height)
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(cylinder)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print("✓ 圆柱体创建成功")
return cylinder
except Exception as e:
print(f"✗ 创建圆柱体失败: {e}")
return None
def createPlane(self, pos=(0, 0, 0), size=(1, 1)):
"""创建平面"""
try:
from panda3d.core import CardMaker, NodePath
# 创建平面
card_maker = CardMaker("Plane")
card_maker.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2)
plane = NodePath(card_maker.generate())
plane.reparentTo(self.render)
plane.setPos(pos)
# 添加到场景管理器
if hasattr(self, 'scene_manager') and self.scene_manager:
self.scene_manager.models.append(plane)
# 更新场景树
if hasattr(self, 'updateSceneTree'):
self.updateSceneTree()
print("✓ 平面创建成功")
return plane
except Exception as e:
print(f"✗ 创建平面失败: {e}")
return None
# 添加碰撞管理相关的代理方法
def enableModelCollisionDetection(self, enable=True, frequency=0.1, threshold=0.5):
"""启用模型间碰撞检测"""

File diff suppressed because it is too large Load Diff

View File

@ -1906,15 +1906,24 @@ class ConsoleRedirect:
def __init__(self, console_widget, stream_type):
self.console_widget = console_widget
self.stream_type = stream_type
# 保存原始输出流的引用
if stream_type == "STDOUT":
self.original_stream = sys.stdout
else:
self.original_stream = sys.stderr
def write(self, text):
"""重定向写入"""
"""重定向写入 - 同时输出到GUI控制台和原始终端"""
# 先输出到原始终端
self.original_stream.write(text)
# 然后输出到GUI控制台仅非空行
if text.strip(): # 忽略空行
self.console_widget.addMessage(text.strip(), self.stream_type)
def flush(self):
"""刷新缓冲区"""
pass
"""刷新缓冲区 - 同时刷新原始流"""
self.original_stream.flush()
class StyledMessageBox:
"""统一样式的消息框辅助类"""