JavaFX的:如何更改焦点遍历策略?(JavaFX: How to change the focu

2019-07-21 01:45发布

是否有可能在JavaFX的在AWT改变焦点遍历策略 ,怎么样?

因为两个我的遍历顺序HBox ES是错误的。

Answer 1:

在普通情况下,导航在容器中以便根据箭头键按下进行,在儿童的顺序,或。 您可以更改节点的顺序 - 它会为你在这种情况下的最佳解决方案。

有一个在JFX后门约穿越引擎战略替代:

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

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

和使用

setImpl_traversalEngine(engine); 

调用应用该引擎。

你可以观察的OpenJFX的代码,理解,它是如何工作的,以及你可以做什么。

要非常小心:这是一个内部API,它很可能会改变,可能的话,在不久的将来。 所以不要依赖这个(你不能靠这个officialy,反正)。

示例实现:

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

这将需要对常见的情况强analitical技能;)



Answer 2:

最简单的办法是编辑文件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" />


Answer 3:

Bluehair的答案是正确的,但你甚至可以在JavaFX的场景生成器做到这一点。

您在左列层次面板。 有来自现场所有组件。 他们为了表示焦点遍历顺序并响应其在FXML文件顺序。

我发现该网页上的这个提示: www.wobblycogs.co.uk



Answer 4:

这是公认的答案适用于改变内部的API(在FX-8的某一点发生了,我现在的版本是8u60b5)。 显然,原来的免责声明仍然适用:它的内部 API,开放在任何时候,恕不另行通知更改!

的变化(相对于公认的答案)

  • 家长需要类型ParentTraversalEngine的TraversalEngine
  • NAV不再TraversalEngine(也不ParentTE)的方法,但仅TopLevelTraversalEngine的
  • 导航实现委托给战略称为算法
  • 实际的焦点转移(好像是?)由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);
    }
}


Answer 5:

我们使用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();
        }
    }
});

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



Answer 6:

在现场建设者进入查看菜单,然后选择显示文件。 在左侧会以您目前FXML文档中的所有对象。 拖动控制向上或向下在列表中重新排序的选项卡索引。 选择隐藏文件使用其他工具,因为文档窗格猪的空间。



Answer 7:

我用Eventfilter作为解决方案结合引用字段的ID的,因此,所有你需要做的就是类似名称的字段(字段1,字段2,字段3,字段4),所以你可以把其中u想要的字段:

mainScene.addEventFilter(KeyEvent.KEY_PRESSED, (event) -> {
        if(event.getCode().equals(KeyCode.TAB)){
            event.consume();
            final Node node =  mainScene.lookup("#field"+focusNumber);
            if(node!=null){
                node.requestFocus();
            }
            focusNumber ++;
            if(focusNumber>11){
              focusNumber=1;
            }
        }
    }); 


Answer 8:

您可以使用NodeName.requestFocus()就像上面说; 此外,一定要索取这个重点实例,并添加所有的根布局的节点,因为当你这样做时,焦点将转换后。



Answer 9:

你可以很容易地SceneBuilder做到这一点。 与scenebuilder打开FXML文件,然后转到层次 文档选项卡下。 将输入控件到你想要通过拖动输入控制器的订单。 记住要检查焦点遍历的性质。 然后集中,当你按下标签栏遍历政策将很好地工作。



文章来源: JavaFX: How to change the focus traversal policy?