I use JavaFX 2.1 and I created GUI using FXML, in the controller of this GUI I added myTextField.requestFocus();
.
But I always get the focus in the other control.
I use JavaFX 2.1 and I created GUI using FXML, in the controller of this GUI I added myTextField.requestFocus();
.
But I always get the focus in the other control.
At the time of initialize()
controls are not yet ready to handle focus.
You can try next trick:
@Override
public void initialize(URL url, ResourceBundle rb) {
Platform.runLater(new Runnable() {
@Override
public void run() {
tf.requestFocus();
}
});
}
For tricky complex applications (like Pavel_K has in the comments) you may want to repeat this routine several times and call method line next one:
private void requestFocusOrDieTrying(Node node) {
Platform.runLater(() -> {
if (!node.isFocused()) {
node.requestFocus();
requestFocusOrDieTrying(node);
}
});
}
Note this is the undocumented approach and it may be wise to add a limit for repetitions to avoid endless loop if something changed or broke in future Java releases. Better to lose focus than a whole app. :)
Example with the described threshold:
@Override
public void requestFocus() {
requestFocus( getNode(), 3 );
}
private void requestFocus( final Node node, final int max ) {
if( max > 0 ) {
runLater(
() -> {
if( !node.isFocused() ) {
node.requestFocus();
requestFocus( node, max - 1 );
}
}
);
}
}
tf == null
is still true at the moment initialize
runs. –
Uncut initialize()
time. Otherwise what a point in having initialize()
method at all? –
Arlina Platform.runLater(() -> { Platform.runLater(() -> {Platform.runLater(() -> {textInput.requestFocus(); });});});
Although it seems to work with two Platform.runLater we decided to put one more for sure. It seems that there are some timings issues in JavaFX with this focus, that's why one Platform.runLater works 10% cases. –
Bromeosin The exact same answer as @Sergey Grinev. Make sure your version of java is up-to-date (JDK 1.8 or later).
Platform.runLater(()->myTextField.requestFocus());
If you requestFocus(); after initializing the scene, it will work!
Like this:
Stage stage = new Stage();
GridPane grid = new GridPane();
//... add buttons&stuff to pane
Scene scene = new Scene(grid, 800, 600);
TEXTFIELD.requestFocus();
stage.setScene(scene);
stage.show();
I hope this helps. :)
This can occur when the Scene property for the Node is not yet set. Alas, the scene property can take a "long" time to be set.
The child node's scene property lags when a scene is first created, and also, when items are added to some parents, such as a TabPane (oddly some parents seem immune, I'm not sure why).
The correct strategy, which has always worked for me :
if (myNode.scene) == null {
// listen for the changes to the node's scene property,
// and request focus when it is set
} else {
myNode.requestFocus()
}
I have a handy Kotlin extension function which does this.
fun Node.requestFocusOnSceneAvailable() {
if (scene == null) {
val listener = object : ChangeListener<Scene> {
override fun changed(observable: ObservableValue<out Scene>?, oldValue: Scene?, newValue: Scene?) {
if (newValue != null) {
sceneProperty().removeListener(this)
requestFocus()
}
}
}
sceneProperty().addListener(listener)
} else {
requestFocus()
}
}
You can then call it from within you code like so :
myNode.requestFocusOnSceneAvailable()
Perhaps somebody would like to translate it to Java.
I ran into the same problem using JavaFX 11 and solved it in a similar way that nickthecoder proposed.
ChangeListener<Scene> sceneListener = new ChangeListener<Scene>() {
@Override
public void changed(ObservableValue<? extends Scene> observable, Scene oldValue, Scene newValue) {
if (newValue != null) {
editInput.requestFocus();
editInput.sceneProperty().removeListener(this);
}
}
};
editInput.sceneProperty().addListener(sceneListener);
Basicly just add a listener to the sceneProperty of the node and in that listener request focus once the scene is set. I also wrote it in such a way that the listener will be removed after it is invoked.
I would rather using timer to enforce focus to text field. The process of checking whether or not the text field has focus, is done in a separate (background) thread. While the process of requesting focus is done in the GUI thread, with the help of Platform.runLater()
.
//I'd rather using timer to enforce focus
Timer checkIfTFIsFocusedTimer = new Timer();
TimerTask checkIfTFIsFocusedTask = new TimerTask() {
@Override
public void run() {
if (!textField.isFocused()) {
Platform.runLater(() -> {
textField.requestFocus();
});
} else {
checkIfTFIsFocusedTimer.cancel();
}
}
};
checkIfTFIsFocusedTimer
.scheduleAtFixedRate(checkIfTFIsFocusedTask,
0, 100);
The older answers account for the case of Platform.runLater
not working, but this answer covers also the case of multiple requests on multiple nodes.
Problem is: the order in which the scene
property becomes non-null for the nodes, and thence the order in which the added listeners get called, is not necessarily the same as the order in which the two listeners were added. And so this order:
requestFocusOnSceneAvailable(node1)
requestFocusOnSceneAvailable(node2)
might unexpectedly result in this order:
node2.requestFocus()
node1.requestFocus()
A solution requires having the listeners call requestFocus()
only on the most recent node, which can be tracked with a static variable:
private static Node nodeToRequestFocusOnOnceSceneAvailable;
public static void requestFocusOnceSceneAvailable(Node node) {
// Remember this node as the latest node requested to receive focus.
nodeToRequestFocusOnOnceSceneAvailable = node;
// Schedule the focus request to happen whenever
// JavaFX finally adds the node to the scene.
Listeners.addAndFire(node.sceneProperty(), new ChangeListener<Scene>() {
@Override
public void changed(ObservableValue<? extends Scene> observable, Scene oldScene, Scene newScene) {
if (newScene != null) {
if (node == nodeToRequestFocusOnOnceSceneAvailable) {
node.requestFocus();
// We no longer need to remember this node,
// since its focus has been requested.
nodeToRequestFocusOnOnceSceneAvailable = null;
}
// We no longer need the listener
// after it has run once.
observable.removeListener(this);
}
}
});
}
Note, this solution assumes there is only one scene.
© 2022 - 2024 — McMap. All rights reserved.
TextArea
refused to get the focus programmatically even though the Stage was visible and active and the current running thread was the JavaFX Application thread. But if I followed the example and queued a newRunnable
it worked. Really strange, I have no words for it. – Proliferation