2013-03-06 18 views
20

Ist es in JavaFX möglich, die Fokus-Traversal-Richtlinie zu ändern, wie in AWT?JavaFX: Wie ändere ich die Fokus-Traversal-Politik?

Weil die Traversierungsreihenfolge für zwei meiner HBox es falsch ist.

+0

Sie Fokus für jeden Knoten in javafx durch den Aufruf node.requestFocus() -Methode anfordern können – invariant

+0

Ja, ich weiß, aber das ist nicht eine sehr saubere Lösung. – Sonja

+0

Bitte stellen Sie Ihr Problem klar dar und geben Sie [sscce] (http://sscce.org/) an. – gontard

Antwort

10

Im allgemeinen Fall erfolgt die Navigation in einer Containerreihenfolge, in der Reihenfolge der Kinder, oder entsprechend den Pfeiltasten. Sie können die Reihenfolge der Knoten ändern - dies ist in dieser Situation die optimale Lösung für Sie.

Es gibt eine Hintertür in JFX über Traversal Motorenstrategie Substitution:

können Sie die interne Klasse com.sun.javafx.scene.traversal.TraversalEngine Unterklasse

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

Und verwenden

setImpl_traversalEngine(engine); 

aufrufen, um diese Engine anzuwenden.

Sie können den Code von OpenJFX beobachten, um zu verstehen, wie es funktioniert und was Sie tun können.

Seien Sie sehr vorsichtig: es ist eine interne API, und es wird wahrscheinlich wahrscheinlich in der nächsten Zukunft ändern. Also verlasse dich nicht darauf (du kannst dich sowieso nicht darauf verlassen).

Beispielimplementierung:

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

Es wird für gemeinsamen Fall stark analitical Fähigkeiten erfordern;)

+5

die interne api scheint sich in fx8 erheblich geändert zu haben, nicht mehr möglich (wahrscheinlich muss man sich anpassen, indem man einen benutzerdefinierten Algorithmus implementiert, eine ParentFocusTraversalEngine damit konfiguriert) – kleopatra

16

Die einfachste Lösung ist die FXML Datei zu bearbeiten und die Behälter entsprechend neu anordnen. Als Beispiel hat meine aktuelle Anwendung einen Registrierungsdialog, in den eine Seriennummer eingegeben werden kann. Zu diesem Zweck gibt es 5 Textfelder. Für den Fokus von einem Textfeld auf den anderen richtig passieren, musste ich sie auf diese Weise zur Liste:

<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" /> 
+0

Ja, das ist der einfachste Weg. Ich hatte das gleiche Problem. Das bedeutet, dass der UI-Szenen-Generator während der Entwicklung die relevanten FXML-Tags in add-hock-Reihenfolge neu generiert. Sobald wir sie richtig geordnet haben, funktioniert es gut. – Channa

+0

Ich habe das gleiche hier gemacht, es funktioniert. – ceklock

+0

Es wäre schön, wenn SB das automatisch für uns tun könnte. – User

10

Bluehair Antwort richtig ist, aber Sie können diese Builder auch in JavaFX Scene tun.

Sie haben Hierarchie-Panel in der linken Spalte. Es gibt alle deine Komponenten aus der Szene. Ihre Reihenfolge repräsentiert die Fokus-Traversierungsreihenfolge und sie antwortet auf ihre Reihenfolge in der FXML-Datei.

fand ich diesen Tipp auf dieser Webseite: www.wobblycogs.co.uk

1

In Szene Builder zur Ansicht Menü gehen und wählen Sie zeigen Dokument. Auf der linken Seite befinden sich alle Objekte in Ihrem aktuellen fxml-Dokument. Ziehen Sie die Steuerelemente in der Liste nach oben oder unten, um sie für den Registerindex neu anzuordnen. Wählen Sie Dokument ausblenden aus, um die anderen Tools zu verwenden, da der Dokumentbereich den Bereich beeinträchtigt.

5

Wir JavaFX event filters dafür verwenden, z.B .:

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

Die event.consume() unterdrückt den Standardfokus Traversal, die sonst Probleme verursacht, wenn requestFocus() Aufruf.

+0

Dies ist das einfachste und beste. Vielen Dank. – chris

+0

Meiner Meinung nach ist dies die einzige nachhaltige Antwort. Wir rufen keine interne API auf, und die Neuanordnung von Knoten in FXML ist nicht immer möglich, z. wenn wir Knoten dynamisch mit Java hinzufügen wollen. – aboger

6

Dies ist die akzeptierte Antwort angepasst an die Änderung der internen API (passiert an einem Punkt von fx-8, meine aktuelle Version ist 8u60b5).Offensichtlich gilt immer noch der ursprüngliche Disclaimer: es ist intern api, jederzeit ohne Vorankündigung zu ändern!

Die Änderungen (im Vergleich zu der akzeptierten Antwort)

  • Elternteil eine TraversalEngine vom Typ ParentTraversalEngine benötigt
  • nav nicht mehr ist ein Verfahren zur TraversalEngine (noch ParentTE), sondern nur von TopLevelTraversalEngine
  • die Navigation Implementierung wird an die Strategie namens Algorithmus
  • delegiert Fokus Focus Transfer ist (scheint zu sein?) behandelt von TopLevelTE, Algorithmus findet nur und gibt das neue Ziel

Die einfache Übersetzung des Beispielcode:

/** 
* 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); 
     vb.setImpl_traversalEngine(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); 
    } 
} 
+0

Siehe ContainerTabOrder für ein Beispiel für einen vollständigen Algorithmus (muss in Children recursen). Aber es war zu komplex für mich, ich habe eine Umgehungslösung verwendet, um Schaltflächen in der Registerkarte Politik in FXML ohne Java-Code zu ignorieren: set 'focusTraversable =" false "'. Es wird mit dem nächsten fokussierbaren Element fortgesetzt. – pdem

0

I Eventfilter als Lösung in Kombination mit Verweis auf die Feld-IDs verwendet, so alles, was Sie tun müssen, ist die Felder wie (Feld1, Feld2, field3 nennen , field4), so können Sie die Felder platzieren, wo u wollen:

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; 
      } 
     } 
    }); 
Verwandte Themen