JavaFX Legătura valueProperty din TextField’s TextFormatter la SimpleDoubleProperty (Programare, Java, Javafx, Javafx 8)

joshsweaney a intrebat.

Am un TextField căruia i s-a dat un TextFormatter, care are un filtru care preia datele de intrare din câmpul de text și se asigură că este în format dublu. Apoi folosește un DoubleStringConverter pentru a converti textul filtrat într-o valoare dublă. Aceasta se află într-o componentă FXML personalizată. Vedeți mai jos un exemplu minimal.

public SomeComponent implements Initializable {
    @FXML
    public TextField inputField;

    public int min;

    public void initialize(URL location, ResourceBundle resources) {
        UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
            String newText = change.getControlNewText();
            if (newText.matches("-?[0-9]{1,13}(\.[0-9]*)?")) { 
                return change;
            }
            return null;
        };

        inputField.setTextFormatter(new TextFormatter<>(new DoubleStringConverter(), min, doubleFilter)); 
    }
}

O altă componentă FXML care utilizează această componentă …

public SomeView implements Initializable {
    @FXML
    SomeComponent comp;
    public void initialize(URL location, ResourceBundle resources) {
        comp.inputField.getTextFormatter().valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
    }
}

bindBidirectional() încearcă să lege valoarea convertită a TextField la o componentă de tip SimpleDoubleProperty care există în altă parte. Dar acest lucru returnează următoarea eroare:

method Property.bindBidirectional(Property<CAP#1>) is not applicable
(argument mismatch; SimpleDoubleProperty cannot be converted to Property<CAP#1>)

În esență, vreau să folosesc valoarea TextField (nu valoarea getText()ci valoarea convertită) pentru a o lega de alte proprietăți.

Îmi dau seama că este ceva în neregulă cu inferența de tip capturată cu TextFormatter, dar nu văd nicăieri în JavaDocs care să arate cum se poate utiliza valoarea dublă a TextFormatter. Care este rostul utilizării unui DoubleStringConverter pentru a converti valoarea dacă nu există o modalitate simplă de a extrage acea valoare dublă din TextField? Aș putea folosi Double.parseDouble(inputField.getText()) dar acest lucru pare inutil dacă m-am chinuit deja să configurez un TextFormatter frumos pentru acest câmp.

Cum pot folosi valoarea proprietății ValueProperty a TextFormatter în afara SomeComponent?

1 răspunsuri
Slaw

textFormatter este o proprietate ObjectProperty<TextFormatter<?>>. Din moment ce TextInputControl nu este generică, nu există nicio modalitate de a parametriza în mod corespunzător proprietatea textFormatter de unde și caracterul sălbatic. Acest lucru înseamnă că, de fiecare dată când interoghezi proprietatea, vei primi un răspuns TextFormatter<?> indiferent dacă a fost setată anterior, de exemplu, la un TextFormatter<Double>. Există câteva modalități de a rezolva această problemă:

  1. Transformați rezultatul în orice tip generic pe care îl așteptați:

    var formatter = (TextFormatter<Number>) comp.inputField.getTextFormatter();
    formatter.valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
    

    Bineînțeles, acest lucru va duce la un avertisment de cast necontrolat. Puteți elimina avertismentul, dacă doriți, prin intermediul unui parametru @SuppressWarnings("unchecked") dar operațiunea rămâne nesigură.

  2. Păstrați propria dvs. referință la TextFormatter<Number> și furnizați o metodă pentru ca alte coduri să o obțină.

    public SomeComponent implements Initializable {
    
        @FXML
        public TextField inputField;
    
        // maintain generic information
        private TextFormatter<Number> inputFieldFormatter;
    
        public int min;
    
        public void initialize(URL location, ResourceBundle resources) {
            UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
                String newText = change.getControlNewText();
                if (newText.matches("-?[0-9]{1,13}(\.[0-9]*)?")) { 
                    return change;
                }
                return null;
            };
    
            inputFieldFormatter = new TextFormatter<>(new NumberStringConverter(), min, doubleFilter);
            inputField.setTextFormatter(inputFieldFormatter)); 
        }
    
        // use this method in your other controller
        public TextFormatter<Number> getInputFieldFormatter() {
            return inputFieldFormatter;
        }
    }
    

Observați că în fiecare caz am folosit un TextFormatter<Number>. Acest lucru se datorează faptului că un DoubleProperty este un Property<Number> iar metoda bindBidirectional se așteaptă la o potrivire generică exactă, spre deosebire de metoda bind care are o limită superioară. Acest lucru a însemnat, de asemenea, că a NumberStringConverter a trebuit să fie utilizat.

Comentarii

  • Genial! De asemenea, vă mulțumim pentru că ați subliniat problema numărului vs. dublu. Un set dificil de generice cu care să lucrezi! –  > Por joshsweaney.