Reputation: 2712
On JavaFX: How to change the focus traversal policy? Alexander Kirov show how to customize the focus traversal policy for a JavaFX application. It works fine, but not for TitledPane
s. If a node in a TitledPane
has focus, the setted TraversalEngine
is not called.
Here is a full example to show this phenomenon:
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);
}
}
The root of the scene is a VBox
and the custom TraversalEngine
is set to it. If the button foo
has the focus and I press [Tab] then te.trav
is called and the focus is set to bar
. That's how I expected. But when bar
has the focus, te.trav
is not called. bar
is a child of the TitledPane
. This behaviour is shown in 1.
Has anyone a solution for this?
Upvotes: 2
Views: 1592
Reputation: 46
In case the component you want to focus on is a Swing one, you just need to overload its requestFocus() to callback its SwingNode parent. Nothing more :
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);
Upvotes: 0
Reputation: 38
I save the fx:id in the field:
nombreDelPropietario.setUserData("#rbTodos");
I set On Action event this function:
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();
}
}
}
Upvotes: 0
Reputation: 2712
This is a tricky solution that deals with TitledPane
s:
@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);
}
}
}
I think the problem with TitltedPane
s is, that the content is not in the children set:
TitledPane.getChildrenUnmodifiable().contains(TitledPane.getContent()) is always false
Upvotes: 1