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

时间:2015-05-01 08:51:10

标签: javafx javafx-8

有没有办法以编程方式关注容器中的下一个可聚焦节点,而无需直接调用特定组件的requestFocus()方法?此功能类似于按Tab键按钮在跳过disabled个节点的组件之间遍历焦点。

3 个答案:

答案 0 :(得分:8)

没有公开的方法。 只有黑客和解决方法。

您可以使用节点的

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 });
    }
}

你最终必须提供一个也不鼓励的Direction参数。

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

答案 1 :(得分:4)

根据您的使用案例,您还可以在父窗格中过滤 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();

}

答案 2 :(得分:0)

在搜索并寻找这个问题的正确答案之后,我终于写下了自己的答案,因为没有答案能真正满足我的需求。

这是我的解决方案(注意:我只使用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
            }
        }
    }
});