1
0
forked from Rowland/EG
EG/core/maintenance_gui.py

1094 lines
42 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
维修系统场景GUI界面
包括步骤显示、工具选择按钮和警告提示
"""
from direct.gui.DirectGui import *
from direct.gui import DirectGuiGlobals as DGG
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from panda3d.core import TextNode, Vec3, Vec4
# 引入全局变量
import builtins
class MaintenanceGUI(DirectObject):
"""维修系统GUI管理器"""
def __init__(self, world):
DirectObject.__init__(self)
self.world = world
self.chinese_font = None
if hasattr(self.world, 'getChineseFont'):
self.chinese_font = self.world.getChineseFont()
# 获取GUI父节点引用
self.aspect2d = None
print(f"🔍 初始化维修GUIworld类型: {type(world).__name__}")
print(f"🔍 world是否有aspect2d: {hasattr(world, 'aspect2d')}")
if hasattr(world, 'aspect2d'):
self.aspect2d = world.aspect2d
print("✅ 从world获取aspect2d成功")
else:
print("❌ world没有aspect2d属性")
# GUI元素
self.step_text = None # 步骤显示文本
self.current_tool_text = None # 当前工具显示文本
self.warning_text = None # 警告文本
self.tool_buttons = [] # 工具按钮列表
self.stop_button = None # 停止按钮
# 状态
self.current_tool = None # 当前选择的工具,初始为无
self.available_tools = [] # 可用工具列表
self.current_step_info = "" # 当前步骤信息
self.mode = "training" # 模式training 或 exam
# 警告显示任务
self.warning_task = None
print("✅ 维修系统GUI初始化完成")
# 添加测试快捷键
self.accept("t", self.test_tool_selection) # 按T键测试工具选择
self.accept("1", lambda: self.test_specific_button(0)) # 按1键测试第一个按钮
self.accept("2", lambda: self.test_specific_button(1)) # 按2键测试第二个按钮
self.accept("3", lambda: self.test_specific_button(2)) # 按3键测试第三个按钮
self.accept("p", self.print_button_positions) # 按P键打印按钮位置
# 添加鼠标监控任务
self.mouse_monitor_task = None
def setup_gui(self, tools_list, mode="training"):
"""设置GUI界面"""
try:
print(f"🎨 设置维修系统GUI工具列表: {tools_list}, 模式: {mode}")
self.available_tools = tools_list if tools_list else [""]
self.mode = mode
# 重新尝试获取aspect2d引用
self.get_aspect2d_reference()
# 清理现有GUI
self.cleanup_gui()
# 创建步骤显示文本
self.create_step_text()
# 创建工具选择按钮(训练和考核模式都需要)
self.create_tool_buttons()
self.create_current_tool_text()
# 创建停止按钮(训练和考核模式都需要)
# self.create_stop_button()
# 创建警告文本(仅训练模式需要)
if mode == "training":
self.create_warning_text()
print("✅ 维修系统GUI设置完成")
# 启动鼠标监控任务(训练和考核模式都需要)
self.start_mouse_monitor()
except Exception as e:
print(f"❌ 设置维修系统GUI失败: {e}")
import traceback
traceback.print_exc()
def start_mouse_monitor(self):
"""启动鼠标监控任务"""
try:
# 停止可能存在的旧任务
if self.mouse_monitor_task:
taskMgr.remove(self.mouse_monitor_task)
# 启动新的监控任务
self.mouse_monitor_task = taskMgr.add(self.monitor_mouse_clicks, "mouse_monitor")
print("✅ 鼠标监控任务已启动")
print(f"✅ 任务管理器中的任务: {[task.getName() for task in taskMgr.getAllTasks()]}")
# 测试一下任务是否能正常运行
self.test_mouse_monitor()
except Exception as e:
print(f"❌ 启动鼠标监控失败: {e}")
import traceback
traceback.print_exc()
def test_mouse_monitor(self):
"""测试鼠标监控功能"""
try:
print("🧪 测试鼠标监控功能...")
# 尝试直接调用监控函数
result = self.monitor_mouse_clicks(None)
print(f"🧪 监控函数调用结果: {result}")
except Exception as e:
print(f"❌ 测试鼠标监控失败: {e}")
import traceback
traceback.print_exc()
def monitor_mouse_clicks(self, task):
"""监控鼠标点击并手动检测按钮"""
try:
# 添加计数器来减少日志输出
if not hasattr(self, '_monitor_counter'):
self._monitor_counter = 0
self._monitor_counter += 1
# 每100帧输出一次状态
if self._monitor_counter % 100 == 1:
print(f"🔄 鼠标监控运行中... (帧 {self._monitor_counter})")
# 检查鼠标状态
mouse_watcher = None
if hasattr(self.world, 'mouseWatcherNode'):
mouse_watcher = self.world.mouseWatcherNode
if self._monitor_counter % 100 == 1:
print(f"✅ 从world获取mouseWatcherNode: {mouse_watcher}")
else:
# 使用全局base对象
try:
import builtins
if hasattr(builtins, 'base') and hasattr(builtins.base, 'mouseWatcherNode'):
mouse_watcher = builtins.base.mouseWatcherNode
if self._monitor_counter % 100 == 1:
print(f"✅ 从base获取mouseWatcherNode: {mouse_watcher}")
except:
if self._monitor_counter % 100 == 1:
print("❌ 无法获取mouseWatcherNode")
if mouse_watcher:
has_mouse = mouse_watcher.hasMouse()
if has_mouse:
mouse_pos = mouse_watcher.getMouse()
# 检查左键状态
mouse_x = mouse_pos.getX()
mouse_y = mouse_pos.getY()
# 检查左键是否被按下
is_button_down = mouse_watcher.isButtonDown('mouse1')
# 如果没有记录当前状态,初始化
if not hasattr(self, '_last_button_state'):
self._last_button_state = False
# 检测按钮从未按下到按下的状态变化(按下瞬间)
if is_button_down and not self._last_button_state:
print(f"🖱️ 鼠标监控:检测到按钮按下,位置({mouse_x:.3f}, {mouse_y:.3f})")
# 检查这次点击是否在按钮区域
clicked_button = self.check_button_click(mouse_x, mouse_y)
if clicked_button is not None:
print(f"🎯 鼠标监控检测到按钮点击: {clicked_button}")
self.on_tool_selected(clicked_button)
# 更新按钮状态
self._last_button_state = is_button_down
else:
if self._monitor_counter % 100 == 1:
print("❌ mouseWatcher为空")
return task.cont if task else None
except Exception as e:
print(f"❌ 鼠标监控异常: {e}")
import traceback
traceback.print_exc()
return task.cont if task else None
def check_button_click(self, mouse_x, mouse_y):
"""检查鼠标点击是否在按钮区域"""
try:
button_width = 0.4 # 与create_tool_buttons保持一致
button_height = 0.25 # 与create_tool_buttons保持一致
button_spacing = 0.45 # 与create_tool_buttons保持一致
start_x = -0.8 # 与create_tool_buttons保持一致
start_y = -0.75 # 与create_tool_buttons保持一致
print(f"🔍 检查按钮点击:鼠标({mouse_x:.3f}, {mouse_y:.3f})")
for i, tool_data in enumerate(self.available_tools):
# 获取工具名称
if isinstance(tool_data, dict):
tool_name = tool_data.get('name', str(tool_data))
else:
tool_name = str(tool_data)
# 计算按钮位置
button_x = start_x + i * button_spacing
button_y = start_y
# 计算按钮边界
left = button_x - button_width/2
right = button_x + button_width/2
bottom = button_y - button_height/2
top = button_y + button_height/2
print(f" 按钮{i} '{tool_name}': 中心({button_x:.3f}, {button_y:.3f}), 范围x[{left:.3f}, {right:.3f}], y[{bottom:.3f}, {top:.3f}]")
# 检查鼠标是否在按钮范围内
if (left <= mouse_x <= right and bottom <= mouse_y <= top):
print(f"✅ 点击在按钮{i} '{tool_name}' 范围内")
return tool_name
print("❌ 点击不在任何按钮范围内")
return None
except Exception as e:
print(f"❌ 检查按钮点击异常: {e}")
return None
def handle_mouse_click(self, qt_x, qt_y):
"""直接处理鼠标点击(从拆装交互系统调用)"""
try:
print(f"🖱️ 直接处理鼠标点击Qt坐标({qt_x}, {qt_y})")
# 将Qt坐标转换为aspect2d坐标
# 获取窗口尺寸
if hasattr(self.world, 'qtWidget') and self.world.qtWidget:
widget_width = self.world.qtWidget.width()
widget_height = self.world.qtWidget.height()
else:
widget_width = 1380
widget_height = 750
# 坐标转换(与之前拆装交互系统中的算法一致)
aspect_x = (qt_x / widget_width) * 2.67 - 1.33
aspect_y = 1.0 - (qt_y / widget_height) * 2.0
print(f"🔄 坐标转换Qt({qt_x}, {qt_y}) -> aspect2d({aspect_x:.3f}, {aspect_y:.3f})")
# 检查是否点击在按钮区域
clicked_button = self.check_button_click(aspect_x, aspect_y)
if clicked_button:
print(f"🎯 直接处理:检测到按钮点击 '{clicked_button}'")
self.on_tool_selected(clicked_button)
return True
return False
except Exception as e:
print(f"❌ 直接处理鼠标点击失败: {e}")
import traceback
traceback.print_exc()
return False
def get_aspect2d_reference(self):
"""获取aspect2d引用"""
if self.aspect2d:
return # 已经有引用了
try:
print("🔍 重新尝试获取aspect2d引用...")
# 方法1: 直接使用world对象推荐
if hasattr(self.world, 'aspect2d'):
self.aspect2d = self.world.aspect2d
print("✅ 从world获取aspect2d成功")
return
# 方法2: 使用world对象作为父节点
# 在main.py的Panda3DWorld中world对象本身就是ShowBase的实例
self.aspect2d = self.world.aspect2d if hasattr(self.world, 'aspect2d') else None
if self.aspect2d:
print("✅ 使用world.aspect2d成功")
else:
print("❌ 无法获取aspect2d引用")
except Exception as e:
print(f"❌ 获取aspect2d引用失败: {e}")
import traceback
traceback.print_exc()
def create_step_text(self):
"""创建步骤显示文本"""
try:
if not self.aspect2d:
print("❌ aspect2d引用不可用无法创建步骤文本")
return
self.step_text = DirectLabel(
text="准备开始维修训练...",
text_align=TextNode.ALeft,
text_scale=0.08,
text_fg=(1, 1, 1, 1),
text_bg=(0, 0, 0, 0.7),
frameColor=(0, 0, 0, 0.5),
frameSize=(-1.8, 1.8, -0.3, 0.3),
pos=(-1.7, 0, 0.8),
parent=self.aspect2d
)
print("✅ 步骤显示文本创建成功")
except Exception as e:
print(f"❌ 创建步骤文本失败: {e}")
import traceback
traceback.print_exc()
def create_tool_buttons(self):
"""创建工具选择按钮"""
try:
print(f"🔧 开始创建工具按钮...")
print(f" aspect2d引用: {self.aspect2d}")
print(f" 可用工具: {self.available_tools}")
print(f" 模式: {self.mode}")
if not self.aspect2d:
print("❌ aspect2d引用不可用无法创建工具按钮")
print(" 尝试重新获取aspect2d引用...")
self.get_aspect2d_reference()
if not self.aspect2d:
print("❌ 重新获取aspect2d失败")
return
print(f"🔧 使用aspect2d创建工具按钮: {self.available_tools}")
# 按钮布局参数(优化为更容易点击)
button_width = 0.4 # 增加宽度
button_height = 0.25 # 增加高度,让按钮更容易点击
button_spacing = 0.45 # 增加间距
start_x = -0.8 # 进一步向右移动
start_y = -0.75 # 向上移动一点
for i, tool in enumerate(self.available_tools):
# 处理工具数据格式
if isinstance(tool, dict):
tool_name = tool.get('name', str(tool))
tool_description = tool.get('description', '')
else:
tool_name = str(tool)
tool_description = ''
print(f" 正在创建按钮 {i+1}/{len(self.available_tools)}: {tool_name}")
# 计算按钮位置(横向排列)
pos_x = start_x + i * button_spacing
pos_y = start_y
# 创建按钮
button = DirectButton(
text=tool_name,
text_scale=0.06,
text_fg=(1, 1, 1, 1),
frameColor=(0.3, 0.3, 0.8, 0.8),
frameSize=(-button_width/2, button_width/2, -button_height/2, button_height/2),
pos=(pos_x, 0, pos_y),
command=self.on_tool_selected,
extraArgs=[tool_name],
parent=self.aspect2d,
# 按钮交互设置
relief=DGG.RAISED,
borderWidth=(0.01, 0.01),
text_pos=(0, -0.02),
# 强制启用鼠标交互
enableEdit=1,
# 音效设置
clickSound=None,
rolloverSound=None,
# 确保按钮优先级和可见性
sortOrder=1000, # 更高的排序值
state=DGG.NORMAL, # 确保按钮状态正常
# 鼠标事件设置
suppressMouse=0
)
# 手动绑定额外的事件监听
button.bind(DGG.B1PRESS, self.button_press_handler, extraArgs=[tool_name])
button.bind(DGG.B1RELEASE, self.button_release_handler, extraArgs=[tool_name])
self.tool_buttons.append(button)
print(f" ✅ 成功创建工具按钮: {tool_name} at ({pos_x}, {pos_y})")
print(f"🎯 总共创建了 {len(self.tool_buttons)} 个工具按钮")
# 设置默认选择的工具样式
self.update_tool_button_styles()
except Exception as e:
print(f"❌ 创建工具按钮失败: {e}")
import traceback
traceback.print_exc()
def create_current_tool_text(self):
"""创建当前工具显示文本"""
try:
if not self.aspect2d:
print("❌ aspect2d引用不可用无法创建当前工具文本")
return
self.current_tool_text = DirectLabel(
text=f"Tool: {self.current_tool}",
text_align=TextNode.ALeft,
text_scale=0.07,
text_fg=(1, 1, 0, 1),
text_bg=(0, 0, 0, 0.7),
frameColor=(0, 0, 0, 0.5),
frameSize=(-0.8, 0.8, -0.2, 0.2),
pos=(1.0, 0, 0.8),
parent=self.aspect2d
)
print("✅ 当前工具文本创建成功")
except Exception as e:
print(f"❌ 创建当前工具文本失败: {e}")
import traceback
traceback.print_exc()
def create_stop_button(self):
"""创建停止按钮"""
try:
if not self.aspect2d:
print("❌ aspect2d引用不可用无法创建停止按钮")
return
# 停止按钮位置:右下角
self.stop_button = DirectButton(
text="停止",
text_align=TextNode.ACenter,
text_scale=0.06,
text_fg=(1, 1, 1, 1),
text_bg=(0, 0, 0, 0),
frameColor=(0.8, 0.2, 0.2, 0.9), # 红色背景
frameSize=(-0.15, 0.15, -0.08, 0.08),
pos=(1.15, 0, -0.85), # 右下角位置
parent=self.aspect2d,
command=self.on_stop_clicked,
relief=DGG.RAISED,
borderWidth=(0.01, 0.01),
rolloverSound=None,
clickSound=None,
pressEffect=1
)
print("✅ 停止按钮创建成功")
except Exception as e:
print(f"❌ 创建停止按钮失败: {e}")
import traceback
traceback.print_exc()
def create_warning_text(self):
"""创建警告文本"""
try:
if not self.aspect2d:
print("❌ aspect2d引用不可用无法创建警告文本")
return
self.warning_text = DirectLabel(
text="",
text_align=TextNode.ACenter,
text_scale=0.09,
text_fg=(1, 0, 0, 1),
text_bg=(1, 1, 0, 0.8),
frameColor=(1, 0, 0, 0.8),
frameSize=(-1.5, 1.5, -0.3, 0.3),
pos=(0, 0, 0.3),
parent=self.aspect2d
)
# 默认隐藏警告文本
self.warning_text.hide()
print("✅ 警告文本创建成功")
except Exception as e:
print(f"❌ 创建警告文本失败: {e}")
import traceback
traceback.print_exc()
def button_press_handler(self, tool_name, event=None):
"""按钮按下事件处理"""
print(f"🖱️ 按钮按下事件:{tool_name}")
def button_release_handler(self, tool_name, event=None):
"""按钮释放事件处理"""
print(f"🖱️ 按钮释放事件:{tool_name}")
print(f"🔄 直接调用工具选择:{tool_name}")
self.on_tool_selected(tool_name)
def on_tool_selected(self, tool):
"""工具选择回调"""
try:
print(f"🎯 按钮点击事件触发!")
print(f"🔧 选择工具: {tool}")
# 考核模式下额外提示
if hasattr(self, 'mode') and self.mode == "exam":
print(f"📝 考核模式工具选择: {tool}")
print(f"📍 当前工具变更: {self.current_tool} -> {tool}")
self.current_tool = tool
# 更新当前工具显示
if self.current_tool_text:
self.current_tool_text['text'] = f"Tool: {tool}"
print(f"✅ 当前工具显示已更新")
# 更新按钮样式
self.update_tool_button_styles()
print(f"✅ 按钮样式已更新")
# 通知拆装交互系统工具变更
if hasattr(self.world, 'assembly_interaction') and self.world.assembly_interaction:
if hasattr(self.world.assembly_interaction, 'step_dialog') and self.world.assembly_interaction.step_dialog:
# 更新步骤对话框中的工具选择
step_dialog = self.world.assembly_interaction.step_dialog
if hasattr(step_dialog, 'tool_combo'):
# 同步工具选择
tool_index = -1
for i in range(step_dialog.tool_combo.count()):
if step_dialog.tool_combo.itemText(i) == tool:
tool_index = i
break
if tool_index >= 0:
step_dialog.tool_combo.setCurrentIndex(tool_index)
print(f"✅ Qt对话框工具选择已同步")
print(f"✅ 工具切换完成: {tool}")
except Exception as e:
print(f"❌ 工具选择失败: {e}")
import traceback
traceback.print_exc()
def on_stop_clicked(self):
"""停止按钮点击回调"""
try:
print("🛑 用户点击停止按钮")
# 通知拆装交互系统停止
if hasattr(self.world, 'assembly_interaction') and self.world.assembly_interaction:
self.world.assembly_interaction.stop_interaction()
else:
print("⚠️ 拆装交互系统不存在,无法停止")
except Exception as e:
print(f"❌ 停止操作失败: {e}")
import traceback
traceback.print_exc()
def update_tool_button_styles(self):
"""更新工具按钮样式"""
try:
for i, button in enumerate(self.tool_buttons):
# 处理工具数据格式
tool_data = self.available_tools[i]
if isinstance(tool_data, dict):
tool_name = tool_data.get('name', str(tool_data))
else:
tool_name = str(tool_data)
if tool_name == self.current_tool:
# 选中状态:亮蓝色
button['frameColor'] = (0.2, 0.8, 1.0, 0.9)
button['text_fg'] = (0, 0, 0, 1)
else:
# 未选中状态:深蓝色
button['frameColor'] = (0.3, 0.3, 0.8, 0.8)
button['text_fg'] = (1, 1, 1, 1)
except Exception as e:
print(f"❌ 更新按钮样式失败: {e}")
import traceback
traceback.print_exc()
def update_step_info(self, step_text):
"""更新步骤信息"""
try:
print(f"📋 更新步骤信息: {step_text}")
self.current_step_info = step_text
if self.step_text:
self.step_text['text'] = step_text
except Exception as e:
print(f"❌ 更新步骤信息失败: {e}")
def show_warning(self, message, duration=2.0):
"""显示警告信息(仅训练模式)"""
try:
# 考核模式下不显示警告
if hasattr(self, 'mode') and self.mode == "exam":
print(f"📝 考核模式:隐藏警告 - {message}")
return
print(f"⚠️ 显示警告: {message}")
if not self.warning_text:
return
# 取消之前的警告任务
if self.warning_task:
taskMgr.remove(self.warning_task)
self.warning_task = None
# 显示警告文本
self.warning_text['text'] = message
self.warning_text.show()
# 设置自动隐藏任务
self.warning_task = taskMgr.doMethodLater(
duration,
self.hide_warning,
'hide_warning_task'
)
except Exception as e:
print(f"❌ 显示警告失败: {e}")
def hide_warning(self, task=None):
"""隐藏警告信息"""
try:
if self.warning_text:
self.warning_text.hide()
if self.warning_task:
self.warning_task = None
return Task.done
except Exception as e:
print(f"❌ 隐藏警告失败: {e}")
return Task.done
def test_tool_selection(self):
"""测试工具选择功能按T键触发"""
if self.available_tools:
# 循环选择工具进行测试
current_index = 0
for i, tool_data in enumerate(self.available_tools):
if isinstance(tool_data, dict):
tool_name = tool_data.get('name', str(tool_data))
else:
tool_name = str(tool_data)
if tool_name == self.current_tool:
current_index = i
break
# 选择下一个工具
next_index = (current_index + 1) % len(self.available_tools)
next_tool_data = self.available_tools[next_index]
if isinstance(next_tool_data, dict):
next_tool_name = next_tool_data.get('name', str(next_tool_data))
else:
next_tool_name = str(next_tool_data)
print(f"⌨️ 键盘测试:切换到工具 '{next_tool_name}'")
self.on_tool_selected(next_tool_name)
def test_specific_button(self, button_index):
"""测试特定按钮(通过索引)"""
if not hasattr(self, 'available_tools') or not self.available_tools:
print(f"⌨️ 按钮{button_index}: 没有可用工具")
return
if button_index >= len(self.available_tools):
print(f"⌨️ 按钮{button_index}: 索引超出范围(最大{len(self.available_tools)-1}")
return
# 获取工具名称
tool_data = self.available_tools[button_index]
if isinstance(tool_data, dict):
tool_name = tool_data.get('name', str(tool_data))
else:
tool_name = str(tool_data)
print(f"⌨️ 按钮{button_index}测试:切换到工具 '{tool_name}'")
self.on_tool_selected(tool_name)
def print_button_positions(self):
"""打印所有按钮的位置信息"""
try:
if not hasattr(self, 'available_tools') or not self.available_tools:
print("📍 没有可用工具按钮")
return
print("📍 ===== 按钮位置信息 =====")
button_width = 0.4
button_height = 0.25
button_spacing = 0.45
start_x = -0.8
start_y = -0.75
for i, tool_data in enumerate(self.available_tools):
# 获取工具名称
if isinstance(tool_data, dict):
tool_name = tool_data.get('name', str(tool_data))
else:
tool_name = str(tool_data)
# 计算按钮位置
button_x = start_x + i * button_spacing
button_y = start_y
# 计算按钮边界
left = button_x - button_width/2
right = button_x + button_width/2
bottom = button_y - button_height/2
top = button_y + button_height/2
print(f"📍 按钮{i} '{tool_name}':")
print(f" 中心: ({button_x:.3f}, {button_y:.3f})")
print(f" 范围: x[{left:.3f}, {right:.3f}], y[{bottom:.3f}, {top:.3f}]")
print(f" 尺寸: {button_width} x {button_height}")
print("📍 ========================")
except Exception as e:
print(f"❌ 打印按钮位置失败: {e}")
import traceback
traceback.print_exc()
def show_exam_results(self, exam_data):
"""显示考核结果GUI界面"""
try:
print("🎓 开始显示考核结果GUI...")
# 清理现有GUI元素
self.cleanup_gui()
# 创建考核结果界面
self.create_exam_result_gui(exam_data)
print("✅ 考核结果GUI显示完成")
except Exception as e:
print(f"❌ 显示考核结果GUI失败: {e}")
import traceback
traceback.print_exc()
def create_exam_result_gui(self, exam_data):
"""创建考核结果GUI界面"""
try:
if not self.aspect2d:
print("❌ aspect2d引用不可用无法创建考核结果GUI")
return
# 主背景 - 黑色背景
from direct.gui.DirectGui import DirectFrame
self.exam_bg = DirectFrame(
frameColor=(0, 0, 0, 0.95), # 更深的黑色背景
frameSize=(-2.0, 2.0, -1.0, 1.0),
pos=(0, 0, 0),
parent=self.aspect2d
)
# 标题
self.exam_title = DirectLabel(
text="🎓 考核结果报告",
text_align=TextNode.ACenter,
text_scale=0.12,
text_fg=(1, 1, 0, 1), # 黄色文字
text_bg=(0, 0, 0, 0), # 透明背景
frameColor=(0, 0, 0, 0), # 透明边框
frameSize=(-1.5, 1.5, -0.15, 0.15),
pos=(0, 0, 0.8),
parent=self.aspect2d
)
# 总体成绩区域
score_text = f"📊 总得分: {exam_data['final_score']:.0f}/{exam_data['max_score']:.0f} 分 ({exam_data['score_rate']:.1f}%)\n"
score_text += f"🏅 评级: {exam_data['grade_icon']} {exam_data['grade']} - {exam_data['grade_desc']}\n"
score_text += f"🎯 操作准确率: {exam_data['accuracy_rate']:.1f}% | 完美步骤: {exam_data['perfect_steps']}/{exam_data['total_steps']}"
# 根据成绩选择文字颜色(在黑色背景下更突出)
if exam_data['score_rate'] >= 90:
score_fg_color = (0.2, 1.0, 0.2, 1) # 亮绿色
elif exam_data['score_rate'] >= 80:
score_fg_color = (0.8, 1.0, 0.2, 1) # 亮黄绿色
elif exam_data['score_rate'] >= 60:
score_fg_color = (1.0, 0.8, 0.2, 1) # 亮橙色
else:
score_fg_color = (1.0, 0.3, 0.3, 1) # 亮红色
self.exam_score = DirectLabel(
text=score_text,
text_align=TextNode.ACenter,
text_scale=0.07,
text_fg=score_fg_color, # 根据成绩动态变色
text_bg=(0, 0, 0, 0), # 透明背景
frameColor=(0, 0, 0, 0), # 透明边框
frameSize=(-1.9, 1.9, -0.3, 0.3),
pos=(0, 0, 0.35),
parent=self.aspect2d
)
# 步骤详情区域
steps_text = "📋 步骤详情:\n"
for step in exam_data['step_details']:
steps_text += f"{step['status']} {step['name']}: {step['current_score']:.0f}/{step['max_score']:.0f}"
if step['tool_error']:
steps_text += " ❌工具错误"
steps_text += f" ({step['attempts']}次操作)\n"
self.exam_steps = DirectLabel(
text=steps_text,
text_align=TextNode.ALeft,
text_scale=0.06,
text_fg=(0.9, 0.9, 0.9, 1), # 浅灰色文字
text_bg=(0, 0, 0, 0), # 透明背景
frameColor=(0, 0, 0, 0), # 透明边框
frameSize=(-1.8, 1.8, -0.4, 0.4),
pos=(0, 0, -0.1),
parent=self.aspect2d
)
# 改进建议区域(如果有建议)
if exam_data['suggestions']:
suggestions_text = "💡 改进建议:\n"
for suggestion in exam_data['suggestions']:
suggestions_text += f"{suggestion}\n"
self.exam_suggestions = DirectLabel(
text=suggestions_text,
text_align=TextNode.ALeft,
text_scale=0.05,
text_fg=(1, 0.8, 0.2, 1), # 橙黄色文字
text_bg=(0, 0, 0, 0), # 透明背景
frameColor=(0, 0, 0, 0), # 透明边框
frameSize=(-1.8, 1.8, -0.25, 0.25),
pos=(0, 0, -0.7),
parent=self.aspect2d
)
# 倒计时显示
self.exam_countdown_text = DirectLabel(
text="10秒后自动关闭",
text_align=TextNode.ACenter,
text_scale=0.06,
text_fg=(0.8, 0.8, 0.8, 1), # 灰色文字
text_bg=(0, 0, 0, 0), # 透明背景
frameColor=(0, 0, 0, 0), # 透明边框
frameSize=(-0.8, 0.8, -0.1, 0.1),
pos=(0, 0, -0.8),
parent=self.aspect2d
)
# 启动10秒倒计时任务
self.start_countdown_timer()
print("✅ 考核结果GUI元素创建完成")
except Exception as e:
print(f"❌ 创建考核结果GUI失败: {e}")
import traceback
traceback.print_exc()
def close_exam_results(self):
"""关闭考核结果界面"""
try:
print("🔄 关闭考核结果界面...")
# 清理考核结果GUI元素
if hasattr(self, 'exam_bg') and self.exam_bg:
self.exam_bg.removeNode()
self.exam_bg = None
if hasattr(self, 'exam_title') and self.exam_title:
self.exam_title.removeNode()
self.exam_title = None
if hasattr(self, 'exam_score') and self.exam_score:
self.exam_score.removeNode()
self.exam_score = None
if hasattr(self, 'exam_steps') and self.exam_steps:
self.exam_steps.removeNode()
self.exam_steps = None
if hasattr(self, 'exam_suggestions') and self.exam_suggestions:
self.exam_suggestions.removeNode()
self.exam_suggestions = None
if hasattr(self, 'exam_countdown_text') and self.exam_countdown_text:
self.exam_countdown_text.removeNode()
self.exam_countdown_text = None
# 停止倒计时任务
if hasattr(self, 'exam_countdown_task') and self.exam_countdown_task:
taskMgr.remove(self.exam_countdown_task)
self.exam_countdown_task = None
print("✅ 考核结果界面已关闭")
except Exception as e:
print(f"❌ 关闭考核结果界面失败: {e}")
import traceback
traceback.print_exc()
def start_countdown_timer(self):
"""启动10秒倒计时"""
try:
self.countdown_seconds = 10
print(f"⏰ 启动考核结果倒计时:{self.countdown_seconds}")
# 启动倒计时任务
self.exam_countdown_task = taskMgr.doMethodLater(
1.0, # 每秒执行一次
self.update_countdown,
'exam_countdown_task'
)
except Exception as e:
print(f"❌ 启动倒计时失败: {e}")
import traceback
traceback.print_exc()
def update_countdown(self, task):
"""更新倒计时显示"""
try:
self.countdown_seconds -= 1
if self.countdown_seconds > 0:
# 更新倒计时显示
if hasattr(self, 'exam_countdown_text') and self.exam_countdown_text:
self.exam_countdown_text['text'] = f"{self.countdown_seconds}秒后自动关闭"
print(f"⏰ 倒计时:{self.countdown_seconds}")
# 继续倒计时
return task.again
else:
# 倒计时结束,自动关闭
print("⏰ 倒计时结束,自动关闭考核结果界面")
self.close_exam_results()
return task.done
except Exception as e:
print(f"❌ 更新倒计时失败: {e}")
import traceback
traceback.print_exc()
return task.done
def get_current_tool(self):
"""获取当前选择的工具"""
return self.current_tool
def set_mode(self, mode):
"""设置模式"""
self.mode = mode
print(f"🎯 维修GUI模式设置为: {mode}")
def cleanup_gui(self):
"""清理GUI元素"""
try:
print("🧹 清理维修系统GUI")
# 清理步骤文本
if self.step_text:
self.step_text.destroy()
self.step_text = None
# 清理当前工具文本
if self.current_tool_text:
self.current_tool_text.destroy()
self.current_tool_text = None
# 清理警告文本
if self.warning_text:
self.warning_text.destroy()
self.warning_text = None
# 清理工具按钮
for button in self.tool_buttons:
if button:
button.destroy()
self.tool_buttons.clear()
# 清理停止按钮
if hasattr(self, 'stop_button') and self.stop_button:
self.stop_button.destroy()
self.stop_button = None
# 取消警告任务
if self.warning_task:
taskMgr.remove(self.warning_task)
self.warning_task = None
# 取消鼠标监控任务
if self.mouse_monitor_task:
taskMgr.remove(self.mouse_monitor_task)
self.mouse_monitor_task = None
# 清理考核结果界面
self.close_exam_results()
print("✅ 维修系统GUI清理完成")
except Exception as e:
print(f"❌ 清理维修系统GUI失败: {e}")
def show_gui(self):
"""显示GUI"""
try:
print(f"🎨 显示维修系统GUI...")
print(f" 模式: {self.mode}")
print(f" 步骤文本: {self.step_text is not None}")
print(f" 当前工具文本: {self.current_tool_text is not None}")
print(f" 工具按钮数量: {len(self.tool_buttons)}")
if self.step_text:
self.step_text.show()
print(" ✅ 步骤文本已显示")
# 当前工具文本和工具按钮在训练和考核模式都需要显示
if self.current_tool_text:
self.current_tool_text.show()
print(" ✅ 当前工具文本已显示")
for i, button in enumerate(self.tool_buttons):
button.show()
print(f" ✅ 工具按钮 {i+1} 已显示")
# 停止按钮在训练和考核模式都需要显示
if self.stop_button:
self.stop_button.show()
print(" ✅ 停止按钮已显示")
print("✅ 维修系统GUI显示完成")
except Exception as e:
print(f"❌ 显示维修系统GUI失败: {e}")
import traceback
traceback.print_exc()
def hide_gui(self):
"""隐藏GUI"""
try:
if self.step_text:
self.step_text.hide()
if self.current_tool_text:
self.current_tool_text.hide()
if self.warning_text:
self.warning_text.hide()
for button in self.tool_buttons:
button.hide()
if self.stop_button:
self.stop_button.hide()
print("✅ 维修系统GUI隐藏")
except Exception as e:
print(f"❌ 隐藏维修系统GUI失败: {e}")