This commit is contained in:
Rowland 2026-01-26 10:39:27 +08:00
parent 385103e252
commit 403c4d34f8
4 changed files with 2971 additions and 2803 deletions

View File

@ -6,7 +6,7 @@ class CustomMouseController:
self.showbase = showbase self.showbase = showbase
# This is used to store which keys are currently pressed. # This is used to store which keys are currently pressed.
self.keyMap = { self.keyMap = {
"mouse1": 0, # "mouse1": 0, # 移除左键,用于选择功能
"mouse3": 0, # 右键 "mouse3": 0, # 右键
"cam-forward": 0, "cam-forward": 0,
"cam-backward": 0, "cam-backward": 0,
@ -16,9 +16,9 @@ class CustomMouseController:
"cam-down": 0 "cam-down": 0
} }
# 添加鼠标控制 # 添加鼠标控制 - 只保留右键控制,左键用于选择
self.showbase.accept("mouse1", self.setKey, ["mouse1", True]) # self.showbase.accept("mouse1", self.setKey, ["mouse1", True]) # 移除左键绑定
self.showbase.accept("mouse1-up", self.setKey, ["mouse1", False]) # self.showbase.accept("mouse1-up", self.setKey, ["mouse1", False]) # 移除左键绑定
self.showbase.accept("mouse3", self.setKey, ["mouse3", True]) # 右键 self.showbase.accept("mouse3", self.setKey, ["mouse3", True]) # 右键
self.showbase.accept("mouse3-up", self.setKey, ["mouse3", False]) # 右键释放 self.showbase.accept("mouse3-up", self.setKey, ["mouse3", False]) # 右键释放
@ -49,7 +49,8 @@ class CustomMouseController:
def setKey(self, key, value, arg: str = None): def setKey(self, key, value, arg: str = None):
self.keyMap[key] = value self.keyMap[key] = value
if (key == "mouse1" or key == "mouse3") and value == True: # 只在右键按下时记录鼠标位置
if key == "mouse3" and value == True:
mouse_pos = self.showbase.mouseWatcherNode.getMouse() mouse_pos = self.showbase.mouseWatcherNode.getMouse()
if mouse_pos: if mouse_pos:
self.last_mouse_x = mouse_pos.get_x() self.last_mouse_x = mouse_pos.get_x()
@ -72,7 +73,7 @@ class CustomMouseController:
self.showbase.camera.setZ(self.showbase.camera, +self.move_speed * dt) self.showbase.camera.setZ(self.showbase.camera, +self.move_speed * dt)
if self.keyMap["cam-down"]: if self.keyMap["cam-down"]:
self.showbase.camera.setZ(self.showbase.camera, -self.move_speed * dt) self.showbase.camera.setZ(self.showbase.camera, -self.move_speed * dt)
if self.keyMap["mouse1"] or self.keyMap["mouse3"]: # 左键或右键按下 if self.keyMap["mouse3"]: # 只使用右键控制视角旋转
try: try:
# 检查是否应该处理鼠标事件避免与ImGui冲突 # 检查是否应该处理鼠标事件避免与ImGui冲突
if self._should_handle_mouse(): if self._should_handle_mouse():

View File

