计算窗口内两个Swing组件的焦点遍历距离

bea*_*u13 9 java swing focus

原帖

我想以编程方式确定从当前窗口中的一个Swing组件(拥有焦点)转到另一个组件所需的键盘笔划数(无论是否有制表符和/或箭头键).每个笔画应增加1的距离; 如果无法访问该组件,则结果应为-1.

由于我无法找到实用方法,我想到了以下签名:

public static int getFocusTraversalDistance( Component from, Component to )
Run Code Online (Sandbox Code Playgroud)

天真,我刚刚接到启动Containerfrom通过getFocusCycleRootAncestor().然后,我将分别使用FocusTraversalPolicywith getFocusTraversalPolicy()和循环遍历组件.getComponentAfter(Container, Component)getComponentBefore(Container, Component)

但是,我不熟悉Swing/AWT焦点子系统,我想知道是否有更优雅的方式?

编辑#1

我需要这些信息的原因是我的硕士论文,我正在撰写.这个想法是通过机器学习来增强基于GUI的猴子测试.训练模型不是挑选随机组件,而是尝试根据历史用户/测试人员痕迹"推荐"组件.我正在使用的一个功能是前一个目标组件和一个可能的目标组件之间的焦点遍历距离.

编辑#2

感谢camickr的宝贵意见,我目前正在使用以下算法:

public static int getFocusTraversalDistance( Component from, Component to ) {
    if ( from.equals( to ) ) {
        return 0;
    }

    final Container root = from.getFocusCycleRootAncestor();

    if ( root == null ) {
        return -1;
    }

    final FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
    final HashSet<Component> visited = new HashSet<>();
    Component before = from;
    Component after = from;
    int distance = 1;

    while ( true ) {
        if ( before != null ) {
            visited.add( before );
            before = policy.getComponentBefore(
                    before.getFocusCycleRootAncestor(), before );
            if ( to.equals( before ) ) {
                return distance;
            }
        }

        if ( after != null ) {
            visited.add( after );
            after = policy.getComponentAfter(
                    after.getFocusCycleRootAncestor(), after );
            if ( to.equals( after ) ) {
                return distance;
            }
        }

        if ( before == null && after == null
                || visited.contains( before ) && visited.contains( after ) ) {
            return -1;
        }

        distance++;
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止似乎有效,但实际上不可聚焦的组件可能会产生奇怪的结果.该AWT焦点子系统DOC说:"[...]所有组件从这个[返回true Component#isFocusable()]的方法." 甚至像JLabel返回这样的组件true,虽然(AFAIK)它实际上无法获得焦点而且Component#hasFocus()总是如此false.

如果有人感兴趣,我可以使用功能齐全的测试套件设置GitHub项目.

cam*_*ckr 5

这个问题只与Swing有关,请不要担心 - 任何帮助都表示赞赏

我已经说过这听起来像是一种合理的方法.我不确定的唯一想法是,当你有多个嵌套面板时,这种方法会起作用.或者至少如果你必须继续获得每个容器的焦点遍历策略,它可能会变得更复杂.

您可以尝试查看KeyboardFocusManager它是否可以提供帮助.

我能想到的唯一其他方法是实际选中表单上的所有组件并将每个组件添加到ArrayList.然后你getFocusTraversalDistance(...)会使用ArrayList而不是FocusTraversalPolicy.当然,这有一个问题,即组件实际上会获得焦点,并且focusGained/ focusLostcode可以被调用.

或者可以将两种方法结合起来.这是使用您的方法来使用焦点遍历策略,但只有这样才能构建ArrayList创建帧的时间.然后你getFocusTraversalDistance(...)可以参考ArrayList,这应该使它更有效.