diff --git a/viewpanel/src/com/spineview/ObjectPanel.java b/viewpanel/src/com/spineview/ObjectPanel.java index a509875..b6216a5 100644 --- a/viewpanel/src/com/spineview/ObjectPanel.java +++ b/viewpanel/src/com/spineview/ObjectPanel.java @@ -42,7 +42,7 @@ public final class ObjectPanel { Object nameField; final java.util.Deque log = new java.util.ArrayDeque(); boolean rendering; - Runnable logPanelRefresh; + boolean logBlockStarted; List objects = new ArrayList(); Object target; } @@ -112,12 +112,6 @@ public final class ObjectPanel { cell = call(root, Obf.TABLE_ADD, new Class[] {actorClass}, cellClass, scroll); layoutCell(cell, Obf.CELL_TOP, Obf.CELL_EXPAND, Obf.CELL_FILL); - state.logPanelRefresh = new Runnable() { - @Override - public void run() { - refreshList(state); - } - }; wire(loader, refresh, new Runnable() { @Override public void run() { @@ -188,13 +182,37 @@ public final class ObjectPanel { return root; } + /** 只往内容表格末尾追加**一行**日志(必要时先补一行分隔标记)。 */ + private static void appendLogRow(State state, String text) { + try { + Class cellClass = Class.forName(Obf.CELL, true, state.loader); + Class actorClass = Class.forName(Obf.ACTOR, true, state.loader); + if (!state.logBlockStarted) { + Object cell = call(state.listTable, Obf.TABLE_ADD, new Class[] {actorClass}, + cellClass, label(state.loader, state.skin, LOG_SEPARATOR)); + layoutCell(cell, Obf.CELL_LEFT); + call(state.listTable, Obf.TABLE_ROW, new Class[0], cellClass); + state.logBlockStarted = true; + } + Object cell = call(state.listTable, Obf.TABLE_ADD, new Class[] {actorClass}, + cellClass, label(state.loader, state.skin, text)); + layoutCell(cell, Obf.CELL_LEFT); + call(state.listTable, Obf.TABLE_ROW, new Class[0], cellClass); + invalidateList(state); + } catch (Throwable error) { + System.err.println("[panel] 日志行追加失败: " + error); + } + } + + private static final String LOG_SEPARATOR = "---------- log ----------"; + /** 在内容表格末尾追加"日志块"(分隔行 + 最近几条消息)。 */ private static void appendLogRows(State state) { try { Class cellClass = Class.forName(Obf.CELL, true, state.loader); Class actorClass = Class.forName(Obf.ACTOR, true, state.loader); Object cell = call(state.listTable, Obf.TABLE_ADD, new Class[] {actorClass}, - cellClass, label(state.loader, state.skin, "---------- log ----------")); + cellClass, label(state.loader, state.skin, LOG_SEPARATOR)); layoutCell(cell, Obf.CELL_LEFT); call(state.listTable, Obf.TABLE_ROW, new Class[0], cellClass); synchronized (state.log) { @@ -205,6 +223,7 @@ public final class ObjectPanel { call(state.listTable, Obf.TABLE_ROW, new Class[0], cellClass); } } + state.logBlockStarted = true; } catch (Throwable error) { System.err.println("[panel] 日志块追加失败: " + error); } @@ -242,6 +261,7 @@ public final class ObjectPanel { try { // Table.clearChildren()(载荷名 `SourceFile()V`):把列表里的行全清掉重建。 call(state.listTable, Obf.TABLE_CLEAR_CHILDREN, new Class[0], void.class); + state.logBlockStarted = false; Class cellClass = Class.forName(Obf.CELL, true, state.loader); Class actorClass = Class.forName(Obf.ACTOR, true, state.loader); for (int i = 0; i < objects.size() && i < 300; i++) { @@ -402,6 +422,7 @@ public final class ObjectPanel { private static void fillTextRows(final State state, List lines) { try { call(state.listTable, Obf.TABLE_CLEAR_CHILDREN, new Class[0], void.class); + state.logBlockStarted = false; Class cellClass = Class.forName(Obf.CELL, true, state.loader); Class actorClass = Class.forName(Obf.ACTOR, true, state.loader); for (String line : lines) { @@ -436,8 +457,8 @@ public final class ObjectPanel { state.log.addLast(text); while (state.log.size() > LOG_LINES) state.log.removeFirst(); } - // 没在渲染中就立刻把日志块刷出来(渲染中则由那次渲染带上,避免递归重排) - if (!state.rendering && state.logPanelRefresh != null) state.logPanelRefresh.run(); + // 只追加一行日志:千万不要在这里重跑列表渲染,否则 Inspect 写好的字段清单会被覆盖 + if (!state.rendering) appendLogRow(state, text); } /** TextField 里的文字(名字被混淆了,按"无参 + 返回 String"取)。 */