28

AWT のように、JavaFX でフォーカス トラバーサル ポリシーを変更することは可能ですか?

HBox私の 2 つのesの走査順序が間違っているためです。

4

11 に答える 11

21

最も簡単な解決策は、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" />
于 2013-05-27T15:50:52.250 に答える
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
            }
        };

そして使う

setImpl_traversalEngine(engine); 

そのエンジンを適用するために呼び出します。

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

一般的なケースでは、強力な分析スキルが必要になります;)

于 2013-03-06T14:37:06.953 に答える
7

これは、内部 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);
    }
}
于 2015-05-07T10:34:53.090 に答える
1

フィールド ID の参照と組み合わせて Eventfilter をソリューションとして使用したので、フィールドに (field1,field2,field3,field4) のような名前を付けるだけで、必要な場所にフィールドを配置できます。

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;
            }
        }
    }); 
于 2016-02-22T13:23:11.450 に答える