JavaFX Привязать valueProperty из TextFormatter TextField к SimpleDoubleProperty - PullRequest
2 голосов
/ 20 марта 2020

У меня есть TextField, которому был присвоен TextFormatter, который имеет фильтр, который принимает ввод текстового поля и гарантирует, что он в двойном формате. Затем он использует DoubleStringConverter для преобразования отфильтрованного текста в двойное значение. Это в пользовательском компоненте F XML. Ниже приведен минимальный пример.

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)); 
    }
}

Другой компонент F XML, который использует этот компонент ...

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

bindBidirectional () пытается связать преобразованное значение TextField, к SimpleDoubleProperty, который существует в другом месте. Но это возвращает следующую ошибку:

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

По сути, я хочу использовать значение TextField (не getText(), а преобразованное значение) для привязки к другим свойствам.

Я понимаю, что с выводом захваченного типа в TextFormatter что-то не так, но я не вижу нигде в JavaDocs, где показано, как использовать двойное значение TextFormatter. Какой смысл использовать DoubleStringConverter для преобразования значения, если нет простого способа извлечь это значение из TextField? Я мог бы использовать Double.parseDouble(inputField.getText()), но это кажется бессмысленным, если я уже столкнулся с проблемой настройки хорошего TextFormatter для поля.

Как использовать valueProperty TextFormatter вне SomeComponent?

1 Ответ

3 голосов
/ 20 марта 2020

Свойство textFormatter является ObjectProperty<TextFormatter<?>>. Так как класс TextInputControl не является обобщенным c, нет способа правильно параметризировать свойство textFormatter, следовательно, подстановочный знак. Это означает, что всякий раз, когда вы запрашиваете свойство, вы получаете TextFormatter<?> независимо от того, предварительно ли оно установлено, например, TextFormatter<Double>. Есть несколько способов решить эту проблему:

  1. Привести результат к тому типу generi c, который вы ожидаете:

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

    Конечно, это приведет к непроверенное предупреждение. Вы можете отключить предупреждение, если хотите, с помощью аннотации @SuppressWarnings("unchecked"), но операция остается небезопасной.

  2. Сохраните собственную ссылку на TextFormatter<Number> и предоставьте метод для получения другого кода это.

    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;
        }
    }
    

Обратите внимание, в каждом случае я использовал TextFormatter<Number>. Это связано с тем, что DoubleProperty - это Property<Number>, а метод bindBidirectional ожидает точного соответствия generi c, в отличие от метода bind, который ограничен сверху. Это также означало, что нужно использовать NumberStringConverter.

...