From e197a6883a7e7f0925bcfe2a88711c9b9a38739e Mon Sep 17 00:00:00 2001 From: tianmo Date: Fri, 16 Oct 2026 15:36:42 +0800 Subject: [PATCH] =?UTF-8?q?Spine=20View=20=E5=90=AF=E5=8A=A8=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=89=93=E5=BC=80=EF=BC=88=E7=AD=89=E4=BB=B7=20Views?= =?UTF-8?q?=20=E8=8F=9C=E5=8D=95=E5=8B=BE=E9=80=89=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E7=94=A8=E6=AF=8F=E6=AC=A1=E6=89=8B=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ViewInstaller.showView():面板 Actor 填好后调 Fx.D(us.spineView) —— 菜单 'Tree View' 的动作体就是 Fx.D(us.Tree)(og.java:23),是编辑器自己的'显示/停靠视图'入口。 - 为什么之前每次都要手点:视图可见状态写在 views.json,只有正常退出才落盘;而我们一直用 SIGTERM 杀编辑器进程,状态没写回去。启动时主动开一次就绕过了这个。 - 列表区仍按设计需要点一次 Refresh(面板是编辑器 UI 搭好之前就建的,那时场景树还是空的)。 --- .../src/com/spineview/ViewInstaller.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/viewpanel/src/com/spineview/ViewInstaller.java b/viewpanel/src/com/spineview/ViewInstaller.java index 168463c..d8a3d85 100644 --- a/viewpanel/src/com/spineview/ViewInstaller.java +++ b/viewpanel/src/com/spineview/ViewInstaller.java @@ -76,6 +76,7 @@ public final class ViewInstaller { field.setAccessible(true); field.set(view, panel); System.err.println("[view] 已把 Spine View 面板挂到视图 " + view); + showView(loader, view); return true; } System.err.println("[view] 视图枚举里找不到 Actor 字段"); @@ -85,6 +86,33 @@ public final class ViewInstaller { return false; } + /** + * 像 Views 菜单那样把视图"打开"一次,这样面板不用每次手动点开。 + * + * 菜单里 "Tree View" 的动作体就一句:`Fx.D(us.Tree)`(`og.java:23`), + * `Fx` 是编辑器里那个静态 Actor 锚点类,`D(Object)` 就是"显示/停靠这个视图"。 + * 面板的可见状态本来就会写进 `views.json`,但只有正常退出才会写;我们一直用 + * SIGTERM 杀进程,所以每次都得手动点 —— 这里启动时主动开一次即可。 + */ + private static void showView(ClassLoader loader, Object view) { + try { + Class fx = Class.forName("Fx", true, loader); + for (Method method : fx.getDeclaredMethods()) { + if (!java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue; + Class[] parameters = method.getParameterTypes(); + if (parameters.length != 1) continue; + if (!parameters[0].isAssignableFrom(view.getClass())) continue; + method.setAccessible(true); + method.invoke(null, view); + System.err.println("[view] 已自动打开 Spine View(等价于 Views 菜单里勾选)"); + return; + } + System.err.println("[view] Fx 上没找到打开视图的方法,跳过自动打开"); + } catch (Throwable error) { + System.err.println("[view] 自动打开视图失败: " + error); + } + } + /** Skin 挂在 OG 的静态字段上(字节码里 OG 有 LSkin;D)。 */ private static Object findSkin(ClassLoader loader) throws Exception { Class holder = Class.forName("OG", true, loader);