Spinner Control Value

I am 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 the keyboard and I increase the upper value, the expected number will not be next. Instead, this is the next default value. How can i fix this?

For example: if I have 5 as the default, and I enter 34, and then click the top arrow, which I expect to get 35, actually get 6.

+6
source share
3 answers

I had the same problem with spinner control. Your error is described here: JDK-8094205

Here is the last comment:

Jonathan Giles added a comment - Dec, 15 2014 12:59

Fixed locally in my repo, this week it will be released on the 8u60 repository as soon as it opens. Now the input of the text editor is fixed when adding / decrements are called (although the value is still not fixed when the focus is lost).

Unit tests:

 javafx.scene.control.SpinnerTest.test_rt_39655_decrement() javafx.scene.control.SpinnerTest.test_rt_39655_increment() 

Changelog: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/89ca7d3f699e

Here is my reception on an Autocommit answering machine. This one will automatically commit whatever the factory accepts.

 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); } } } } 
+5
source

By design, changes to the text field of a Spinner control are only performed when the user presses the ENTER key using an 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 entered value cannot be converted, this will NumberFormatException , storing the incorrect value in the text box.

We can provide our own implementation, listening to other keys, such as a TAB key, through an event filter, and at the same time, and in case of an exception, restore the last valid value.

Something like that:

 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())); } } } } 
+3
source

This solved the problem for me, but it relies on the Apache Commons Validator to validate the entered value in spinner ( org.apache.commons.validator.GenericValidator )

 valueSpinner.getEditor().textProperty().addListener((observable, oldValue, newValue) -> { try { if (GenericValidator.isInt(newValue)) { valueSpinner.getValueFactory().setValue(Integer.parseInt(newValue)); } } catch (NumberFormatException e) { if (GenericValidator.isInt(oldValue)) { valueSpinner.getValueFactory().setValue(Integer.parseInt(oldValue)); } } }); 

Edit: - You can check the value without using the Apache Commons Validator, as in this example: -

  private boolean isInteger(String value) { if (value == null) { return false; } try { new Integer(value); return true; } catch (NumberFormatException e) { return false; } } valueSpinner.getEditor().textProperty().addListener((observable, oldValue, newValue) -> { try { if (isInteger(newValue)) { valueSpinner.getValueFactory().setValue(Integer.parseInt(newValue)); } } catch (NumberFormatException e) { if (isInteger(oldValue)) { valueSpinner.getValueFactory().setValue(Integer.parseInt(oldValue)); } } }); 
+1
source

Source: https://habr.com/ru/post/979475/


All Articles