Purtroppo, Spinner non si comporta come previsto: nella maggior parte del sistema operativo, dovrebbe commettere il valore modificato a fuoco perduto. Ancora più sfortunato, non fornisce alcuna opzione di configurazione per renderlo facilmente come previsto.
Quindi dobbiamo impegnare manualmente il valore in un listener in focusedProperty. Sul lato positivo, Spinner ha già il codice così facendo - è privata, però, dobbiamo c & p è
/**
* c&p from Spinner
*/
private <T> void commitEditorText(Spinner<T> spinner) {
if (!spinner.isEditable()) return;
String text = spinner.getEditor().getText();
SpinnerValueFactory<T> valueFactory = spinner.getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
}
// useage in client code
spinner.focusedProperty().addListener((s, ov, nv) -> {
if (nv) return;
//intuitive method on textField, has no effect, though
//spinner.getEditor().commitValue();
commitEditorText(spinner);
});
Si noti che c'è un metodo
textField.commitValue()
cui mi sarei aspettato di. .. beh ... commetti il valore, che non ha alcun effetto. È (finale!) Implementato per aggiornare il valore del textFormatter se disponibile. Non funziona nello Spinner, anche se si utilizza un textFormatter for validation. Potrebbe esserci qualche ascoltatore interno mancante o lo spinner non ancora aggiornato alla relativamente nuova API - non scavare, però.
Aggiornamento
Durante la riproduzione in giro un po 'più con TextFormatter ho notato che un formattatore guarantees to commit su focusLost:
Il valore viene aggiornato quando il controllo perde la sua messa a fuoco o si tratta commited (TextField only)
Che effettivamente funziona come d ocumented tale che potremmo aggiungere un listener ValueProperty del formattatore a ricevere la notifica ogni volta che il valore è impegnata:
TextField field = new TextField();
TextFormatter fieldFormatter = new TextFormatter(
TextFormatter.IDENTITY_STRING_CONVERTER, "initial");
field.setTextFormatter(fieldFormatter);
fieldFormatter.valueProperty().addListener((s, ov, nv) -> {
// do stuff that needs to be done on commit
});
Trigger per un impegnano:
- utente preme INVIO
- perde il controllo si concentrano
- field.setText è chiamato a livello di codice (questo è un comportamento non documentato!)
Tornando allo spinner: possiamo usare questo comportamento commit-on-focusLost del valore di un formattatore per forzare un commit sul valore di spinnerFactory. Qualcosa di simile
// normal setup of spinner
SpinnerValueFactory factory = new IntegerSpinnerValueFactory(0, 10000, 0);
spinner.setValueFactory(factory);
spinner.setEditable(true);
// hook in a formatter with the same properties as the factory
TextFormatter formatter = new TextFormatter(factory.getConverter(), factory.getValue());
spinner.getEditor().setTextFormatter(formatter);
// bidi-bind the values
factory.valueProperty().bindBidirectional(formatter.valueProperty());
Si noti che la modifica (la scrittura o la programmazione sostituendo/aggiungendo/incolla di testo) non non grilletto un commettere - quindi questo non può essere utilizzato se è necessario impegnarsi-on-text-cambiamento.
Questa è una risposta davvero buona e pulita – Alberto
Per coloro che vengono a questa risposta alla ricerca del motivo per cui la loro selezione non si aggiorna nonostante la pressione di invio: probabilmente stai usando un ChangeListener - si attiva solo se c'è stato un vero cambiamento nel valore , a volte JavaFX sembra sbagliarsi. Prova a utilizzare un InvalidationListener. – oskopek