A DESCRIPTION OF THE PROBLEM :
The Spinner control has an editor TextField. This field is the only way to notice when a user is done editing the Spinner, and the value can be committed. Indeed, by default, the Spinner wires a listener to the editor's action listener to do so. However, unlike a normal TextField, whose ActionEvent can be consumed to stop handling of the KeyEvent that triggered it; the SpinnerSkin class does not properly consume the originating KeyEvent when the propagated one is consumed. This can result in unwanted handling of this event by parent nodes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Start the class provided (SpinnerNonConsuming).
2. Click into the "Normal" TextField, hit ENTER, and notice that it prints out an action, but does not log a KeyEvent from the VBox listener.
3. Click into the Spinner's TextField, hit ENTER, and notice that it both prints out the action, and also logs a KeyEvent from the VBox listener.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Performing (3) should not log a KeyEvent from the VBox listener.
ACTUAL -
The KeyEvent event is logged.
---------- BEGIN SOURCE ----------
public class SpinnerNonConsuming extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
TextField textField = new TextField("Normal text field");
textField.setOnAction(event -> {
System.out.println("Normal action event: " + textField.getText());
event.consume();
});
Spinner<Integer> integerSpinner = new Spinner<>(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100, 50));
integerSpinner.getEditor().setOnAction(event -> {
System.out.println("Spinner action event: " + integerSpinner.getValue());
event.consume();
});
integerSpinner.setEditable(true);
VBox root = new VBox(textField, integerSpinner);
root.setOnKeyPressed(event -> System.out.println("Key pressed: " + event.getCode()));
primaryStage.setScene(new Scene(root, 300, 300));
primaryStage.show();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Attach the following listener to the Spinner, which is over-eager as it suppresses even if the action event isn't consumed:
spinner.setOnKeyPressed(t -> {
if (t.getCode() == KeyCode.ENTER) {
t.consume();
}
});
FREQUENCY : always