ADDITIONAL SYSTEM INFORMATION :
Rocky Linux 9: Linux 5.14.0-284.18.1.el9_2.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jun 22 17:36:46 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
openjdk version "17.0.7" 2023-04-18 LTS
OpenJDK Runtime Environment (Red_Hat-17.0.7.0.7-2) (build 17.0.7+7-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-17.0.7.0.7-2) (build 17.0.7+7-LTS, mixed mode, sharing)
OpenJFX: 17.0.2, 19.0.2, 21, 22-ea+11
Linux 6.1.58-1-lts #1 SMP PREEMPT_DYNAMIC Sun, 15 Oct 2023 18:38:43 +0000 x86_64 GNU/Linux
openjdk 17.0.8.1 2023-08-24
OpenJDK Runtime Environment (build 17.0.8.1+1)
OpenJDK 64-Bit Server VM (build 17.0.8.1+1, mixed mode)
OpenJFX: 22-ea+11
The bug is reproducible 100 % of the time on the mentioned Linux systems. It was NOT reproducible on Windows (Win10, openjdk 17.0.1).
A DESCRIPTION OF THE PROBLEM :
There seems to be a focusing issue for Control when they are repeatedly displayed in a new Stage (e.g. when an existing component is shown repeatedly in a dialog, when a new dialog window is used every time).
This leads to unexpected visual effects (multiple Controls have the blue focus border), which is a minor inconvenience.
A major inconvenience is that for TextFields, this bug also prevents KeyEvents (keyboard input) from reaching the affected TextFields, while MouseEvents are still handled as expected.
The bug only occurs if new/different Stages are used. It does not occur if the same Stage is reused every time the components are shown.
If there are problem with reproducing this issue, we can provide screenhots or a short screen capture (video).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
(See code example, this is just a short summary.)
Create two TextFields (A and B and some RadioButtons (in a ToggleGroup) in a Pane. Display the Pane in a new Stage. Enter some text. While TextField A is focused (blue border), close the Stage. Display the Pane in another NEW Stage. Repeat, but focus on a RadioButton before closing the Stage.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Both TextFields should still accept keyboard input as normal. No preference for whether TextField A should be focused when it is shown for the second, ... time. Only one Control should hold the focus (blue border, blinking cursor for TextFields) at any time).
ACTUAL -
TextField A appears initially focused (blue border, blinking cursor) and reacts to mouse events (including copy&paste via right-click menu), but does NOT accept keyboard input. Any keyboard input for A lands in TextField B (!). If B is focused, both TextFields have a blue border and a blinking cursor at the same time (!). B behaves as expected. When a RadioButton was focused when the Stage was closed, you can get blue borders for multiple RadioButtons and TextFields at the same time.
---------- BEGIN SOURCE ----------
/*
* Demo for broken focus (esp. keyboard input for TextFields) that are repeatedly shown in *new* Stages.
*
* Demo shows the broken behavior when using new Stages, and the expected behavior when the same stage is being
* reused. It also demonstrates that the focus problem effects not only TextFields, but also e.g. RadioButtons.
* There is also a workaround, which can be uncommented to be applied.
*/
public static class BrokenFocusAndKeyboardInputWhenTextFieldsReusedInNewDialogsDemoApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(final Stage stage) {
final VBox textFieldBox1 = createInputBox();
final VBox textFieldBox2 = createInputBox();
final Button openNewDialogButton = new Button("Open NEW dialog (broken)");
openNewDialogButton.setOnAction(evt -> {
// Hide/destroy previous dialog
if (openNewDialogButton.getUserData() instanceof Stage oldDialogStage) {
oldDialogStage.hide();
openNewDialogButton.setUserData(null);
}
final Stage newDialogStage = createDemoDialogStage();
setContentAndShow(newDialogStage, textFieldBox1);
openNewDialogButton.setUserData(newDialogStage);
});
final Button openExistingDialogButton = new Button("(Re-)Open EXISTING dialog (ok)");
final Stage reusableDialog = createDemoDialogStage();
openExistingDialogButton.setOnAction(evt -> {
setContentAndShow(reusableDialog, textFieldBox2);
});
final HBox root = new HBox(openNewDialogButton, openExistingDialogButton);
final Scene scene = new Scene(root, 500, 200);
stage.setScene(scene);
Platform.setImplicitExit(true);
stage.setTitle("BrokenFocusAndKeyboardInputWhenTextFieldsReusedInNewDialogsDemoApp");
stage.show();
}
private static void setContentAndShow(final Stage dialogStage, final Node content) {
if (dialogStage.getScene().getRoot() instanceof Pane rootPane) {
rootPane.getChildren().setAll(content);
}
dialogStage.show();
}
private static VBox createInputBox() {
final ToggleGroup toggleGroup = new ToggleGroup();
final VBox textFieldBox = new VBox(new TextField("a"), new TextField("b"), new TextField("c"),
createRadio("d", toggleGroup), createRadio("e", toggleGroup), createRadio("f", toggleGroup));
textFieldBox.getChildren()
.forEach(n -> n.addEventHandler(Event.ANY, event -> System.out.println("Event: " + event)));
return textFieldBox;
}
private static RadioButton createRadio(final String text, final ToggleGroup toggleGroup) {
final RadioButton rb = new RadioButton(text);
rb.setToggleGroup(toggleGroup);
return rb;
}
private static Stage createDemoDialogStage() {
final Stage dialogWindow = new Stage(StageStyle.UTILITY);
dialogWindow.setTitle("EventFilterCreepDemoApp - Dialog");
final Pane dialogRoot = new StackPane();
dialogWindow.setScene(new Scene(dialogRoot));
// Uncomment for WORKAROUND:
// dialogWindow.showingProperty().addListener((obs, oldIsShowing, newIsShowing) -> {
// // Request focus on hiding the Stage (no idea WHY it helps, but it does??)
// if (!newIsShowing) {
// dialogRoot.requestFocus();
// }
// });
// END WORKAROUND
return dialogWindow;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
(See code example: There is some code to uncomment there.)
When closing a Stage, request focus on it before discarding the Stage. Then everything behaves as expected.
FREQUENCY : always
Edit 2023/11/27:
- cannot be reproduced on macOS 13.5.2
- cannot be reproduced on windows 11