1
0
forked from Rowland/EG

脚本打包加载

This commit is contained in:
Hector 2025-09-29 09:16:37 +08:00
parent 9c4116319b
commit c252a8cba7
8 changed files with 437 additions and 186 deletions

View File

@ -351,7 +351,11 @@ class RenderPipeline(RPObject):
continue
material = state.get_attrib(MaterialAttrib).get_material()
shading_model = material.emission.x
if material.emission is not None:
shading_model = material.emission.x
else:
shading_model = 0.0
# SHADING_MODEL_TRANSPARENT
if shading_model == 3:

View File

@ -2,6 +2,7 @@
from xml.sax.handler import property_encoding
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox
from direct.gui.DirectGui import DirectFrame, DirectLabel
from direct.showbase.ShowBaseGlobal import aspect2d
from panda3d.core import TextNode, Vec4, NodePath
@ -189,7 +190,7 @@ class InfoPanelManager(DirectObject):
# 如果有背景图片,保存背景图片路径
if bg_image:
panel_node.setTag("bg_image_path", bg_image)
panel_node.setTag("image_path", bg_image)
if not visible:
@ -197,6 +198,8 @@ class InfoPanelManager(DirectObject):
# 将面板添加到场景树
#self._addPanelToSceneTree(panel_node, panel_id)
if hasattr(self.world, 'gui_elements'):
self.world.gui_elements.append(panel_node)
return panel_node
@ -820,6 +823,8 @@ class InfoPanelManager(DirectObject):
# 将面板添加到场景树
#self._addPanelToSceneTree(panel_node, panel_id)
if hasattr(self.world, 'gui_elements'):
self.world.gui_elements.append(panel_node)
return panel_node
@ -1266,6 +1271,101 @@ class InfoPanelManager(DirectObject):
traceback.print_exc()
return None
def onCreateSampleInfoPanel(self):
"""创建示例天气信息面板(模拟数据)"""
try:
# 获取中文字体
from panda3d.core import TextNode
font = self.world.getChineseFont() if self.world.getChineseFont() else None
# 使用唯一的面板ID
import time
unique_id = f"weather_info_{int(time.time())}"
# 创建示例面板
weather_panel = self.createInfoPanel(
panel_id=unique_id, # 使用唯一ID
position=(1.32, 0.68),
size=(1, 0.6),
bg_color=(0.15, 0.25, 0.35, 0), # 蓝色背景
border_color=(0.3, 0.5, 0.7, 0), # 蓝色边框
title_color=(0.7, 0.9, 1.0, 1.0), # 浅蓝色标题
content_color=(0.95, 0.95, 0.95, 1.0),
font=font,
bg_image="/home/tiger/图片/内部信息框2@2x.png"
)
# 更新面板标题
self.updatePanelContent(unique_id, title="北京天气")
self._addPanelToSceneTree(weather_panel, unique_id)
# 立即显示加载中信息
self.updatePanelContent(unique_id, content="正在获取天气数据...")
self.registerDataSource(unique_id, self.getRealWeatherData, update_interval=5.0)
print("✓ 示例天气信息面板已创建")
except Exception as e:
print(f"✗ 创建示例天气信息面板失败: {e}")
import traceback
traceback.print_exc()
QMessageBox.critical(self, "错误", f"创建示例天气信息面板时出错: {str(e)}")
def getRealWeatherData(self):
"""获取真实天气数据"""
try:
import requests
import json
from datetime import datetime
# 请求天气数据
url = "https://wttr.in/Beijing?format=j1"
response = requests.get(url, timeout=10)
response.raise_for_status()
# 解析JSON数据
weather_data = response.json()
# 提取当前天气信息
current_condition = weather_data['current_condition'][0]
weather_desc = current_condition['weatherDesc'][0]['value']
temp_c = current_condition['temp_C']
feels_like = current_condition['FeelsLikeC']
humidity = current_condition['humidity']
pressure = current_condition['pressure']
visibility = current_condition['visibility']
wind_speed = current_condition['windspeedKmph']
wind_dir = current_condition['winddir16Point']
# 提取空气质量(如果可用)
air_quality = "N/A"
if 'air_quality' in weather_data and weather_data['air_quality']:
if 'us-epa-index' in current_condition:
air_quality_index = current_condition['air_quality_index']
air_quality = f"指数: {air_quality_index}"
# 获取更新时间
update_time = datetime.now().strftime("%Y-%m-%d %H:%M")
# 格式化显示内容
content = f"天气状况: {weather_desc}\n温度: {temp_c}°C (体感 {feels_like}°C)\n湿度: {humidity}%\n气压: {pressure} hPa\n能见度: {visibility} km\n风速: {wind_speed} km/h ({wind_dir})\n空气质量: {air_quality}\n更新时间: {update_time}"
return content
except requests.exceptions.Timeout:
return "错误: 获取天气数据超时"
except requests.exceptions.ConnectionError:
return "错误: 网络连接失败"
except requests.exceptions.HTTPError as e:
return f"HTTP错误: {e}"
except json.JSONDecodeError:
return "错误: 无法解析天气数据"
except KeyError as e:
return f"错误: 天气数据格式不正确 (缺少字段: {e})"
except Exception as e:
return f"获取天气数据失败: {str(e)}"
# 示例数据源函数
def getRealtimeData():

