From b8e84c7aa5f1d80d2900317939cd2ef6161bda5e Mon Sep 17 00:00:00 2001 From: tianmo Date: Fri, 16 Oct 2026 18:47:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=81=9C=E7=94=A8=20grabScrollFocus=EF=BC=9A?= =?UTF-8?q?=E5=AE=83=E6=8A=8A=E5=88=97=E8=A1=A8=E7=9A=84=20ScrollPane=20?= =?UTF-8?q?=E5=BD=93=20Stage.addActor=20=E7=9A=84=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E4=BC=A0=E8=BF=9B=E5=8E=BB=EF=BC=8C=E5=AF=BC=E8=87=B4=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E8=A2=AB=E6=90=AC=E5=87=BA=E9=9D=A2=E6=9D=BF=E7=94=BB?= =?UTF-8?q?=E5=88=B0=E7=AA=97=E5=8F=A3=E5=B7=A6=E4=B8=8B=E8=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:点过面板按钮后,列表(Inspector 114 行)画在窗口左下角一小块里,面板中段只剩红/绿描边。 原因(探针实测 pid 59699): - 面板根表格只剩 2 个子控件(按钮块 + 日志 Label),ScrollPane 不见了; - ScrollPane 的父级变成 do[0,0,0x0](Stage 根),绝对坐标 (57,824); - grabScrollFocus 在 Stage 上找「1 个 Actor 参数 + void」当 setScrollFocus, 只排除 dl/do/eX;但编辑器的 Stage 类 dt **自己声明** D(Ldl;)V(字节码 = root.addActor), 于是唯一候选就是 addActor,被 invoke 后 Group.addActor 先把 ScrollPane 摘下来再挂到 Stage 根。 修复(用户选方案 B):不再调用 grabScrollFocus(滚动焦点本来就靠鼠标点列表拿到)。 复验(新进程 pid 60682,同一探针):root 子控件 = 3,ScrollPane 父级 = root, 绝对坐标 (2115,830) 回到停靠框内。 --- viewpanel/src/com/spineview/ObjectPanel.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/viewpanel/src/com/spineview/ObjectPanel.java b/viewpanel/src/com/spineview/ObjectPanel.java index 0d05f69..5a7ad23 100644 --- a/viewpanel/src/com/spineview/ObjectPanel.java +++ b/viewpanel/src/com/spineview/ObjectPanel.java @@ -820,12 +820,23 @@ public final class ObjectPanel { /** * 把编辑器的**滚动焦点**抢到面板的列表上(鼠标滚轮才会滚列表)。 * + * ⚠️ 2026-10-16 已停用(用户选方案 B):不再调用。原因见下面实测—— + * 它在 Stage 上找"1 个 Actor 参数 + void"的方法当 setScrollFocus,只排除了声明在 + * `dl`(Actor)/`do`(Group)/`eX`(WidgetGroup) 上的方法;可**编辑器的 Stage 类 `dt` + * 自己声明了** `D(Ldl;)V`(字节码就是 `root.addActor(actor)`,即 Stage.addActor), + * 于是它成了唯一候选被调用 → ScrollPane 被 Group.addActor 先摘下来再挂到 Stage 根, + * 坐标保留局部值 (57,824) → 整块列表(114 行)被画到**窗口左下角**, + * 被 ScrollPane 自己的裁剪框裁成 400x400 一小块(就是"列表里的 UI 跑到外面")。 + * 日志现场:`[panel] 没找到 setScrollFocus(候选 setter 1 个 / getter 0 个)`。 + * 实测焦点本来就是靠鼠标点一下列表拿到的,不需要这段。 + * * 识别方式(不猜名字、也不会误调 addActor): * - 只在 **Stage 自己声明的**方法里找(`uk`/`dt`/`lpt6` 这些层), * `addActor` 声明在 Group 上、不在这一层,所以不会被误选; * - 候选 setter = 「1 个参数是 Actor 类型、返回 void」;候选 getter = 「无参、返回 Actor 类型」; * - 调 setter 后看哪个 getter 变成了我们的面板 —— 那就是 setScrollFocus 那一对,日志会写出来。 */ + @SuppressWarnings("unused") static void grabScrollFocus(final State state) { try { Object stage = SceneObjects.global(state.loader, "uk"); @@ -1376,8 +1387,11 @@ public final class ObjectPanel { } try { ((Runnable) route[1]).run(); - Object st = LAST_STATE; - if (st instanceof State) grabScrollFocus((State) st); + // 这里以前会调 grabScrollFocus(state) 去抢滚动焦点。 + // 2026-10-16 停用:它会把列表的 ScrollPane 当成 Stage.addActor 的参数传进去, + // 结果 ScrollPane 被搬出面板、挂到 Stage 根,列表就画到窗口左下角去了 + // (证据:dt.D(Ldl;)V 的字节码 = root.addActor;探针实测 root 子控件只剩 2 个)。 + // 滚动焦点本来就靠鼠标点一下列表拿到,不需要这段。 } catch (Throwable error) { System.err.println("[panel] 动作失败: " + error); error.printStackTrace(System.err);