有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

原职

我想通过编程确定在当前窗口中从一个Swing组件(拥有焦点)到另一个Swing组件需要多少键盘笔划(不管是tab键还是箭头键)。每个笔划应增加1的距离;如果无法到达组件,则结果应为-1

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

public static int getFocusTraversalDistance( Component from, Component to )

天真地,我会从通过^{}获取Containerfrom开始。之后,我将使用^{}获取FocusTraversalPolicy,并分别使用^{}^{}循环组件

但是,我对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++;
    }
}

到目前为止,这似乎是可行的,但实际上不可聚焦的组件可能会产生奇怪的结果。{a6}表示“[…]所有组件从这个[^{}]方法返回true。”即使像JLabel这样的组件也返回true,尽管(AFAIK)它实际上无法获得焦点,而且^{}总是false

如果有人感兴趣,我可以设置一个带有完整功能测试套件的GitHub项目


共 (1) 个答案

  1. # 1 楼答案

    this question is related to Swing only, don't worry—any help is appreciated

    我已经说过这听起来是一个合理的方法。我唯一不确定的是,当您有多个嵌套面板时,该方法是否有效。或者,如果必须为每个容器保持获取焦点遍历策略,则至少可能会变得更复杂

    您可以尝试查看KeyboardFocusManager,看看它是否有帮助

    我唯一能想到的另一种方法是实际地对表单上的所有组件进行制表,并将每个组件添加到ArrayList。然后您的getFocusTraversalDistance(...)将使用ArrayList而不是FocusTraversalPolicy。当然,这有一个问题,组件实际上会获得焦点,并且可以调用focusGained/focusLost代码

    或者将这两种方法结合起来。也就是说,使用您的方法来使用焦点遍历策略,但仅在创建帧时使用此策略来构建ArrayList。然后您的getFocusTraversalDistance(...)可以引用ArrayList,这应该会使它更有效率