View File

@ -544,8 +544,8 @@ class GUIManager:
if isinstance(size, (list, tuple)) and len(size) >= 2:
# 分别处理宽度和高度的缩放
width_scale = size[0] * 0.05
height_scale = size[2] * 0.05
width_scale = size[0] * 0.25
height_scale = size[2] * 0.25
else:
# 如果只提供了一个缩放值,则使用相同值
width_scale = size * 0.1 if isinstance(size, (int, float)) else 0.2

View File

@ -100,7 +100,7 @@ class MyWorld(CoreWorld):
self.vr_manager = VRManager(self)
self.vr_input_handler = VRInputHandler(self, self.vr_manager)
self.alvr_streamer = ALVRStreamer(self, self.vr_manager)
# 启动脚本系统
self.script_manager.start_system()

View File

@ -399,6 +399,12 @@ class ProjectManager:
self._saveGUIElementsToJSON(build_dir, project_path)
self._copyScriptsToBuild(build_dir, project_path)
self._copyScriptSystemToBuild(build_dir)
self._copyInfoPanelSystemToBuild(build_dir)
source_render_pipeline = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),"RenderPipelineFile")
dest_render_pipeline = os.path.join(build_dir,"RenderPipelineFile")
@ -424,6 +430,89 @@ class ProjectManager:
#创建requirements.txt文件
self._createRequirementsFile(build_dir)
def _copyScriptsToBuild(self, build_dir, project_path):
"""复制脚本文件到构建目录的scripts文件夹"""
try:
# 创建目标scripts目录
scripts_dest = os.path.join(build_dir, "scripts")
# 正确的源scripts目录路径
scripts_src = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scripts")
# 如果上面的路径不存在尝试项目路径下的scripts目录
if not os.path.exists(scripts_src):
scripts_src = os.path.join(project_path, "scripts")
if os.path.exists(scripts_src):
# 直接复制整个scripts目录
if os.path.exists(scripts_dest):
shutil.rmtree(scripts_dest)
shutil.copytree(
scripts_src,
scripts_dest,
ignore=shutil.ignore_patterns('__pycache__', '*.pyc', '.git', '.vscode', '*.log')
)
print("✓ Scripts目录已复制到build/scripts")
else:
# 创建空的scripts目录
if not os.path.exists(scripts_dest):
os.makedirs(scripts_dest)
print("⚠️ 项目中没有scripts目录")
except Exception as e:
print(f"⚠️ 复制脚本文件时出错: {str(e)}")
def _copyScriptSystemToBuild(self, build_dir):
"""复制core/script_system.py文件到构建目录"""
try:
# 源文件路径
source_script_system = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "core",
"script_system.py")
# 目标目录
core_dest = os.path.join(build_dir, "core")
# 如果源文件存在
if os.path.exists(source_script_system):
# 确保目标目录存在
if not os.path.exists(core_dest):
os.makedirs(core_dest)
# 复制文件
shutil.copy2(source_script_system, os.path.join(core_dest, "script_system.py"))
print("✓ core/script_system.py文件已复制到build目录")
else:
print("⚠️ core/script_system.py文件未找到")
except Exception as e:
print(f"⚠️ 复制core/script_system.py文件时出错: {str(e)}")
def _copyInfoPanelSystemToBuild(self, build_dir):
"""复制core/script_system.py文件到构建目录"""
try:
# 源文件路径
source_InfoPanel_system = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "core",
"InfoPanelManager.py")
# 目标目录
core_dest = os.path.join(build_dir, "core")
# 如果源文件存在
if os.path.exists(source_InfoPanel_system):
# 确保目标目录存在
if not os.path.exists(core_dest):
os.makedirs(core_dest)
# 复制文件
shutil.copy2(source_InfoPanel_system, os.path.join(core_dest, "InfoPanelManager.py"))
print("✓ core/InfoPanelManager.py文件已复制到build目录")
else:
print("⚠️ core/InfoPanelManager.py文件未找到")
except Exception as e:
print(f"⚠️ 复制core/InfoPanelManager.py文件时出错: {str(e)}")
def _saveGUIElementsToJSON(self, build_dir, project_path):
"""保存GUI元素到JSON文件内容与_collectGUIElementInfo保持一致"""
try:
@ -1035,10 +1124,31 @@ setup(
'direct.task',
'direct.actor',
'direct.interval',
'direct.stdpy.file',
'direct.stdpy.pickle',
'panda3d.core',
'panda3d.direct',
'rpcore',
'rpcore.util.movement_controller',
'rpcore.native',
'rpcore.render_pipeline',
'rplibs',
'rpplugins',
'rpplugins.scattering',
'rpplugins.pssm',
'rpplugins.godrays',
'json',
'os',
'sys',
'six',
'collections',
'collections.abs',
'weakref',
'copy',
'itertools',
'importlib',
'importlib.util',
'importlib.machinery',
],
}},

