#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Qt环境GUI事件修复测试 解决Qt集成环境中DirectGUI事件处理问题 """ import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel from PyQt5.QtCore import Qt from PyQt5.QtGui import QMouseEvent from QPanda3D.QPanda3DWidget import QPanda3DWidget from QPanda3D.Panda3DWorld import Panda3DWorld from direct.gui.DirectGui import * from direct.gui.OnscreenText import OnscreenText from panda3d.core import * class QtGUIFixWorld(Panda3DWorld): def __init__(self): super().__init__() print("=== Qt GUI事件修复测试 ===") self.setBackgroundColor(0.2, 0.2, 0.3) # 检查环境 print(f"窗口类型: {type(self.win)}") print(f"图形引擎: {self.graphicsEngine}") # 延迟创建GUI self.taskMgr.doMethodLater(0.5, self.createTestGUI, "create-gui") # 保存GUI元素引用用于事件处理 self.gui_elements = [] def createTestGUI(self, task=None): """创建测试GUI""" print("\n--- 创建Qt环境GUI ---") # 方法1: 标准DirectGUI创建 try: self.title = OnscreenText( text="Qt环境GUI测试", pos=(0, 0.8), scale=0.08, fg=(1, 1, 1, 1), align=TextNode.ACenter ) print(f"✓ 标题创建成功: {self.title}") except Exception as e: print(f"❌ 标题创建失败: {str(e)}") # 测试按钮1 - 标准创建 try: self.button1 = DirectButton( text="标准按钮", pos=(0, 0, 0.4), scale=0.1, frameColor=(0, 1, 0, 1), command=self.onButton1Click ) self.gui_elements.append(('button1', self.button1)) print(f"✓ 标准按钮创建成功: {self.button1}") except Exception as e: print(f"❌ 标准按钮创建失败: {str(e)}") # 测试按钮2 - 手动事件处理 try: self.button2 = DirectButton( text="修复按钮", pos=(0, 0, 0.1), scale=0.1, frameColor=(1, 0, 0, 1), command=self.onButton2Click ) # 手动设置事件处理 self.setupManualEvents(self.button2) self.gui_elements.append(('button2', self.button2)) print(f"✓ 修复按钮创建成功: {self.button2}") except Exception as e: print(f"❌ 修复按钮创建失败: {str(e)}") # 测试按钮3 - 自定义点击检测 try: self.button3 = DirectButton( text="自检按钮", pos=(0, 0, -0.2), scale=0.1, frameColor=(0, 0, 1, 1), # 不设置command,使用自定义检测 ) self.gui_elements.append(('button3', self.button3)) print(f"✓ 自检按钮创建成功: {self.button3}") # 启动自定义点击检测 self.taskMgr.add(self.checkButtonClicks, "check-clicks") except Exception as e: print(f"❌ 自检按钮创建失败: {str(e)}") return task.done if task else None def setupManualEvents(self, button): """为按钮设置手动事件处理""" try: # 获取按钮的PGItem if hasattr(button, 'guiItem'): pgItem = button.guiItem # 强制启用事件 pgItem.setActive(True) print(f" 手动启用按钮事件: {pgItem}") except Exception as e: print(f" 手动事件设置失败: {str(e)}") def checkButtonClicks(self, task): """自定义按钮点击检测""" # 检查鼠标状态 if hasattr(self, 'mouseWatcherNode') and self.mouseWatcherNode.hasMouse(): # 获取鼠标位置 mouseX = self.mouseWatcherNode.getMouseX() mouseY = self.mouseWatcherNode.getMouseY() # 检查是否在button3范围内 if hasattr(self, 'button3'): buttonPos = self.button3.getPos() buttonScale = self.button3.getScale() # 简单的边界检测 if (abs(mouseX - buttonPos.getX()) < buttonScale.getX() * 0.5 and abs(mouseY - buttonPos.getZ()) < buttonScale.getZ() * 0.5): # 检查是否有鼠标点击 if self.mouseWatcherNode.isButtonDown('button1'): self.onButton3Click() # 防止重复触发 return task.pause(0.5) return task.cont def onButton1Click(self): """标准按钮点击""" print("🟢 标准按钮被点击!") def onButton2Click(self): """修复按钮点击""" print("🔴 修复按钮被点击!") def onButton3Click(self): """自检按钮点击""" print("🔵 自检按钮被点击!") def handleQtMouseEvent(self, event): """处理Qt鼠标事件""" try: # 将Qt事件转换为Panda3D坐标 if hasattr(self, 'win'): winX = event.x() winY = event.y() winWidth = self.win.getXSize() winHeight = self.win.getYSize() # 转换为归一化坐标 (-1 到 1) normalizedX = (winX / winWidth) * 2.0 - 1.0 normalizedY = 1.0 - (winY / winHeight) * 2.0 print(f"Qt鼠标事件: ({winX}, {winY}) -> 归一化: ({normalizedX:.3f}, {normalizedY:.3f})") # 手动检查GUI元素 for name, element in self.gui_elements: if hasattr(element, 'getPos'): elemPos = element.getPos() elemScale = element.getScale() # 简单边界检测 if (abs(normalizedX - elemPos.getX()) < elemScale.getX() * 0.5 and abs(normalizedY - elemPos.getZ()) < elemScale.getZ() * 0.5): print(f" 点击在 {name} 范围内!") # 手动触发回调 if name == 'button1': self.onButton1Click() elif name == 'button2': self.onButton2Click() elif name == 'button3': self.onButton3Click() return True except Exception as e: print(f"Qt事件处理失败: {str(e)}") return False class CustomQPanda3DWidget(QPanda3DWidget): """自定义QPanda3DWidget,支持事件转发""" def __init__(self, world, parent=None): super().__init__(world, parent) self.world = world print("自定义QPanda3D部件初始化") def mousePressEvent(self, event): """重写鼠标按下事件""" print(f"\n=== Qt鼠标按下事件 ===") print(f"位置: ({event.x()}, {event.y()})") print(f"按钮: {event.button()}") # 尝试让世界处理事件 if hasattr(self.world, 'handleQtMouseEvent'): handled = self.world.handleQtMouseEvent(event) if handled: print("事件已被世界处理") return # 调用父类方法 super().mousePressEvent(event) def main(): print("启动Qt环境GUI事件修复测试...") app = QApplication(sys.argv) # 创建主窗口 mainWindow = QMainWindow() mainWindow.setWindowTitle("Qt GUI事件修复测试") mainWindow.setGeometry(100, 100, 800, 600) # 创建布局 centralWidget = QWidget() layout = QVBoxLayout(centralWidget) # 添加说明 label = QLabel("Qt环境DirectGUI事件修复测试") label.setAlignment(Qt.AlignCenter) label.setStyleSheet("background-color: lightgreen; padding: 10px;") layout.addWidget(label) # 创建世界 world = QtGUIFixWorld() # 创建自定义Panda3D部件 pandaWidget = CustomQPanda3DWidget(world) layout.addWidget(pandaWidget) mainWindow.setCentralWidget(centralWidget) mainWindow.show() print("\n测试说明:") print("绿色按钮: 标准DirectGUI事件处理") print("红色按钮: 手动事件修复") print("蓝色按钮: 自定义点击检测") print("查看控制台输出了解事件处理情况") return app.exec_() if __name__ == "__main__": main()