让鼠标滚轮能滚列表:把列表 ScrollPane 的 touchable 从默认 childrenOnly 改成 enabled(无参返回枚举的方法=getTouchable,枚举 dv 第0常量=enabled)
- 诊断证据:程序化 scrollY(200) 生效(before=0 after=200),说明可滚范围没问题, 是滚轮事件没送到面板 —— 因为 childrenOnly 时 ScrollPane 自己不是命中目标,收不到 enter、 也就不会 setScrollFocus。 - 顺带把这条 Actor/Touchable 映射写进 anchors.tsv + names.tsv。
This commit is contained in:
1 parent
d59287937d
commit
13bce4509d
3 files changed
+73
No files matched your search
@@ -87,3 +87,9 @@ dR S (F)LdR; minWidth
|
|||||||
dR C (F)LdR; minHeight
|
dR C (F)LdR; minHeight
|
||||||
dR Z (F)LdR; prefWidth
|
dR Z (F)LdR; prefWidth
|
||||||
dR V (F)LdR; prefHeight
|
dR V (F)LdR; prefHeight
|
||||||
|
# ---- Actor 的 Touchable(点击/进入命中相关;用于让 ScrollPane 收到鼠标进入→拿到 scroll focus)----
|
||||||
|
# 定位方式(不靠名字):`Actor.getTouchable()` = **无参且返回枚举**的那个方法;枚举类 = dv;
|
||||||
|
# libGDX Touchable 声明顺序 enabled/disabled/childrenOnly → 第 0 个常量就是 enabled。
|
||||||
|
# 现象佐证:ScrollPane 默认 childrenOnly 时自己不是命中目标,收不到 enter → 滚轮事件不会送到它,
|
||||||
|
# 但程序化 scrollY() 是生效的(实测 before=0 after=200)。
|
||||||
|
dl L (Ldv;)V setTouchable
|
||||||
|
Can't render this file because it contains an unexpected character in line 72 and column 99.
|
@@ -143,6 +143,7 @@ dl I ()Z isTouchable
|
|||||||
dl L ()V clear
|
dl L ()V clear
|
||||||
dl L ()Z hasParent
|
dl L ()Z hasParent
|
||||||
dl L (Ldn;)Z addCaptureListener
|
dl L (Ldn;)Z addCaptureListener
|
||||||
|
dl L (Ldv;)V setTouchable
|
||||||
dl S (FF)V setOrigin
|
dl S (FF)V setOrigin
|
||||||
dl S (Lde;)Lde; localToStageCoordinates
|
dl S (Lde;)Lde; localToStageCoordinates
|
||||||
dl V ()V toBack
|
dl V ()V toBack
|
||||||
|
|||||||
|
@@ -84,6 +84,7 @@ public final class ObjectPanel {
|
|||||||
call(state.listTable, Obf.TABLE_LEFT, new Class<?>[0], tableClass);
|
call(state.listTable, Obf.TABLE_LEFT, new Class<?>[0], tableClass);
|
||||||
Object scroll = scrollClass.getConstructor(actorClass, skinClass).newInstance(state.listTable, skin);
|
Object scroll = scrollClass.getConstructor(actorClass, skinClass).newInstance(state.listTable, skin);
|
||||||
state.listScroll = scroll;
|
state.listScroll = scroll;
|
||||||
|
makeTouchable(scroll);
|
||||||
state.status = label(loader, skin, "Ready. Press Refresh to list scene objects.");
|
state.status = label(loader, skin, "Ready. Press Refresh to list scene objects.");
|
||||||
Object logScroll = null;
|
Object logScroll = null;
|
||||||
state.nameField = fieldClass.getConstructor(String.class, skinClass)
|
state.nameField = fieldClass.getConstructor(String.class, skinClass)
|
||||||
@@ -537,6 +538,64 @@ public final class ObjectPanel {
|
|||||||
state.logBlockStarted = false;
|
state.logBlockStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把 ScrollPane 的 touchable 设成 `enabled`(它默认是 childrenOnly)。
|
||||||
|
*
|
||||||
|
* 为什么:ScrollPane 是靠自己的 InputListener 在鼠标"进入"时调 `Stage.setScrollFocus(this)`
|
||||||
|
* 来接收滚轮的;childrenOnly 时它自己不是命中目标,就永远收不到 enter → 滚轮事件不会送到它,
|
||||||
|
* 表现就是"面板能程序化滚动,但鼠标滚轮没用"。
|
||||||
|
*
|
||||||
|
* 不靠名字定位:`Actor.getTouchable()` 是"**无参 + 返回枚举**"的那个方法;枚举第 0 个常量
|
||||||
|
* 就是 `Touchable.enabled`(libGDX 的声明顺序 enabled/disabled/childrenOnly)。
|
||||||
|
*/
|
||||||
|
static void makeTouchable(Object actor) {
|
||||||
|
try {
|
||||||
|
Class<?> enumType = null;
|
||||||
|
for (Method method : actor.getClass().getMethods()) {
|
||||||
|
if (method.getParameterTypes().length != 0) continue;
|
||||||
|
Class<?> returns = method.getReturnType();
|
||||||
|
if (!returns.isEnum()) continue;
|
||||||
|
enumType = returns;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (enumType == null) {
|
||||||
|
System.err.println("[panel] 找不到 Touchable 枚举,跳过");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object[] constants = enumType.getEnumConstants();
|
||||||
|
if (constants == null || constants.length == 0) return;
|
||||||
|
Object enabled = constants[0];
|
||||||
|
for (Method method : actor.getClass().getMethods()) {
|
||||||
|
Class<?>[] types = method.getParameterTypes();
|
||||||
|
if (types.length != 1 || types[0] != enumType) continue;
|
||||||
|
if (method.getReturnType() != void.class) continue;
|
||||||
|
method.setAccessible(true);
|
||||||
|
method.invoke(actor, enabled);
|
||||||
|
System.err.println("[panel] ScrollPane.touchable = " + enabled
|
||||||
|
+ "(枚举 " + enumType.getName() + " 第 0 个常量)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.err.println("[panel] 找不到 setTouchable");
|
||||||
|
} catch (Throwable error) {
|
||||||
|
System.err.println("[panel] 设置 touchable 失败: " + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float readFloat(Object target, String name) {
|
||||||
|
try {
|
||||||
|
for (Method method : target.getClass().getMethods()) {
|
||||||
|
if (!method.getName().equals(name)) continue;
|
||||||
|
if (method.getParameterTypes().length != 0) continue;
|
||||||
|
if (method.getReturnType() != float.class) continue;
|
||||||
|
method.setAccessible(true);
|
||||||
|
return ((Float) method.invoke(target)).floatValue();
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
// 读不到就返回 -1
|
||||||
|
}
|
||||||
|
return -1f;
|
||||||
|
}
|
||||||
|
|
||||||
private static void invalidateList(final State state) {
|
private static void invalidateList(final State state) {
|
||||||
try {
|
try {
|
||||||
call(state.listTable, "b_", new Class<?>[0], void.class);
|
call(state.listTable, "b_", new Class<?>[0], void.class);
|
||||||
@@ -563,6 +622,13 @@ public final class ObjectPanel {
|
|||||||
// 再打开"强制纵向滚动":setForceScroll 在载荷里叫 `I`((ZZ)V,指纹确认 ~2/3)
|
// 再打开"强制纵向滚动":setForceScroll 在载荷里叫 `I`((ZZ)V,指纹确认 ~2/3)
|
||||||
call(state.listScroll, "I", new Class<?>[] {boolean.class, boolean.class}, void.class,
|
call(state.listScroll, "I", new Class<?>[] {boolean.class, boolean.class}, void.class,
|
||||||
Boolean.FALSE, Boolean.TRUE);
|
Boolean.FALSE, Boolean.TRUE);
|
||||||
|
// 诊断(只读+可回滚):读一下当前滚动位置,再程序化滚 200,再读一次。
|
||||||
|
// before/after 都写日志:如果 after 还是 0 → 说明 ScrollPane 认为"内容装得下"(高度没测到);
|
||||||
|
// 如果 after 变成 200 → 说明面板能滚,是滚轮事件没送到面板。
|
||||||
|
float before = readFloat(state.listScroll, "invoke");
|
||||||
|
call(state.listScroll, "Class", new Class<?>[] {float.class}, void.class, Float.valueOf(200f));
|
||||||
|
float after = readFloat(state.listScroll, "invoke");
|
||||||
|
System.err.println("[panel] scroll diag: before=" + before + " after=" + after);
|
||||||
} catch (Throwable error) {
|
} catch (Throwable error) {
|
||||||
System.err.println("[panel] 恢复滚动失败: " + error);
|
System.err.println("[panel] 恢复滚动失败: " + error);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user