@ -113,20 +113,21 @@ class EventHandler:
def mousePressEventLeft(self, evt): def mousePressEventLeft(self, evt):
"""处理鼠标左键按下事件""" """处理鼠标左键按下事件"""
print("\n=== 开始处理鼠标左键事件 ===") print("\n=== EventHandler开始处理鼠标左键事件 ===")
#print(f"当前工具: {self.world.currentTool}") print(f"🔧 当前工具: {getattr(self.world, 'currentTool', '未知')}")
if not evt: if not evt:
print("事件为空") print("事件为空")
return return
if self.world.currentTool == "地形编辑": if self.world.currentTool == "地形编辑":
print("🔧 地形编辑模式,调用地形编辑处理")
self._handleTerrainEdit(evt,"add") self._handleTerrainEdit(evt,"add")
return return
# 获取鼠标点击的位置 # 获取鼠标点击的位置
x = evt.get('x', 0) x = evt.get('x', 0)
y = evt.get('y', 0) y = evt.get('y', 0)
#print(f"鼠标点击位置: ({x}, {y})") print(f"📍 EventHandler收到鼠标点击位置: ({x:.1f}, {y:.1f})")
# 获取准确的窗口尺寸 # 获取准确的窗口尺寸
winWidth, winHeight = self.world.getWindowSize() winWidth, winHeight = self.world.getWindowSize()
@ -184,7 +185,7 @@ class EventHandler:
self.showClickRay(worldNearPoint, worldFarPoint, hitPos) self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
# 处理ImGui鼠标点击 # 处理ImGui鼠标点击
if hasattr(self.world, 'imgui_manager') and self.world.imgui_manager: if hasattr(self.world, 'processImGuiMouseClick'):
if self.world.processImGuiMouseClick(x, y): if self.world.processImGuiMouseClick(x, y):
# 如果ImGui处理了点击不再进行其他处理 # 如果ImGui处理了点击不再进行其他处理
pickerNP.removeNode() pickerNP.removeNode()
@ -484,7 +485,7 @@ class EventHandler:
self.world.selection.updateSelection(selectedModel) self.world.selection.updateSelection(selectedModel)
# 在树形控件中查找并选中对应的项 # 在树形控件中查找并选中对应的项
if self.world.interface_manager.treeWidget: if hasattr(self.world, 'interface_manager') and self.world.interface_manager and hasattr(self.world.interface_manager, 'treeWidget') and self.world.interface_manager.treeWidget:
#print("查找树形控件中的对应项...") #print("查找树形控件中的对应项...")
root = self.world.interface_manager.treeWidget.invisibleRootItem() root = self.world.interface_manager.treeWidget.invisibleRootItem()
foundItem = None foundItem = None

View File

@ -1496,6 +1496,10 @@ class SelectionSystem:
# 如果没有明确指定轴,尝试通过鼠标位置检测 # 如果没有明确指定轴,尝试通过鼠标位置检测
self.dragGizmoAxis = self.detectGizmoAxisAtMouse(mouseX, mouseY) self.dragGizmoAxis = self.detectGizmoAxisAtMouse(mouseX, mouseY)
# 启动拖拽更新任务
if hasattr(self.world, 'taskMgr') and self.world.taskMgr:
self.world.taskMgr.add(self._dragUpdateTask, "gizmoDragUpdate")
# 如果仍然无法确定拖拽轴,则取消拖拽 # 如果仍然无法确定拖拽轴,则取消拖拽
if not self.dragGizmoAxis: if not self.dragGizmoAxis:
print("开始拖拽失败: 无法确定拖拽轴") print("开始拖拽失败: 无法确定拖拽轴")
@ -1625,7 +1629,8 @@ class SelectionSystem:
# 应用新缩放值 # 应用新缩放值
self.gizmoTarget.setScale(new_scale) self.gizmoTarget.setScale(new_scale)
self.world.property_panel.refreshModelValues(self.gizmoTarget) if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
return return
elif is_rotate_tool: elif is_rotate_tool:
rotation_speed = 0.5 rotation_speed = 0.5
@ -1644,7 +1649,8 @@ class SelectionSystem:
start_hpr.y + rotation_amount, start_hpr.y + rotation_amount,
start_hpr.z + rotation_amount) start_hpr.z + rotation_amount)
self.gizmoTarget.setHpr(new_hpr) self.gizmoTarget.setHpr(new_hpr)
self.world.property_panel.refreshModelValues(self.gizmoTarget) if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
return return
# 使用坐标轴的实际位置而不是目标节点位置来计算屏幕投影 # 使用坐标轴的实际位置而不是目标节点位置来计算屏幕投影
@ -1794,8 +1800,14 @@ class SelectionSystem:
if light_object: if light_object:
light_object.pos = newPos light_object.pos = newPos
self.gizmoTarget.setPos(newPos) self.gizmoTarget.setPos(newPos)
print(f"🔄 光源拖拽移动: {currentPos} -> {newPos}")
else: else:
self.gizmoTarget.setPos(newPos) self.gizmoTarget.setPos(newPos)
print(f"🔄 节点拖拽移动: {currentPos} -> {newPos} (轴: {self.dragGizmoAxis}, 距离: {movement_distance:.3f})")
# 更新属性面板
if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
# 更新坐标轴位置 - 计算新的中心位置 # 更新坐标轴位置 - 计算新的中心位置
minPoint = Point3() minPoint = Point3()
@ -1845,6 +1857,38 @@ class SelectionSystem:
"""停止坐标轴拖拽""" """停止坐标轴拖拽"""
print(f"停止坐标轴拖拽 - 轴: {self.dragGizmoAxis}") print(f"停止坐标轴拖拽 - 轴: {self.dragGizmoAxis}")
# 移除拖拽更新任务
if hasattr(self.world, 'taskMgr') and self.world.taskMgr:
self.world.taskMgr.remove("gizmoDragUpdate")
def _dragUpdateTask(self, task):
"""拖拽更新任务 - 持续更新拖拽状态"""
try:
if not self.isDraggingGizmo:
return task.done
# 检查鼠标是否仍然按下
if not self.world.mouseWatcherNode.hasMouse():
return task.cont
# 获取当前鼠标位置
mouse_x = self.world.mouseWatcherNode.getMouseX()
mouse_y = self.world.mouseWatcherNode.getMouseY()
# 转换为窗口坐标
winWidth, winHeight = self.world.getWindowSize()
window_x = (mouse_x + 1) * 0.5 * winWidth
window_y = (1 - mouse_y) * 0.5 * winHeight
# 调用拖拽更新
self.updateGizmoDrag(window_x, window_y)
return task.cont
except Exception as e:
print(f"拖拽更新任务错误: {e}")
return task.done
if hasattr(self.world,'command_manager') and self.world.command_manager and self.gizmoTarget: if hasattr(self.world,'command_manager') and self.world.command_manager and self.gizmoTarget:
current_pos = self.gizmoTarget.getPos() current_pos = self.gizmoTarget.getPos()

