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

У меня есть таблица, в которой перечислены объекты типа Bot, у которых есть имя и свойства isOn, которые я хочу перечислить:

private SimpleStringProperty name;
private boolean isOn;

Логическое значение включено, я хочу, чтобы его читали с флажка, а также редактировали с этого флажка.

До сих пор я мог добавить флажок в столбец в моей таблице для каждой строки, но это чисто визуально (т. Е. Он не привязан к члену Bot isOn).

Как я могу заставить флажок читать и писать от и к этому члену Bot?

Вот мой код, связанный с таблицей в целом:

ObservableList<Bot> bots = FXCollections.observableArrayList();
@FXML
private TableView<Bot> botTable;
@FXML
private TableColumn<Bot, String> nameColumn;
@FXML
private TableColumn<Bot, Boolean> statusColumn;

public void initialize(URL location, ResourceBundle resources){
    nameColumn.setCellValueFactory(new PropertyValueFactory<Bot, String>("name"));
    statusColumn.setCellValueFactory(new PropertyValueFactory<Bot, Boolean>("on"));
    statusColumn.setSortable(false);

    statusColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Bot, Boolean>, ObservableValue<Boolean>>(){
        @Override public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Bot, Boolean> features) {
            return new SimpleBooleanProperty(features.getValue() != null);
        }
    });

    // create a cell value factory with an add button for each row in the table.
    statusColumn.setCellFactory(new Callback<TableColumn<Bot, Boolean>, TableCell<Bot, Boolean>>() {
        @Override public TableCell<Bot, Boolean> call(TableColumn<Bot, Boolean> personBooleanTableColumn) {
            return new AddBotCell(/*stage, botTable*/);
        }
    });

    botTable.setItems(bots);
}

/** A table cell containing a button for adding a new person. */
private class AddBotCell extends TableCell<Bot, Boolean> {
    // a checkbox for adding a new bot.
    final CheckBox checkbox = new CheckBox();
    // pads and centers the add button in the cell.
    final StackPane paddedCheckBox = new StackPane();

    AddBotCell(/*final Stage stage, final TableView table*/) {
        paddedCheckBox.setPadding(new Insets(3));
        paddedCheckBox.getChildren().add(checkbox);
        checkbox.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
            }
        });
    }
    /** places an add checkbox in the row only if the row is not empty. */
    @Override protected void updateItem(Boolean item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            setGraphic(checkbox);
        }
    }
}

person Luca Guarro    schedule 26.04.2018    source источник


Ответы (1)


Вам нужно снять флажок, если ячейка становится пустой. Кроме того, вам необходимо обновить значение, когда пользователь взаимодействует с CheckBox. Это лучше сделать от слушателя к свойству selected:

private class AddBotCell extends TableCell<Bot, Boolean> {
    // a button for adding a new person.
    final CheckBox checkbox = new CheckBox();
    // pads and centers the add button in the cell.
    final StackPane paddedCheckBox = new StackPane();
    // records the y pos of the last button press so that the add person dialog can be shown next to the cell.
    final DoubleProperty buttonY = new SimpleDoubleProperty();
    private boolean updating = false;

    AddBotCell(/*final Stage stage, final TableView table*/) {
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        paddedCheckBox.setPadding(new Insets(3));
        paddedCheckBox.getChildren().add(checkbox);
        checkbox.selectedProperty().addListener((o, oldValue, newValue) -> {
            if (!updating) {
                updating = true;
                ((Bot)getTableRow().getItem()).setIsOn(newValue);
                updating = false;
            }
        });
    }

    /** places an add button in the row only if the row is not empty. */
    @Override protected void updateItem(Boolean item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null) {
            setGraphic(null);
        } else {
            setGraphic(paddedCheckBox);
            updating = true;
            checkbox.setSelected(item);
            updating = false;
        }
    }
}

Также ваш cellValueFactory должен использовать значение свойства.

statusColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Bot, Boolean>, ObservableValue<Boolean>>(){
    @Override public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Bot, Boolean> features) {
        return new SimpleBooleanProperty(features.getValue().isIsOn());
    }
});
person fabian    schedule 26.04.2018
comment
что не так с использованием CheckBoxTableCell (по сравнению с собственным)? - person kleopatra; 26.04.2018
comment
Кроме того, я не могу получить объект Bot из getTableRow().getItem(), поскольку он не позволяет мне вызвать функцию setIsOn(newValue). - person Luca Guarro; 26.04.2018
comment
Я забыл имя метода, и элемент должен быть приведен, поскольку по какой-то причине JavaFX использует необработанный тип для TableRow ячейки... Отредактировал код. Должно работать сейчас... - person fabian; 26.04.2018
comment
Работает отлично. Спасибо. - person Luca Guarro; 26.04.2018
comment
Не могли бы вы объяснить, какова цель обновления логического значения? Какую именно ошибку он предотвращает? - person Luca Guarro; 26.04.2018
comment
@LucaGuarro Если вы решите сохранить поле BooleanProperty как в классе Bot, использование setIsOn() обновит элемент, что вызовет ненужное обновление. Также вам не нужно обрабатывать обновления состояния selected, если это делается во время обновления элемента. - person fabian; 26.04.2018
comment
О, хорошо, я вижу. Таким образом, вместо примитивного логического значения, если бы я дал боту BooleanProperty в качестве члена и установил его в checkbox.selectedProperty(), где бы я ни изменил это BooleanProperty в коде, это будет отражено в флажке? - person Luca Guarro; 27.04.2018
comment
@LucaGuarro при условии, что вы вернете собственность из cellValueFactory, да. - person fabian; 27.04.2018