I'm using Spinner from 8u40b17.
SpinnerValueFactory svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
Spinner sp = new Spinner();
sp.setValueFactory(svf);
sp.setEditable(true);
sp.setPrefWidth(80);
I noticed that when I enter some value from keyboard and I increase the upper value the expected number is not the next. Instead of this it's the next default value. How I can fix this?
For example: if I have 5 as default value and I enter 34, then press the upper arrow I expect to get 35 by actually get 6.
I had the same problem with the spinner control. Your bug has been documented here: JDK-8094205
Here is the last comment:
Jonathan Giles added a comment - Dec, 15 2014 12:59 AM
Fixed locally in my repo, will push to the 8u60 repo this week once it opens. Now the text editor input is committed when increment / decrement are called (although the value is still not committed when focus is lost).
Unit tests:
javafx.scene.control.SpinnerTest.test_rt_39655_decrement() javafx.scene.control.SpinnerTest.test_rt_39655_increment()
The changeset: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/89ca7d3f699e
Here is my take on an Autocommit spinner. This one will auto commit anything that the factory will accept.
public class SpinnerAutoCommit<T> extends Spinner<T> {
public SpinnerAutoCommit() {
super();
addListenerKeyChange();
}
public SpinnerAutoCommit(int min, int max, int initialValue) {
super(min, max, initialValue);
addListenerKeyChange();
}
public SpinnerAutoCommit(int min, int max, int initialValue, int amountToStepBy) {
super(min, max, initialValue, amountToStepBy);
addListenerKeyChange();
}
public SpinnerAutoCommit(double min, double max, double initialValue) {
super(min, max, initialValue);
addListenerKeyChange();
}
public SpinnerAutoCommit(double min, double max, double initialValue, double amountToStepBy) {
super(min, max, initialValue, amountToStepBy);
addListenerKeyChange();
}
public SpinnerAutoCommit(ObservableList<T> items) {
super(items);
addListenerKeyChange();
}
public SpinnerAutoCommit(SpinnerValueFactory<T> valueFactory) {
super(valueFactory);
addListenerKeyChange();
}
private void addListenerKeyChange() {
getEditor().textProperty().addListener((observable, oldValue, newValue) -> {
commitEditorText();
});
}
private void commitEditorText() {
if (!isEditable()) return;
String text = getEditor().getText();
SpinnerValueFactory<T> valueFactory = getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
}
}
By design, the changes in the textfield of the Spinner
control are commited only when the user hits ENTER key, via action handler:
getEditor().setOnAction(action -> {
String text = getEditor().getText();
SpinnerValueFactory<T> valueFactory = getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
});
Note that if the typed value can't be converted, this will throw a NumberFormatException
, keeping the wrong value in the textfield.
We can provide our own implementation, listening to other keys, like TAB key, via event filter, and at the same time, and in case of exception, restore the last valid value.
Something like this:
private final Spinner sp = new Spinner();
@Override
public void start(Stage primaryStage) {
SpinnerValueFactory svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
sp.setValueFactory(svf);
sp.setEditable(true);
sp.setPrefWidth(80);
// Commit on TAB
sp.addEventFilter(KeyEvent.ANY, e->{
if (sp.isEditable() && e.getCode().equals(KeyCode.TAB)) {
doCommit();
e.consume();
}
});
// Override Commit on ENTER
sp.getEditor().setOnAction(e->{
if(sp.isEditable()) {
doCommit();
e.consume();
}
});
Scene scene = new Scene(new StackPane(sp), 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
/*
Commit new value, checking conversion to integer,
restoring old valid value in case of exception
*/
private void doCommit(){
String text = sp.getEditor().getText();
SpinnerValueFactory<Integer> valueFactory = sp.getValueFactory();
if (valueFactory != null) {
StringConverter<Integer> converter = valueFactory.getConverter();
if (converter != null) {
try{
Integer value = converter.fromString(text);
valueFactory.setValue(value);
} catch(NumberFormatException nfe){
sp.getEditor().setText(converter.toString(valueFactory.getValue()));
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With