专注于容器中的下一个项目

Focus on next item in container

有没有一种方法可以在不直接调用特定组件的 requestFocus() method? This functionality would be similar to pressing the tab button to traverse focus between components where disabled 节点的情况下以编程方式关注容器中的下一个可聚焦节点。

没有 public 方法。 只有破解和解决方法。

您可以使用节点的

impl_traverse(Direction.NEXT);

方法。但是这个已被弃用,可以随时删除,并且您的代码会因新的 java 版本而中断。

或者,您可以捕获回车键并触发 Tab 键事件。但这同样丑陋。

或者如果您在文本字段中,您可以这样做:

if( textfield.getSkin() instanceof BehaviorSkinBase) {
    ((BehaviorSkinBase) textfield.getSkin()).getBehavior().traverseNext();  
}

但这也不鼓励,因为它不是 api。

即使您像这样使用反射来访问场景的遍历方法:

Method[] allMethods = scene.getClass().getDeclaredMethods();
for (Method m : allMethods) {
    String mname = m.getName();
    if (mname.startsWith("traverse")) {
        m.setAccessible(true);
        m.invoke(scene, new Object[] { textfield, Direction.NEXT });
    }
}

你最终不得不提供一个方向参数,这也是不鼓励的。

你能做的最好的事情就是comment and vote on this issue

根据您的用例,您还可以过滤并将 Enter 键转换为父窗格中的 Tab

@Override
public void start( final Stage primaryStage )
{
    TextField field1 = new TextField();
    TextField field2 = new TextField();
    TextField field3 = new TextField();
    VBox vbox = new VBox( field1, field2, field3 );

    vbox.addEventFilter( KeyEvent.KEY_PRESSED, ( KeyEvent event ) ->
    {
        if ( event.getCode() == KeyCode.ENTER )
        {
            KeyEvent newEvent
                    = new KeyEvent(
                            null,
                            null,
                            KeyEvent.KEY_PRESSED,
                            "",
                            "\t",
                            KeyCode.TAB,
                            event.isShiftDown(),
                            event.isControlDown(),
                            event.isAltDown(),
                            event.isMetaDown()
                    );

            Event.fireEvent( event.getTarget(), newEvent );
            event.consume();
        }
    } );
    final Scene scene = new Scene( vbox, 800, 600 );
    primaryStage.setScene( scene );
    primaryStage.show();

}

在搜索和寻找这个问题的一个像样的答案后,我终于写了一个自己的答案,因为没有答案真正满足我的需要。

这是我的解决方案(注意:我只使用 TextFields,因此默认情况下,setOnAction 在按下 ENTER 时执行):

textField.setOnAction((ActionEvent e) -> {
    boolean isThisField = false;
    for (Node child : textField.getParent().getChildrenUnmodifiable()) {
        if (isThisField) {

            //This code will only execute after the current Node
            if (child.isFocusTraversable() && !child.isDisabled()) {
                child.requestFocus();

                //Reset check to prevent later Node from pulling focus
                isThisField = false;
            }
        } else {

            //Check if this is the current Node
            isThisField = child.equals(textField);
        }
    }

    //Check if current Node still has focus
    boolean focusChanged = !textField.isFocused();
    if (!focusChanged) {
        for (Node child : textField.getParent().getChildrenUnmodifiable()) {
            if (!focusChanged && child.isFocusTraversable() && !child.isDisabled()) {
                child.requestFocus();

                //Update to prevent later Node from pulling focus
                focusChanged = true
            }
        }
    }
});