Как использовать привязку JavaFX для отключения кнопки, если текстовое поле содержит недопустимый ввод

#javafx

#javafx

Вопрос:

Я получил следующий код из окончательного руководства по современным Java-клиентам с JavaFX:

 updateButton.disableProperty()
    .bind(listView.getSelectionModel().selectedItemProperty().isNull()
            .or(wordTextField.textProperty().isEmpty())
            .or(definitionTextArea.textProperty().isEmpty()));
  

Я хотел бы изменить его, чтобы кнопка была отключена, если введенная строка frequencyTextField не является неотрицательным целым числом. Я добавил термин к соединению, как показано:

 updateButton.disableProperty()
    .bind(listView.getSelectionModel().selectedItemProperty().isNull()
            .or(isLegalFrequency(frequencyTextField.textProperty()).not())
            .or(wordTextField.textProperty().isEmpty())
            .or(definitionTextArea.textProperty().isEmpty()));
  

Хотя это, вероятно, не имеет значения, вот метод, который проверяет правильность:

     private BooleanProperty isLegalFrequency(StringProperty sp) {
        System.out.println("isLegalFrequency("   sp.get()   ")");
        try {
            int value = Integer.parseInt(sp.get());
            return new SimpleBooleanProperty(value >= 0);
        } catch (NumberFormatException e) {
            return new SimpleBooleanProperty(false);
        }
    }
  

Моя проблема в том, что кнопка всегда отключена. Я установил, что isLegalFrequency() это вызывается только один раз, когда создается сцена. Это имеет смысл, поскольку я передаю frequencyTextField.textProperty() , а не вызываю для него метод (который, предположительно, настраивает прослушиватель за кулисами).

Есть ли способ изменить программу без добавления явного прослушивателя, чтобы она вела себя так, как я хотел, или необходимо создать ChangeListener on frequencyTextField.textProperty ?

Ответ №1:

В общем случае вы можете создать произвольный метод:

 private Boolean validate() {
    // arbitrary implementation here...
    // in your case something like
    if (listView.getSelectionModel().getSelectedItem() == null) return false ;
    if (wordTextField.getText().isEmpty()) return false ;
    if (definitionTextArea.getText().isEmpty()) return false ;
    if (! isLegalFrequency(frequencyTextField.getText())) return false ;
    return true ;
}
  

а затем выполните

 updateButton.disableProperty().bind(Bindings.createBooleanBinding(
    () -> ! validate(),
    listView.getSelectionModel().selectedItemProperty(),
    frequencyTextField.textProperty(),
    wordTextField.textProperty(),
    definitionTextArea.textProperty()));
  

Параметрами createBooleanBinding() метода являются a Callable<Boolean> (т. Е. Метод, не принимающий параметров и возвращающий a Boolean ), За которым следует ноль или более экземпляров javafx.beans.Observable (любое свойство или ObservableList и т. Д. Будет работать). Вы должны включить здесь любое свойство (или другое наблюдаемое), которое должно вызвать пересчет disableProperty() при его изменении.