From dc150f793bf13f565fc686135af8a01e88f1f854 Mon Sep 17 00:00:00 2001 From: Hector <2055590199@qq.com> Date: Wed, 20 Aug 2025 16:36:19 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=9D=90=E6=A0=87=E8=BD=B4=E9=A2=9C=E8=89=B2?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E4=BD=86=E9=9C=80=E7=BB=A7=E7=BB=AD=E6=9B=B4?= =?UTF-8?q?=E6=94=B9sort=202.=E6=8B=96=E6=8B=BD=E7=BB=93=E6=9D=9F=E5=90=8E?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=8F=AF=E8=A7=81=E6=80=A7=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/TranslateArrowHandle.fbx | Bin 0 -> 49692 bytes core/selection.py | 501 ++++++++++++---------------------- ui/widgets.py | 1 + 3 files changed, 177 insertions(+), 325 deletions(-) create mode 100755 core/TranslateArrowHandle.fbx diff --git a/core/TranslateArrowHandle.fbx b/core/TranslateArrowHandle.fbx new file mode 100755 index 0000000000000000000000000000000000000000..297256501b3da663344a4ccd8a988a2e5e30319d GIT binary patch literal 49692 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 HhUEVbfwn*L literal 0 HcmV?d00001 diff --git a/core/selection.py b/core/selection.py index 5d28830b..ecbbe5c4 100644 --- a/core/selection.py +++ b/core/selection.py @@ -11,7 +11,7 @@ from PIL.ImageChops import lighter from panda3d.core import (Vec3, Point3, Point2, LineSegs, ColorAttrib, RenderState, DepthTestAttrib, CollisionTraverser, CollisionHandlerQueue, CollisionNode, CollisionRay, GeomNode, BitMask32, Material, LColor, DepthWriteAttrib, - TransparencyAttrib) + TransparencyAttrib, Vec4) from direct.task.TaskManagerGlobal import taskMgr import math @@ -50,14 +50,14 @@ class SelectionSystem: # 高亮相关 self.gizmoHighlightAxis = None self.gizmo_colors = { - "x": (1*10, 0, 0, 1), # 红色 - "y": (0, 1*10, 0, 1), # 绿色 - "z": (0, 0, 1*10, 1) # 蓝色 + "x": (1, 0, 0, 0), # 红色 + "y": (0, 1, 0, 0), # 绿色 + "z": (0, 0, 1, 0) # 蓝色 } self.gizmo_highlight_colors = { - "x": (1.5*20, 1.5*20, 0, 1), # 黄色高亮 - "y": (1.5*20, 1.5*20, 0, 1), # 黄色高亮 - "z": (1.5*20, 1.5*20, 0, 1) # 黄色高亮 + "x": (1, 1, 0, 0), # 黄色高亮 + "y": (1, 1, 0, 0), # 黄色高亮 + "z": (1, 1, 0, 0) # 黄色高亮 } print("✓ 选择和变换系统初始化完成") @@ -303,7 +303,7 @@ class SelectionSystem: # 只调用一次几何体创建 self.createGizmoGeometry() - # 只调用一次颜色设置 + #只调用一次颜色设置 self.setGizmoAxisColor("x", self.gizmo_colors["x"]) self.setGizmoAxisColor("y", self.gizmo_colors["y"]) self.setGizmoAxisColor("z", self.gizmo_colors["z"]) @@ -322,321 +322,79 @@ class SelectionSystem: if not self.gizmo: return - # 创建X轴(红色) - x_lines = LineSegs("x_axis") - x_lines.setThickness(6.0) - x_lines.moveTo(0, 0, 0) - x_lines.drawTo(self.axis_length, 0, 0) - # 创建X轴箭头 - x_lines.moveTo(self.axis_length - 0.5, -0.2, 0) - x_lines.drawTo(self.axis_length, 0, 0) - x_lines.drawTo(self.axis_length - 0.5, 0.2, 0) - x_geom = x_lines.create() - self.gizmoXAxis = self.gizmo.attachNewNode(x_geom) - self.gizmoXAxis.setName("gizmo_x_axis") - #self.gizmoXAxis.setLightOff() - # 创建Y轴(绿色) - y_lines = LineSegs("y_axis") - y_lines.setThickness(6.0) - y_lines.moveTo(0, 0, 0) - y_lines.drawTo(0, self.axis_length, 0) - # 创建Y轴箭头 - y_lines.moveTo(-0.2, self.axis_length - 0.5, 0) - y_lines.drawTo(0, self.axis_length, 0) - y_lines.drawTo(0.2, self.axis_length - 0.5, 0) - y_geom = y_lines.create() - self.gizmoYAxis = self.gizmo.attachNewNode(y_geom) - self.gizmoYAxis.setName("gizmo_y_axis") - #self.gizmoYAxis.setLightOff() + model_paths = [ + "core/TranslateArrowHandle.fbx", + "EG/core/TranslateArrowHandle.fbx", + ] + arrow_model = None + for path in model_paths: + try: + arrow_model = self.world.loader.loadModel(path) + if arrow_model: + print(f"成功加载模型: {path}") + break + except: + continue + self.gizmoXAxis = self.gizmo.attachNewNode("gizmo_x_axis") + x_arrow = arrow_model.copyTo(self.gizmoXAxis) + x_arrow.setName("x_arrow") + x_arrow.setHpr(0,-90,0) + x_arrow.setScale(0.1,0.05,0.05) + x_arrow.setPos(0,0,0) + + self.gizmoYAxis = self.gizmo.attachNewNode("gizmo_y_axis") + y_arrow = arrow_model.copyTo(self.gizmoYAxis) + y_arrow.setName("y_arrow") + y_arrow.setHpr(90,0,0) + y_arrow.setScale(0.1,0.05,0.05) + y_arrow.setPos(0,0,0) # 创建Z轴(蓝色) - z_lines = LineSegs("z_axis") - z_lines.setThickness(6.0) - z_lines.moveTo(0, 0, 0) - z_lines.drawTo(0, 0, self.axis_length) - # 创建Z轴箭头 - z_lines.moveTo(-0.2, 0, self.axis_length - 0.5) - z_lines.drawTo(0, 0, self.axis_length) - z_lines.drawTo(0.2, 0, self.axis_length - 0.5) - z_geom = z_lines.create() - self.gizmoZAxis = self.gizmo.attachNewNode(z_geom) - self.gizmoZAxis.setName("gizmo_z_axis") - #self.gizmoZAxis.setLightOff() + self.gizmoZAxis = self.gizmo.attachNewNode("gizmo_z_axis") + z_arrow = arrow_model.copyTo(self.gizmoZAxis) + z_arrow.setName("z_arrow") + # 旋转箭头使其指向Z轴正方向 + z_arrow.setHpr(0, 0, -90) # 根据需要调整旋转 + z_arrow.setScale(0.1,0.05,0.05) + z_arrow.setPos(0, 0, 0) - # 确保坐标轴不被光照影响 - #self.gizmo.setLightOff() - - # 使用最强的渲染设置,确保坐标轴绝对不会被遮挡 - self.gizmo.setBin("gui-popup", 0) # 使用最高的GUI渲染层 - self.gizmo.setDepthTest(False) # 完全禁用深度测试 - self.gizmo.setDepthWrite(False) # 禁用深度写入 - self.gizmo.setTwoSided(True) # 双面渲染 - - # 创建强制前景渲染状态 - from panda3d.core import RenderModeAttrib, TransparencyAttrib - foreground_state = RenderState.make( - DepthTestAttrib.make(DepthTestAttrib.MNone), # 完全不进行深度测试 - TransparencyAttrib.make(TransparencyAttrib.MAlpha) # 启用透明度混合 - ) - #self.gizmo.setState(foreground_state) - - # 对每个坐标轴设置独立的最高渲染优先级 - self.gizmoXAxis.setBin("gui-popup", 10) - self.gizmoXAxis.setDepthTest(False) - self.gizmoXAxis.setDepthWrite(False) - self.gizmoXAxis.setLightOff() - self.gizmoXAxis.setState(foreground_state) - - self.gizmoYAxis.setBin("gui-popup", 20) - self.gizmoYAxis.setDepthTest(False) - self.gizmoYAxis.setDepthWrite(False) - self.gizmoYAxis.setLightOff() - self.gizmoYAxis.setState(foreground_state) - - self.gizmoZAxis.setBin("gui-popup", 30) - self.gizmoZAxis.setDepthTest(False) - self.gizmoZAxis.setDepthWrite(False) - self.gizmoZAxis.setLightOff() - self.gizmoZAxis.setState(foreground_state) - - - - # 初始化高亮状态 - self.gizmoHighlightAxis = None - - # 立即设置初始颜色,确保创建时就有正确的颜色 - self.setGizmoAxisColor("z", self.gizmo_colors["z"]) + # 设置初始颜色 self.setGizmoAxisColor("x", self.gizmo_colors["x"]) self.setGizmoAxisColor("y", self.gizmo_colors["y"]) + self.setGizmoAxisColor("z", self.gizmo_colors["z"]) + + # 使用最强的渲染设置,确保坐标轴绝对不会被遮挡 + # self.gizmo.setBin("default", 0) # 使用最高的GUI渲染层 + # self.gizmo.setDepthTest(True) # 完全禁用深度测试 + # self.gizmo.setDepthWrite(True) # 禁用深度写入 + # self.gizmo.setTwoSided(True) # 双面渲染 - print(f"✓ 坐标轴几何体创建完成,长度={self.axis_length}") - - # 为 RenderPipeline 环境设置正确的渲染状态 - self._setupRenderPipelineCompatibleGizmo() - - self._setupEmissiveMaterials() - self._setupGizmoRendering() except Exception as e: print(f"创建坐标轴几何体失败: {str(e)}") - def _setupEmissiveMaterials(self): - try: - from panda3d.core import Material,Vec4 - materials ={ - "x":(Vec4(1,0,0,1),Vec4(2.0,0,0,1)), - "y":(Vec4(0,1,0,1),Vec4(0,2.0,0,1)), - "z":(Vec4(0,0,1,1),Vec4(0,0,2.0,1)) - } - axis_nodes ={ - "x":self.gizmoXAxis, - "y":self.gizmoYAxis, - "z":self.gizmoZAxis - } - for axis,(base_color,emission_color) in materials.items(): - if axis_nodes[axis]: - material=Material(f"gizmo_{axis}_material") - material.setBaseColor(base_color) - material.setEmission(emission_color) - material.setRoughness(1.0) - material.setMetallic(0.0) - axis_nodes[axis].setMaterial(material) - except Exception as e: - print(f"自发光材质设置失败: {str(e)}") + def _applyAxisMaterial(self, node, color): + from panda3d.core import Material, Vec4, ColorWriteAttrib, DepthWriteAttrib + # 构造一个“自发光”的材质,让颜色不依赖灯光/法线 + m = Material() + col = Vec4(*color) + m.setBaseColor(col) # 记录用 + m.setDiffuse(col) # 记录用(RP标准材质可能不读取) + m.setEmission(Vec4(col.x, col.y, col.z, 1.0)) # 关键:用发光通道显示颜色 + node.setMaterial(m, 1) - def _setupGizmoRendering(self): - """设置坐标轴渲染属性""" - try: - # 设置渲染优先级,确保在最前面显示 - self.gizmo.setBin("gui-popup", 1000) - self.gizmo.setDepthTest(False) - self.gizmo.setDepthWrite(False) - self.gizmo.setLightOff() + # 走能直接写到最终画面的阶段(两种方式二选一): + # 方式1:完全绕过管线(最稳) + node.setTag("pipeline-disable", "1") + # 方式2:留在管线内但走最终阶段(若不想禁用管线,可改用下面这一行,并去掉上一行) + # node.setTag("pipeline-stage", "final") - # 为每个轴设置独立的渲染属性 - for i, axis_node in enumerate([self.gizmoXAxis, self.gizmoYAxis, self.gizmoZAxis]): - if axis_node: - axis_node.setBin("gui-popup", 1001 + i) - axis_node.setDepthTest(False) - axis_node.setDepthWrite(False) - axis_node.setLightOff() - - except Exception as e: - print(f"设置坐标轴渲染失败!!!!!!: {str(e)}") - - def _setupRenderPipelineCompatibleGizmo(self): - """为 RenderPipeline 环境设置兼容的坐标轴渲染 - 激进修复版本""" - try: - from panda3d.core import (ShaderAttrib, MaterialAttrib, RenderModeAttrib, - AntialiasAttrib, TransparencyAttrib, CullFaceAttrib, - RescaleNormalAttrib, TextureAttrib) - - # 第一步:完全隔离坐标轴,避免被任何系统处理 - self._isolateGizmoFromRenderPipeline() - - # 第二步:使用最简单的渲染方式 - self._setupMinimalGizmoRendering() - - # 第三步:强制设置每个轴的独立渲染 - self._forceAxisIndependentRendering() - - - except Exception as e: - # 使用最后的备用方案 - self._setupUltimateGizmoFallback() - - def _isolateGizmoFromRenderPipeline(self): - """完全隔离坐标轴,避免被 RenderPipeline 处理""" - try: - # 设置所有可能的隔离标签 - isolation_tags = [ - ("no_shadow", "1"), - ("no_lighting", "1"), - ("no_material", "1"), - ("no_shader", "1"), - ("no_fog", "1"), - ("no_texture", "1"), - ("gui_element", "1"), - ("bypass_rp", "1"), - ("fixed_pipeline", "1"), - ("ignore_all", "1") - ] - - for tag, value in isolation_tags: - self.gizmo.setTag(tag, value) - - # 完全禁用所有高级功能,使用最高优先级 - self.gizmo.setShaderOff(10000) - self.gizmo.setLightOff(10000) - self.gizmo.setFogOff(10000) - self.gizmo.setMaterialOff(10000) - self.gizmo.setTextureOff(10000) - - # 禁用所有可能的渲染特性 - from panda3d.core import RenderModeAttrib, CullFaceAttrib - # self.gizmo.setRenderModeWireframe() - # self.gizmo.setTwoSided(True) - self.gizmo.setRenderMode(RenderModeAttrib.MFilled) - self.gizmo.setTwoSided(True) - - self.gizmo.setColorScale(2.0,2.0,2.0,1.0) - for axis_node in [self.gizmoXAxis,self.gizmoYAxis,self.gizmoZAxis]: - if axis_node: - axis_node.setTag("emissive","1") - axis_node.setTag("unlit","1") - axis_node.setColorScale(2.0,2.0,2.0,1.0) - - except Exception as e: - print(f" ❌ 隔离失败: {e}") - - def _setupMinimalGizmoRendering(self): - """设置最简单的渲染方式""" - try: - from panda3d.core import (ShaderAttrib, MaterialAttrib, TextureAttrib, - CullFaceAttrib, RescaleNormalAttrib) - - # 使用最高优先级的 GUI 渲染 bin - self.gizmo.setBin("gui-popup", 10000) - self.gizmo.setDepthTest(False) - self.gizmo.setDepthWrite(False) - - # 创建最简单的渲染状态 - minimal_state = RenderState.make( - ShaderAttrib.makeOff(10000), # 完全禁用着色器 - MaterialAttrib.makeOff(), # 禁用材质 - TextureAttrib.makeOff(), # 禁用纹理 - CullFaceAttrib.make(CullFaceAttrib.MCullNone), # 禁用面剔除 - RescaleNormalAttrib.makeOff() # 禁用法线重缩放 - ) - self.gizmo.setState(minimal_state, 10000) - - except Exception as e: - print(f" ❌ 最简渲染设置失败: {e}") - - def _forceAxisIndependentRendering(self): - """强制设置每个轴的独立渲染""" - try: - # 轴配置 - axis_configs = [ - (self.gizmoXAxis, "X轴", (1.0, 0.0, 0.0, 1.0), 0), - (self.gizmoYAxis, "Y轴", (0.0, 1.0, 0.0, 1.0), 0), - (self.gizmoZAxis, "Z轴", (0.0, 0.0, 1.0, 1.0), 0) - ] - - for axis_node, name, color, priority in axis_configs: - if axis_node: - # 每个轴都完全独立设置 - self._setupSingleAxisRendering(axis_node, name, color, 0) - - - except Exception as e: - print(f" ❌ 独立轴渲染设置失败: {e}") - - def _setupSingleAxisRendering(self, axis_node, name, color, priority): - """为单个轴设置完全独立的渲染""" - try: - from panda3d.core import (LVecBase4f, RenderState, ColorAttrib, - TransparencyAttrib, LColor, AntialiasAttrib, - RenderModeAttrib, CullFaceAttrib, AuxBitplaneAttrib, - LightRampAttrib) - - # 转换颜色为LColor并增加亮度 - base_color = LColor(*color) - emissive_color = LColor(base_color[0], base_color[1], base_color[2], 1.0) - - # 完全禁用所有高级渲染功能 - axis_node.clearShader() - axis_node.clearTexture() - axis_node.clearMaterial() - axis_node.setLightOff() - axis_node.setFogOff() - axis_node.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 6.0)) - axis_node.setAttrib(AntialiasAttrib.make(AntialiasAttrib.MLine)) - axis_node.setBin("gui-popup", 0) - axis_node.setDepthTest(False) - axis_node.setDepthWrite(False) - axis_node.setTwoSided(True) - - # 强制设置自发光颜色 - axis_node.setColor(*color) - axis_node.setColorScale(1.0, 1.0, 1.0, 1.0) # 增加整体亮度 - - except Exception as e: - print(" ❌ {} 轴渲染设置失败: {}".format(name, str(e))) - raise e - - def _setupUltimateGizmoFallback(self): - """最后的备用方案 - 最简单的渲染""" - try: - # 最简单的设置 - self.gizmo.setLightOff() - self.gizmo.setFogOff() - self.gizmo.setBin("gui-popup", 20000) - self.gizmo.setDepthTest(False) - self.gizmo.setDepthWrite(False) - - # 直接设置颜色,不使用复杂的渲染状态 - if self.gizmoXAxis: - self.gizmoXAxis.setColor(1, 0, 0, 1) - self.gizmoXAxis.setLightOff() - self.gizmoXAxis.setBin("gui-popup", 20001) - self.gizmoXAxis.setDepthTest(False) - - if self.gizmoYAxis: - self.gizmoYAxis.setColor(0, 1, 0, 1) - self.gizmoYAxis.setLightOff() - self.gizmoYAxis.setBin("gui-popup", 20002) - self.gizmoYAxis.setDepthTest(False) - - if self.gizmoZAxis: - self.gizmoZAxis.setColor(0, 0, 1, 1) - self.gizmoZAxis.setLightOff() - self.gizmoZAxis.setBin("gui-popup", 20003) - self.gizmoZAxis.setDepthTest(False) - - except Exception as e: - print(f"❌ 最后备用方案也失败: {e}") + # 可见性状态:允许颜色写入,不写深度,双面可见,禁用雾 + node.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_all)) + node.setAttrib(DepthWriteAttrib.make(False)) + node.setTwoSided(True) + node.setFogOff() def updateGizmoTask(self, task): """坐标轴更新任务 - 包含固定大小功能""" @@ -791,34 +549,127 @@ class SelectionSystem: self.gizmoStartPos = None - def setGizmoAxisColor(self, axis, color): - """设置坐标轴颜色 - RenderPipeline 兼容版本""" - try: - from panda3d.core import AntialiasAttrib,TransparencyAttrib + # def setGizmoAxisColor(self, axis, color): + # """设置坐标轴颜色 - RenderPipeline 兼容版本""" + # try: + # from panda3d.core import AntialiasAttrib,TransparencyAttrib + # + # axis_nodes = { + # "x": self.gizmoXAxis, + # "y": self.gizmoYAxis, + # "z": self.gizmoZAxis + # } + # + # if axis in axis_nodes and axis_nodes[axis]: + # axis_node = axis_nodes[axis] + # + # axis_node.setColor(color[0]*20.0,color[1]*20.0,color[2]*20.0,color[3]) + # axis_node.setColorScale(color[0]*10.0,color[1]*10.0,color[2]*10.0,color[3]) + # axis_node.setShaderOff(10000) + # axis_node.setLightOff() + # axis_node.setMaterialOff() + # axis_node.setTextureOff() + # axis_node.setFogOff() + # + # except Exception as e: + # print(f"设置坐标轴颜色失败: {str(e)}") + # # 回退到简单的颜色设置 + # try: + # if axis in axis_nodes and axis_nodes[axis]: + # axis_nodes[axis].setColor(*color) + # except: + # pass + def setGizmoAxisColor(self, axis, color): + """使用材质设置坐标轴颜色 - RenderPipeline兼容版本""" + try: + from panda3d.core import Material, Vec4,ColorWriteAttrib,DepthWriteAttrib,DepthTestAttrib,TransparencyAttrib + + # 获取对应的轴节点 axis_nodes = { "x": self.gizmoXAxis, "y": self.gizmoYAxis, "z": self.gizmoZAxis } - if axis in axis_nodes and axis_nodes[axis]: - axis_node = axis_nodes[axis] + if axis not in axis_nodes or not axis_nodes[axis]: + return - axis_node.setColor(color[0]*20.0,color[1]*20.0,color[2]*20.0,color[3]) - axis_node.setColorScale(color[0]*20.0,color[1]*20.0,color[2]*20.0,color[3]) - axis_node.setShaderOff(10000) - axis_node.setLightOff(10000) - axis_node.setMaterialOff(10000) - axis_node.setTextureOff(1000) - axis_node.setFogOff(10000) + axis_node = axis_nodes[axis] + + # 查找箭头模型节点 + arrow_node = None + if axis == "x": + arrow_node = axis_node.find("x_arrow") + elif axis == "y": + arrow_node = axis_node.find("y_arrow") + elif axis == "z": + arrow_node = axis_node.find("z_arrow") + + if not arrow_node: + print(f"未找到{axis}轴的箭头模型") + return + + # 创建或获取材质 + mat = Material() + + # 设置材质属性 - 使用自发光确保在RenderPipeline下可见 + mat.setBaseColor(Vec4(color[0], color[1], color[2], color[3])) + mat.setDiffuse(Vec4(0, 0, 0, 1)) + #mat.setEmission(Vec4(color[0], color[1], color[2], 1.0)) # 自发光 + mat.setEmission(Vec4(1,1,1,1.0)) # 自发光 + mat.set_roughness(1) + + # 应用材质 + arrow_node.setMaterial(mat, 1) + + + # 设置透明度 + if color[3] < 1.0: + arrow_node.setTransparency(TransparencyAttrib.MAlpha) + else: + arrow_node.setTransparency(TransparencyAttrib.MNone) + + # 创建自定义渲染状态 - 确保始终在最前方 + # state = RenderState.make( + # ColorWriteAttrib.make(ColorWriteAttrib.CAll), # 允许颜色写入 + # DepthTestAttrib.make(DepthTestAttrib.MAlways), # 始终通过深度测试 + # DepthWriteAttrib.make(DepthWriteAttrib.MOff) # 不写入深度缓冲区 + # ) + # # 应用渲染状态 + # arrow_node.set_state(state) + + arrow_node.setLightOff() # 禁用光照影响 + arrow_node.setShaderOff() # 禁用着色器 + arrow_node.setFogOff() # 禁用雾效果 + arrow_node.setBin("fixed", 10) # 使用固定渲染顺序,确保在最前 + + # 保存材质引用以便后续修改 + if axis == "x": + self.xMat = mat + elif axis == "y": + self.yMat = mat + elif axis == "z": + self.zMat = mat + + axis_node.setLightOff() + axis_node.setShaderOff() + axis_node.setFogOff() + #axis_node.set_state(state) + axis_node.setBin("fixed", 9) # 确保轴节点在箭头模型之前渲染 except Exception as e: print(f"设置坐标轴颜色失败: {str(e)}") - # 回退到简单的颜色设置 + # 回退到简单颜色设置 try: + axis_nodes = { + "x": self.gizmoXAxis, + "y": self.gizmoYAxis, + "z": self.gizmoZAxis + } + if axis in axis_nodes and axis_nodes[axis]: - axis_nodes[axis].setColor(*color) + axis_nodes[axis].setColor(color[0], color[1], color[2], color[3]) except: pass diff --git a/ui/widgets.py b/ui/widgets.py index 9a1c5dc7..dcd1cc76 100644 --- a/ui/widgets.py +++ b/ui/widgets.py @@ -363,6 +363,7 @@ class CustomTreeWidget(QTreeWidget): # 更新属性面板 self.world.updatePropertyPanel(dragged_item) + self.world.property_panel._syncEffectiveVisibility(dragged_node) else: event.ignore()