JavaFX:如何更改焦点遍历策略?

Son*_*nja 25 java javafx focus javafx-2 javafx-8

在JavaFX中是否可以更改焦点遍历策略,例如在AWT中?

因为我的两个HBoxes 的遍历顺序是错误的.

小智 18

最简单的解决方案是编辑FXML文件并适当地重新排序容器.例如,我当前的应用程序有一个注册对话框,可以在其中输入序列号.为此目的有5个文本字段.为了使焦点从一个文本字段正确传递到另一个文本字段,我必须以这种方式列出它们:

<TextField fx:id="tfSerial1" layoutX="180.0" layoutY="166.0" prefWidth="55.0" />
<TextField fx:id="tfSerial2" layoutX="257.0" layoutY="166.0" prefWidth="55.0" />
<TextField fx:id="tfSerial3" layoutX="335.0" layoutY="166.0" prefWidth="55.0" />
<TextField fx:id="tfSerial4" layoutX="412.0" layoutY="166.0" prefWidth="55.0" />
<TextField fx:id="tfSerial5" layoutX="488.0" layoutY="166.0" prefWidth="55.0" />
Run Code Online (Sandbox Code Playgroud)


小智 13

Bluehair的答案是对的,但即使在JavaFX Scene Builder中也可以这样做.

左列中有"层次结构"面板.场景中有你的所有组件.它们的顺序代表焦点遍历顺序,它响应它们在FXML文件中的顺序.

我在这个网页上找到了这个小贴士:www.wobblycogs.co.uk


Ale*_*rov 12

在通常情况下,导航以容器顺序,按子女的顺序或按箭头键按下完成.您可以更改节点的顺序 - 在这种情况下,它将是您的最佳解决方案.

JFX中有一个关于遍历引擎策略替换的后门:

你可以继承内部类com.sun.javafx.scene.traversal.TraversalEngine

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

并使用

setImpl_traversalEngine(engine); 
Run Code Online (Sandbox Code Playgroud)

打电话申请该引擎.

您可以观察OpenJFX的代码,了解它,它是如何工作的,以及您可以做些什么.

要非常小心:它是一个内部API,可能会在最近的将来发生变化.所以不要依赖于此(无论如何你不能依靠这个官方).

示例实施:

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();
}
Run Code Online (Sandbox Code Playgroud)

普通案件需要强大的分析能力;)

  • 内部api似乎在fx8中发生了很大变化,不再可能(可能需要通过实现自定义算法进行调整,使用它配置ParentFocusTraversalEngine) (5认同)

小智 7

我们正在使用JavaFX事件过滤器,例如:

cancelButton.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
    @Override
    public void handle(KeyEvent event) {
        if (event.getCode() == KeyCode.TAB && event.isShiftDown()) {
            event.consume();
            getDetailsPane().requestFocus();
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

event.consume()抑制的默认焦点遍历,当调用否则会造成麻烦requestFocus().


kle*_*tra 6

这是适应内部api更改的公认答案(发生在fx-8的某个点,我目前的版本是8u60b5).显然原来的免责声明仍然适用:它是内部 API,随时可以随时更改,恕不另行通知!

变化(与接受的答案相比)

  • 父需要一个ParentTraversalEngine类型的TraversalEngine
  • nav不再是TraversalEngine(也不是ParentTE)的方法,而只是TopLevelTraversalEngine的方法
  • 导航实现被委托给名为Algorithm的策略
  • 实际焦点转移是(似乎是?)由TopLevelTE处理,算法只找到并返回新目标

示例代码的简单翻译:

/**
 * Requirement: configure focus traversal
 * old question with old hack (using internal api):
 * http://stackoverflow.com/q/15238928/203657
 * 
 * New question (closed as duplicate by ... me ..)
 * http://stackoverflow.com/q/30094080/203657
 * Old hack doesn't work, change of internal api
 * rewritten to new internal (sic!) api
 * 
 */
public class FocusTraversal extends Application {

    private Parent getContent() {
        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");

        Algorithm algo = new Algorithm() {

            @Override
            public Node select(Node node, Direction dir,
                    TraversalContext context) {
                Node next = trav(node, dir);
                return next;
            }

            /**
             * Just for fun: implemented to invers reaction
             */
            private Node trav(Node node, Direction drctn) {
                int index = vb.getChildren().indexOf(node);

                switch (drctn) {
                    case DOWN:
                    case RIGHT:
                    case NEXT:
                    case NEXT_IN_LINE:    
                        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 + ">");

                return vb.getChildren().get(index);
            }

            @Override
            public Node selectFirst(TraversalContext context) {
                return vb.getChildren().get(0);
            }

            @Override
            public Node selectLast(TraversalContext context) {
                return vb.getChildren().get(vb.getChildren().size() - 1);
            }

        };
        ParentTraversalEngine engine = new ParentTraversalEngine(vb, algo);
        // internal api in fx8
        // vb.setImpl_traversalEngine(engine);
        // internal api since fx9
        ParentHelper.setTraversalEngine(vb, engine);
        vb.getChildren().addAll(button1, button2, button3);
        return vb;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(getContent()));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Run Code Online (Sandbox Code Playgroud)