Search code examples
javajavafxfocusjavafx-2javafx-8

JavaFX: How to change the focus traversal policy?


Is it possible in JavaFX to change the focus traversal policy, like in AWT?

Because the traversal order for two of my HBoxes is wrong.


Solution

  • In common case the navigation is done in a container order, in order of children, or according to arrow keys pressing. You can change order of nodes - it will be the optimal solution for you in this situation.

    There is a back door in JFX about traversal engine strategy substitution :

    you can subclass the internal class com.sun.javafx.scene.traversal.TraversalEngine

    engine = new TraversalEngine(this, false) {
                @Override public void trav(Node owner, Direction dir) {
                    // do whatever you want
                }
            };
    

    And use

    setImpl_traversalEngine(engine); 
    

    call to apply that engine.

    You can observe the code of OpenJFX, to understand, how it works, and what you can do.

    Be very careful : it is an internal API, and it is likely to change, possibly, in the nearest future. So don't rely on this (you cannot rely on this officialy, anyway).

    Sample implementation :

    public void start(Stage stage) throws Exception {
        final VBox vb = new VBox();
    
        final Button button1 = new Button("Button 1");
        final Button button2 = new Button("Button 2");
        final Button button3 = new Button("Button 3");
    
        TraversalEngine engine = new TraversalEngine(vb, false) {
            @Override
            public void trav(Node node, Direction drctn) {
                int index = vb.getChildren().indexOf(node);
    
                switch (drctn) {
                    case DOWN:
                    case RIGHT:
                    case NEXT:
                        index++;
                        break;
                    case LEFT:
                    case PREVIOUS:
                    case UP:
                        index--;
                }
    
                if (index < 0) {
                    index = vb.getChildren().size() - 1;
                }
                index %= vb.getChildren().size();
    
                System.out.println("Select <" + index + ">");
    
                vb.getChildren().get(index).requestFocus();
            }
        };
    
        vb.setImpl_traversalEngine(engine);
    
        vb.getChildren().addAll(button1, button2, button3);
        Scene scene = new Scene(vb);
        stage.setScene(scene);
        stage.show();
    }
    

    It will require strong analitical skills for common case ;)