View File

@ -902,6 +902,7 @@ class SceneManager:
"tags": {},
"parent_name":None,
"video_path":gui_node.getTag("video_path") if gui_node.hasTag("video_path") else None,
"panel_id":gui_node.getTag("panel_id") if gui_node.hasTag("panel_id") else None,
}
parent = gui_node.getParent()
@ -911,13 +912,13 @@ class SceneManager:
gui_info["parent_name"] = parent_name
# 收集所有标签仅对NodePath类型的对象
# if hasattr(gui_node, 'getTagNames'):
# for tag in gui_node.getTagNames():
# gui_info["tags"][tag] = gui_node.getTag(tag)
# elif hasattr(gui_node, 'getTags'): # 对于DirectGUI对象
# # DirectGUI对象使用不同的方法存储标签
# if hasattr(gui_node, '_tags'):
# gui_info["tags"] = gui_node._tags.copy()
if hasattr(gui_node, 'getTagNames'):
for tag in gui_node.getTagNames():
gui_info["tags"][tag] = gui_node.getTag(tag)
elif hasattr(gui_node, 'getTags'): # 对于DirectGUI对象
# DirectGUI对象使用不同的方法存储标签
if hasattr(gui_node, '_tags'):
gui_info["tags"] = gui_node._tags.copy()
# 根据类型收集特定信息
if gui_type == "button":
@ -965,39 +966,37 @@ class SceneManager:
gui_info["panel_id"] = gui_node.getTag("panel_id")
# 收集背景图片信息
if hasattr(gui_node, 'hasTag') and gui_node.hasTag("bg_image_path"):
gui_info["bg_image_path"] = gui_node.getTag("bg_image_path")
if hasattr(gui_node, 'hasTag') and gui_node.hasTag("image_path"):
gui_info["image_path"] = gui_node.getTag("image_path")
# 如果是信息面板,收集面板数据
if hasattr(gui_node, 'hasTag') and gui_node.hasTag("info_panel_data"):
gui_info["panel_data"] = gui_node.getTag("info_panel_data")
# 收集挂载的脚本信息
if hasattr(self.world, 'script_manager') and self.world.script_manager:
try:
script_manager = self.world.script_manager
scripts = script_manager.get_scripts_on_object(gui_node)
scripts = script_manager.get_scripts_on_object(gui_node) # 修复:使用 gui_node 而不是 node
if scripts:
gui_info["scripts"] = []
for script_component in scripts:
try:
script_name = script_manager.script_name
#获取脚本路径
script_name = script_component.script_name
# 获取脚本路径
script_class = script_component.script_instance.__class__
script_file = self._get_script_file_path(script_class,script_name)
#只有当脚本文件存在时才保存
script_file = self._get_script_file_path(script_class, script_name)
# 只有当脚本文件存在时才保存
if script_file and os.path.exists(script_file):
gui_info["scirpts"].append({
"name":script_name,
"file":script_file
gui_info["scripts"].append({
"name": script_name,
"file": script_file
})
print(f"收集脚本信息{script_name}from {script_file}")
print(f"收集脚本信息: {script_name} from {script_file}")
else:
print(f"警告: 脚本文件不存在: {script_file}")
except Exception as e:
print(f"收集单个脚本信息失败{script_name},错误{e}")
print(f"收集单个脚本信息失败 {script_name}, 错误: {e}")
continue
except Exception as e:
print(f"收集脚本信息失败{e}")
print(f"收集脚本信息失败: {e}")
print(f"成功收集GUI元素信息: {gui_info}")
return gui_info
@ -2075,7 +2074,8 @@ class SceneManager:
return task.done
taskMgr.doMethodLater(0.1, load_2d_video_file_task, 'load2DVideoFileTask')
elif gui_type == "info_panel":
new_element = self.world.info_panel_manager.onCreateSampleInfoPanel()
# 如果创建成功,设置属性
if new_element:
# 如果返回的是列表(多选创建),取第一个

View File

@ -12,6 +12,7 @@ import json
from direct.actor.Actor import Actor
from panda3d.core import TextNode, CardMaker, TextureStage, NodePath, Texture, TransparencyAttrib
from core.InfoPanelManager import InfoPanelManager
# 获取渲染管线路径
# 在文件开头添加sys导入如果还没有的话
import sys
@ -33,52 +34,88 @@ os.chdir(project_root)
render_pipeline_path = 'RenderPipelineFile'
sys.path.insert(0, render_pipeline_path)
# 修改管线路径查找
# 改进路径设置逻辑
pipeline_path = os.path.join(project_root, "RenderPipelineFile")
if not os.path.isfile(os.path.join(pipeline_path, "setup.py")):
pipeline_path = os.path.join(project_root, "RenderPipelineFile")
if os.path.exists(pipeline_path) and pipeline_path not in sys.path:
sys.path.insert(0, pipeline_path)
# 同时添加子目录以确保所有模块都能正确导入
for root, dirs, files in os.walk(pipeline_path):
if root not in sys.path:
sys.path.insert(0, root)
import math
from random import random, randint, seed
from panda3d.core import Vec3, load_prc_file_data, Filename
from direct.showbase.ShowBase import ShowBase
from direct.task.TaskManagerGlobal import taskMgr
# os.chdir(os.path.dirname(os.path.realpath(__file__)))
from core.script_system import ScriptManager
class MainApp(ShowBase):
def __init__(self):
# 在调用父类构造函数前确保必要的属性存在
if not hasattr(self, 'appRunner'):
self.appRunner = None
load_prc_file_data("", """
win-size 1380 750
window-title Render
""")
pipeline_path = "../../"
# 简化 sys.path 设置逻辑
pipeline_path = os.path.join(project_root, "RenderPipelineFile")
if os.path.exists(pipeline_path):
if pipeline_path not in sys.path:
sys.path.insert(0, pipeline_path)
else:
print(f"错误: 找不到渲染管线目录: {pipeline_path}")
return
if not os.path.isfile(os.path.join(pipeline_path, "setup.py")):
pipeline_path = "../../RenderPipeline"
try:
from rpcore import RenderPipeline
self.render_pipeline = RenderPipeline()
self.render_pipeline.create(self)
#self.render_pipeline.pre_show_base_init()
#ShowBase.__init__(self)
sys.path.insert(0, pipeline_path)
from rpcore import RenderPipeline, SpotLight
self.render_pipeline = RenderPipeline()
self.render_pipeline.create(self)
except ImportError as e:
print(f"导入RenderPipeline模块失败: {e}")
import traceback
traceback.print_exc()
ShowBase.__init__(self)
self.render_pipeline = None
return
self.script_manager = ScriptManager(self)
self.script_manager.start_system()
# 加载所有脚本
self.script_manager.load_all_scripts_from_directory()
self.info_panel_manager = InfoPanelManager(self)
try:
# 再导入controller模块
from rpcore.util.movement_controller import MovementController
self.controller = MovementController(self)
self.controller.set_initial_position(
Vec3(0, -50, 20), Vec3(0, 0, 0))
self.controller.setup()
except ImportError as e:
print(f"导入MovementController失败: {e}")
self.controller = None
from rpcore.util.movement_controller import MovementController
self.render_pipeline.daytime_mgr.time = "12:00"
self._loadFont()
self.loadFullScene()
self.loadGUIFromJSON()
self.controller = MovementController(self)
self.controller.set_initial_position(
Vec3(0, -50, 20), Vec3(0, 0, 0))
self.controller.setup()
base.accept("l", self.tour)
if hasattr(self, 'accept'):
base.accept("l", self.tour)
def _loadFont(self):
"""加载中文字体"""
@ -97,15 +134,20 @@ class MainApp(ShowBase):
"""获取中文字体"""
return self.chinese_font
def getResourcePath(self,relative_path):
if getattr(sys,'frozen',False):
base_path = os.path.dirname(sys.executable)
else:
base_path = os.path.dirname(os.path.abspath(__file__))
return os.path.join(base_path,relative_path)
def loadFullScene(self):
"""加载完整场景,包括所有元素"""
if not hasattr(self, 'loader') or not hasattr(self, 'render'):
print("错误: Panda3D核心组件未正确初始化")
return
try:
import sys
# 获取场景文件路径
if getattr(sys, 'frozen', False):
scene_file = os.path.join(os.path.dirname(sys.executable), "scene.bam")
else:
scene_file = "scene.bam"
scene_file = self.getResourcePath("scene.bam")
if os.path.exists(scene_file):
# 使用readBamFile加载完整场景
@ -118,6 +160,9 @@ class MainApp(ShowBase):
self.render_pipeline.prepare_scene(scene)
print("✓ 完整场景加载成功")
# 检测并播放模型动画
#self._processModelAnimations(scene)
# 处理场景中的各种元素
self.processSceneElements(scene)
else:
@ -129,6 +174,58 @@ class MainApp(ShowBase):
import traceback
traceback.print_exc()
def _processModelAnimations(self, node_path):
"""处理节点中的动画模型"""
try:
# 查找场景中所有可能的动画模型
char_nodes = node_path.findAllMatches("**/+Character")
for char_node in char_nodes:
try:
# 获取父节点(通常是模型根节点)
model_root = char_node.getParent()
model_name = model_root.getName()
print(f"检测到可能的动画模型: {model_name}")
# 尝试创建Actor
actor = Actor(model_root)
actor.reparentTo(self.render)
actor.setPos(node_path.getPos())
actor.setHpr(node_path.getHpr())
actor.setScale(node_path.getScale())
# 获取动画名称
anim_names = actor.getAnimNames()
if anim_names:
print(f"✓ 成功创建动画模型: {model_name}")
print(f" 可用动画: {anim_names}")
# 循环播放所有动画
for anim_name in anim_names:
print(f" 循环播放动画: {anim_name}")
actor.loop(anim_name)
break # 只播放第一个动画,避免同时播放多个动画
# 替换原始模型
model_root.detachNode()
else:
# 没有动画,使用原始模型
print(f"模型 {model_name} 不包含动画")
actor.detachNode() # 移除创建的Actor
except Exception as e:
print(f"处理动画模型 {char_node.getName()} 时出错: {str(e)}")
except Exception as e:
print(f"处理模型动画时出错: {str(e)}")
import traceback
traceback.print_exc()
def processSceneElements(self, scene):
"""处理场景中的各种元素"""
try:
@ -137,6 +234,14 @@ class MainApp(ShowBase):
def processNode(nodePath,depth=0):
loaded_nodes[nodePath.getName()] = nodePath
if nodePath.hasTag("scripts_info"):
try:
import json
scripts_info = json.loads(nodePath.getTag("scripts_info"))
self.processScripts(nodePath,scripts_info)
except Exception as e:
print(f"处理节点 {nodePath.getName()} 的脚本时出错: {str(e)}")
if nodePath.hasTag("light_type"):
light_type = nodePath.getTag("light_type")
@ -238,20 +343,16 @@ class MainApp(ShowBase):
self.controller.play_motion_path(mopath, 3.0)
def loadGUIFromJSON(self):
import sys
# 获取GUI元素JSON文件路径
if getattr(sys, 'frozen', False):
gui_json_path = os.path.join(os.path.dirname(sys.executable), "gui", "gui_elements.json")
else:
gui_json_path = "gui/gui_elements.json"
try:
gui_json_path = self.getResourcePath("gui/gui_elements.json")
if os.path.exists(gui_json_path):
with open(gui_json_path, 'r', encoding='utf-8') as f:
content = f.read().strip()
if content:
gui_data = json.loads(content)
self.createGUIElement(gui_data)
else:
print("GUI配置文件为空 ")
except Exception as e:
print(f"加载GUI元素时出错: {str(e)}")
import traceback
@ -354,6 +455,12 @@ class MainApp(ShowBase):
video_path=video_path,
size=absolute_scale
)
elif gui_type == "info_panel":
new_element = self.info_panel_manager.onCreateSampleInfoPanel()
if "scripts" in gui_info and new_element:
self.processScripts(new_element,gui_info["scripts"])
except Exception as e:
print(f"重建GUI元素失败 {name}: {e}")
import traceback
@ -504,6 +611,12 @@ class MainApp(ShowBase):
traceback.print_exc()
def createGUI2DImage(self, pos=(0, 0, 0), image_path=None, size=0.2):
# 添加属性检查
if not hasattr(self, 'aspect2d'):
print("错误: aspect2d未初始化")
return None
if image_path and not os.path.isabs(image_path):
image_path = self.getResourcePath(image_path)
# 处理非均匀缩放
if isinstance(size, (list, tuple)) and len(size) >= 2:
# 分别处理宽度和高度的缩放
@ -542,8 +655,12 @@ class MainApp(ShowBase):
print(f"无法加载图片: {image_path}")
except Exception as e:
print(f"加载图片时出错: {e}")
return image_node
def createGUI2DVideoScreen(self, pos=(0, 0, 0), size=0.2, video_path=None):
import os
if video_path and not os.path.isabs(video_path):
image_path = self.getResourcePath(video_path)
from direct.gui.DirectGui import DirectFrame
from panda3d.core import TransparencyAttrib, Texture, TextureStage
import os
@ -635,16 +752,53 @@ class MainApp(ShowBase):
import traceback
traceback.print_exc()
def processScripts(self, element, script_info_list):
"""处理元素上挂载的脚本 - 使用新的脚本系统"""
try:
print(f"正在为元素 {element.getName()} 挂载脚本")
print(f"可用脚本列表: {self.script_manager.get_available_scripts()}")
for script_info in script_info_list:
script_name = script_info["name"]
script_file = script_info.get("file", "")
# 从文件路径中提取脚本类名
if script_file:
# 获取脚本文件名(不含路径和扩展名)
script_filename = os.path.basename(script_file)
script_class_name = os.path.splitext(script_filename)[0]
print(f"尝试挂载脚本: {script_class_name} (来自文件: {script_file})")
# 使用脚本管理器为元素添加脚本
script_component = self.script_manager.add_script_to_object(element, script_class_name)
if script_component:
print(f"✓ 脚本 {script_class_name} 已挂载到元素 {element.getName()}")
else:
print(f"⚠️ 脚本 {script_class_name} 挂载失败")
# 列出可用脚本帮助调试
available_scripts = self.script_manager.get_available_scripts()
print(f"当前可用脚本: {available_scripts}")
else:
print(f"⚠️ 脚本信息不完整: {script_name}")
except Exception as e:
print(f"挂载脚本到元素 {element.getName()} 失败: {str(e)}")
import traceback
traceback.print_exc()
# 在 main.py 的最后部分,修改为:
if __name__ == "__main__":
try:
app = MainApp()
app.run()
if hasattr(app, 'run'):
app.run()
else:
print("应用程序初始化失败")
except Exception as e:
print(f"应用程序启动失败: {str(e)}")
import traceback
traceback.print_exc()
# 在Windows上可以使用下面的代码显示错误对话框
# input("按回车键退出...")

View File

@ -734,7 +734,7 @@ class MainWindow(QMainWindow):
self.infoPanelMenu = menubar.addMenu('信息面板')
# 创建示例面板动作
self.createSamplePanelAction = self.infoPanelMenu.addAction('创建示例面板')
self.createSamplePanelAction.triggered.connect(self.onCreateSampleInfoPanel)
self.createSamplePanelAction.triggered.connect(self.world.info_panel_manager.onCreateSampleInfoPanel)
# 添加更多面板创建选项
# self.createSystemStatusPanelAction = self.infoPanelMenu.addAction('创建系统状态面板')
# self.createSystemStatusPanelAction.triggered.connect(self.onCreateSystemStatusPanel)
@ -2493,113 +2493,7 @@ class MainWindow(QMainWindow):
traceback.print_exc()
return None
def onCreateSampleInfoPanel(self):
"""创建示例天气信息面板(模拟数据)"""
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(aspect2d)
# 使用唯一的面板ID
import time
unique_id = f"weather_info_{int(time.time())}"
# 创建示例面板
weather_panel = info_manager.createInfoPanel(
panel_id=unique_id, # 使用唯一ID
position=(1.32, 0.68),
size=(1, 0.6),
bg_color=(0.15, 0.25, 0.35, 0), # 蓝色背景
border_color=(0.3, 0.5, 0.7, 0), # 蓝色边框
title_color=(0.7, 0.9, 1.0, 1.0), # 浅蓝色标题
content_color=(0.95, 0.95, 0.95, 1.0),
font=font,
bg_image="/home/tiger/图片/内部信息框2@2x.png"
)
# 更新面板标题
info_manager.updatePanelContent(unique_id, title="北京天气")
# 添加到场景树
self.addInfoPanelToTree(weather_panel, "天气信息面板")
# 立即显示加载中信息
info_manager.updatePanelContent(unique_id, content="正在获取天气数据...")
info_manager.registerDataSource(unique_id, self.getRealWeatherData, update_interval=5.0)
# # 立即显示示例数据
# sample_data = self.getSampleWeatherData()
# info_manager.updatePanelContent(unique_id, content=sample_data)
#
# # 注册数据源,定期更新示例数据
# info_manager.registerDataSource(unique_id, self.getSampleWeatherData, update_interval=2.0)
print("✓ 示例天气信息面板已创建")
except Exception as e:
print(f"✗ 创建示例天气信息面板失败: {e}")
import traceback
traceback.print_exc()
QMessageBox.critical(self, "错误", f"创建示例天气信息面板时出错: {str(e)}")
def getRealWeatherData(self):
"""获取真实天气数据"""
try:
import requests
import json
from datetime import datetime
# 请求天气数据
url = "https://wttr.in/Beijing?format=j1"
response = requests.get(url, timeout=10)
response.raise_for_status()
# 解析JSON数据
weather_data = response.json()
# 提取当前天气信息
current_condition = weather_data['current_condition'][0]
weather_desc = current_condition['weatherDesc'][0]['value']
temp_c = current_condition['temp_C']
feels_like = current_condition['FeelsLikeC']
humidity = current_condition['humidity']
pressure = current_condition['pressure']
visibility = current_condition['visibility']
wind_speed = current_condition['windspeedKmph']
wind_dir = current_condition['winddir16Point']
# 提取空气质量(如果可用)
air_quality = "N/A"
if 'air_quality' in weather_data and weather_data['air_quality']:
if 'us-epa-index' in current_condition:
air_quality_index = current_condition['air_quality_index']
air_quality = f"指数: {air_quality_index}"
# 获取更新时间
update_time = datetime.now().strftime("%Y-%m-%d %H:%M")
# 格式化显示内容
content = f"天气状况: {weather_desc}\n温度: {temp_c}°C (体感 {feels_like}°C)\n湿度: {humidity}%\n气压: {pressure} hPa\n能见度: {visibility} km\n风速: {wind_speed} km/h ({wind_dir})\n空气质量: {air_quality}\n更新时间: {update_time}"
return content
except requests.exceptions.Timeout:
return "错误: 获取天气数据超时"
except requests.exceptions.ConnectionError:
return "错误: 网络连接失败"
except requests.exceptions.HTTPError as e:
return f"HTTP错误: {e}"
except json.JSONDecodeError:
return "错误: 无法解析天气数据"
except KeyError as e:
return f"错误: 天气数据格式不正确 (缺少字段: {e})"
except Exception as e:
return f"获取天气数据失败: {str(e)}"
def getSampleWeatherData(self):
"""获取示例天气数据"""
@ -2972,17 +2866,6 @@ class MainWindow(QMainWindow):
except Exception as e:
return f"获取场景信息失败: {str(e)}"
def onCreateAllInfoPanels(self):
"""创建所有信息面板"""
try:
self.onCreateSampleInfoPanel()
self.onCreateSystemStatusPanel()
self.onCreateSensorDataPanel()
self.onCreateSceneInfoPanel()
QMessageBox.information(self, "成功",
"所有信息面板已创建完成!\n快捷键:\nF1 - 示例面板\nF2 - 系统状态面板\nF3 - 传感器数据面板\nF4 - 场景信息面板")
except Exception as e:
QMessageBox.critical(self, "错误", f"创建信息面板时出错: {str(e)}")
# ==================== 脚本管理事件处理 ====================