#!/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"🔍 初始化维修GUI,world类型: {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}")