JavaFX, как проверить, все ли динамически добавленные текстовые поля пусты - PullRequest
1 голос
/ 15 апреля 2020

У меня есть TextField и две кнопки подряд. Одна кнопка (кнопка «Добавить») добавляет другую строку TextField и другую пару кнопок добавления и удаления, другая кнопка удаляет строку. Кнопка удаления отключена, пока текущая строка является единственной строкой, поэтому не может быть никаких строк.

Кнопка добавления активна, только если текстовое поле текущей строки не пустое и если оно является последнее текстовое поле. Поэтому каждая строка имеет отключенную «кнопку добавления», за исключением последней.

Мой вопрос сейчас заключается в том, как связать «кнопку добавления» disableProperty со всеми существующими текстовыми полями и проверить, не являются ли они пустыми. На самом деле, я думаю, что мне нужно только проверить последнее текстовое поле, и если оно пустое, я отключаю последнюю «кнопку добавления», если что-то написано, последняя «кнопка добавления» остается отключенной, но активируется текущая строка .

Я нашел обходной путь, при котором я привязываю кнопку к текстовому полю, затем, если я добавляю еще одну строку, я отсоединяю кнопку, отключаю ее, а если я удаляю строку, я активирую только последнюю кнопку и привязать его снова к текстовому полю. Это решение кажется очень неуклюжим, и мне было интересно, есть ли более элегантное решение с привязкой свойств.

Мой код (с обходным решением, чтобы вы могли видеть, что я хочу сделать):

public class Controller {
@FXML
private VBox VBox;

public ObservableList<TextField> oList = FXCollections.observableArrayList();
public ObservableList<Button> bList = FXCollections.observableArrayList();

public void initialize(){
    createRow();
}

private void createRow(){
    HBox box = new HBox(10);
    TextField textField = new TextField();
    Button addButton = new Button("Add row");
    Button deleteButton = new Button("Delete");
    box.getChildren().addAll(textField, addButton, deleteButton);
    VBox.getChildren().add(box);

    oList.add(textField);
    bList.add(addButton);

    addButton.disableProperty().bind(Bindings.isEmpty(textField.textProperty()));

    addButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            addButton.disableProperty().unbind();
            createRow();
            textField.setDisable(true);
            addButton.setDisable(true);
        }
    });

    deleteButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {

            int idx = oList.indexOf(textField);
            oList.remove(idx);
            bList.remove(idx);
            VBox.getChildren().remove(idx);

            for(TextField tf : oList){
                int i = oList.indexOf(tf);
                if(oList.size()-1 == i){
                    tf.setDisable(false);
                    bList.get(i).disableProperty().bind(Bindings.isEmpty(tf.textProperty()));
                }
            }


        }
    });

}

}

и два снимка экрана:

4 строки добавлены, все «кнопки добавления» отключены, также последняя из них b c в текстовом поле ничего не написано

Здесь я удалил строку test1, а пустая строка и все «кнопки добавления» по-прежнему отключены, кроме последний, потому что в текстовом поле есть текст

Спасибо за вашу помощь!

PS: я знаю, что в моем коде ObservableLists не нужны, но я пробовал что-то и позволил им потому что я забыл ...

1 Ответ

1 голос
/ 15 апреля 2020

Вы можете создать BooleanExpression, который возвращает true, если все TextField в списке пусты. Обратите внимание, что вам нужно воссоздать это выражение как содержимое изменения ObservableList<TextField> ':

oList.addListener((ListChangeListener<? super TextField>) c -> {
    addButton.disableProperty().unbind();
    BooleanExpression allEmpty = oList.stream()
            .map(tf -> BooleanExpression.booleanExpression(tf.textProperty().isEmpty()))
            .reduce(new SimpleBooleanProperty(true), BooleanExpression::and);
    addButton.disableProperty().bind(allEmpty);
});

Каждый раз, когда добавляется или удаляется новый TextField, каждый TextField в списке будет сопоставлен с BooleanExpression свойства empty этого TextField. Затем все выражения будут объединены.

Примечание : аналогичным образом можно также использовать al oop вместо потока.

Примечание : вам нужно добавить этот слушатель перед добавлением любого элемента в список.

...