2

关于JavaFX:如何更改焦点遍历策略?Alexander Kirov 展示了如何为 JavaFX 应用程序自定义焦点遍历策略。它工作正常,但不适用于TitledPanes。如果 a 中的节点TitledPane具有焦点,TraversalEngine则不会调用 set。

下面是一个完整的例子来展示这种现象:

package org.example;

import com.sun.javafx.scene.traversal.Direction;
import com.sun.javafx.scene.traversal.TraversalEngine;

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class FocusTest extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        // Create UI
        final VBox root = new VBox();
        final Button foo = new Button("foo");
        foo.setId("foo");
        root.getChildren().add(foo);
        final Button bar = new Button("bar");
        bar.setId("bar");
        final Pane content = new Pane();
        content.getChildren().add(bar);
        final TitledPane tp = new TitledPane("tp", content);
        root.getChildren().add(tp);

        // Set TraversalEngine
        final TraversalEngine te = new TraversalEngine(root, false) {
            @Override
            public void trav(Node owner, Direction direction) {
                System.out.printf("trav owner: %s, direction: %s%n",
                        owner.getId(), direction);
                switch (direction) {
                case DOWN:
                case RIGHT:
                case NEXT:
                    if (owner == foo) {
                        bar.requestFocus();
                    } else if (owner == bar) {
                        foo.requestFocus();
                    }
                    break;
                case LEFT:
                case PREVIOUS:
                case UP:
                    if (owner == foo) {
                        bar.requestFocus();
                    } else if (owner == bar) {
                        foo.requestFocus();
                    }
                    break;
                }
            }
        };
        root.setImpl_traversalEngine(te);

        // Show Scene
        final Scene scene = new Scene(root);
        primaryStage.setHeight(200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

场景的根是 aVBox并且自定义TraversalEngine设置为它。如果按钮foo有焦点并且我按下 [Tab] 然后te.trav被调用并且焦点设置为bar。这就是我的预期。但是什么时候bar有焦点,te.trav就不叫了。bar是一个孩子TitledPane。这种行为显示在1中。

有没有人解决这个问题?

TitledPane 中的焦点遍历

4

3 回答 3

1

这是一个处理TitledPanes 的棘手解决方案:

@SuppressWarnings("deprecation")
private static void registerTraversalEngine(final Parent parent,
        final TraversalEngine te) {
    parent.setImpl_traversalEngine(te);
    for (Node child : parent.getChildrenUnmodifiable()) {
        if (child instanceof Parent) {
            registerTraversalEngine((Parent) child, te);
        }
    }
    if (parent instanceof TitledPane) {
        final TitledPane tp = (TitledPane) parent;
        if (tp.getContent() instanceof Parent) {
            registerTraversalEngine((Parent) tp.getContent(), te);
        }
    }
}

我认为TitltedPanes 的问题是,内容不在孩子集中:

TitledPane.getChildrenUnmodifiable().contains(TitledPane.getContent()) is always false
于 2013-03-14T08:49:46.663 回答
0

如果您要关注的组件是 Swing 组件,您只需重载其 requestFocus() 以回调其 SwingNode 父级。仅此而已:

    SwingNode n = new SwingNode() {

        @Override
        public void requestFocus() {
            System.err.println("SwingNode.requestFocus "); // just to check
            super.requestFocus();
        }
    };
    JTextArea p = new JTextArea() {

        @Override
        public void requestFocus() {
            System.err.println("JTextArea.requestFocus");
            n.requestFocus(); // <- HERE IS THE TRICK: use SwingNode focus instead of Swing component one
        }
    };
    n.setContent(p);
于 2015-04-01T19:42:46.760 回答
0

我将 fx:id 保存在该字段中:

nombreDelPropietario.setUserData("#rbTodos");

我设置了 On Action 事件这个函数:

    

public void procesaEnter(ActionEvent event) {

        /* Obtiene el Objeto que recibió el Enter */

        Node source = (Node) event.getSource();

        /* Obtiene el ID del objeto al que hay que ir */

        String idDestino = (String) source.getUserData();

        /* Si está informado */

        if (idDestino != null) {

            /* Recupera el Nodo */

            Node destino = (Node) ((Scene) source.getScene()).lookup(idDestino);

            /* Si está el nodo activo, accede al nodo seleccionado */

            if (destino != null) {
                destino.requestFocus();
            }

        }

    }
于 2013-10-10T01:08:02.097 回答