140
demo.py
View File

@ -122,6 +122,13 @@ class MyWorld(CoreWorld):
self.accept("p",self.onPatrolKeyPressed) self.accept("p",self.onPatrolKeyPressed)
self.accept("P",self.onPatrolKeyPressed) self.accept("P",self.onPatrolKeyPressed)
# 绑定鼠标事件用于3D场景选择
self.accept("mouse1", self.onMouseClick)
self.accept("mouse1-up", self.onMouseRelease)
# 尝试多种鼠标移动事件绑定方式
self.accept("mouse-move", self.onMouseMove)
self.accept("drag", self.onMouseMove)
# 初始化事件处理系统 # 初始化事件处理系统
self.event_handler = EventHandler(self) self.event_handler = EventHandler(self)
@ -480,6 +487,103 @@ class MyWorld(CoreWorld):
except Exception as e: except Exception as e:
print(f"处理 F 键事件失败: {e}") print(f"处理 F 键事件失败: {e}")
def onMouseClick(self):
"""处理鼠标点击事件"""
print("\n=== 鼠标点击事件触发 ===")
try:
# 检查鼠标是否有效
if not self.mouseWatcherNode.hasMouse():
print("❌ 鼠标无效或不在窗口内")
return
print("✓ 鼠标位置有效")
# 获取鼠标位置
mouse_x = self.mouseWatcherNode.getMouseX()
mouse_y = self.mouseWatcherNode.getMouseY()
print(f"📍 鼠标标准化坐标: ({mouse_x:.3f}, {mouse_y:.3f})")
# 转换为窗口坐标
winWidth, winHeight = self.win.getSize()
window_x = (mouse_x + 1) * 0.5 * winWidth
window_y = (1 - mouse_y) * 0.5 * winHeight
print(f"📍 鼠标窗口坐标: ({window_x:.1f}, {window_y:.1f})")
print(f"📐 窗口尺寸: {winWidth} x {winHeight}")
# 检查ImGui是否捕获了鼠标
imgui_captured = self.processImGuiMouseClick(window_x, window_y)
print(f"🖱️ ImGui捕获状态: {imgui_captured}")
if imgui_captured:
print("❌ ImGui处理了该事件跳过3D场景选择")
return
# 调用事件处理器进行射线检测和选择
if hasattr(self, 'event_handler'):
print("✓ 找到事件处理器,开始处理选择")
self.event_handler.mousePressEventLeft({
'x': window_x,
'y': window_y
})
else:
print("❌ 未找到事件处理器")
except Exception as e:
print(f"❌ 处理鼠标点击事件失败: {e}")
import traceback
traceback.print_exc()
def onMouseRelease(self):
"""处理鼠标释放事件"""
try:
# 检查鼠标是否有效
if not self.mouseWatcherNode.hasMouse():
return
# 获取鼠标位置
mouse_x = self.mouseWatcherNode.getMouseX()
mouse_y = self.mouseWatcherNode.getMouseY()
# 转换为窗口坐标
winWidth, winHeight = self.win.getSize()
window_x = (mouse_x + 1) * 0.5 * winWidth
window_y = (1 - mouse_y) * 0.5 * winHeight
# 调用事件处理器
if hasattr(self, 'event_handler'):
self.event_handler.mouseReleaseEventLeft({
'x': window_x,
'y': window_y
})
except Exception as e:
print(f"处理鼠标释放事件失败: {e}")
def onMouseMove(self):
"""处理鼠标移动事件"""
try:
# 检查鼠标是否有效
if not self.mouseWatcherNode.hasMouse():
return
# 获取鼠标位置
mouse_x = self.mouseWatcherNode.getMouseX()
mouse_y = self.mouseWatcherNode.getMouseY()
# 转换为窗口坐标
winWidth, winHeight = self.win.getSize()
window_x = (mouse_x + 1) * 0.5 * winWidth
window_y = (1 - mouse_y) * 0.5 * winHeight
# 调用事件处理器
if hasattr(self, 'event_handler'):
self.event_handler.mouseMoveEvent({
'x': window_x,
'y': window_y
})
except Exception as e:
print(f"处理鼠标移动事件失败: {e}")
def onPatrolKeyPressed(self): def onPatrolKeyPressed(self):
"""处理 P 键按下事件 - 控制巡检系统""" """处理 P 键按下事件 - 控制巡检系统"""
try: try:
@ -904,15 +1008,7 @@ class MyWorld(CoreWorld):
imgui.separator() imgui.separator()
imgui.same_line() imgui.same_line()
# 其他工具按钮 # 工具按钮已移除(导入、保存、播放)
if imgui.button("导入"):
print("导入模型")
imgui.same_line()
if imgui.button("保存"):
print("保存场景")
imgui.same_line()
if imgui.button("播放"):
print("播放动画")
def _draw_scene_tree(self): def _draw_scene_tree(self):
"""绘制场景树面板""" """绘制场景树面板"""
@ -4944,6 +5040,32 @@ class MyWorld(CoreWorld):
print(f"ImGui界面检测失败: {e}") print(f"ImGui界面检测失败: {e}")
return False return False
def processImGuiMouseClick(self, x, y):
"""处理ImGui鼠标点击事件返回是否消费了该事件"""
try:
# ImGui优先策略如果ImGui想要捕获鼠标则由ImGui处理
if hasattr(imgui, 'get_io') and imgui.get_io().want_capture_mouse:
return True
# 检查是否有任何ImGui窗口悬停
try:
if imgui.is_any_window_hovered():
return True
except AttributeError:
# 如果方法不存在,跳过这个检查
pass
# 检查鼠标是否在ImGui界面区域内
if self._is_mouse_over_imgui():
return True
# 如果以上条件都不满足则让3D场景处理该事件
return False
except Exception as e:
print(f"ImGui鼠标点击处理失败: {e}")
return False
# ==================== 消息系统 ==================== # ==================== 消息系统 ====================
def add_message(self, text, color=(1.0, 1.0, 1.0, 1.0)): def add_message(self, text, color=(1.0, 1.0, 1.0, 1.0)):