如何根据是否在JavaFX8 TableView中选择了CheckBoxTableCell来设置TextFieldTableCell的可编辑性?

时间:2018-10-06 04:33:35

标签: javafx tableview javafx-8 changelistener

我正在尝试根据是否勾选了TextFieldTableCell(位于同一行)来设置CheckBoxTableCell的可编辑性。因此,例如,如果第二行的复选框被打勾,如下所示,则“ B”处的文本应可编辑。如果未选中该复选框,则“ B”应不可编辑。

Example

我的计划是在TextFieldTableCell的{​​{1}}的“选定”侦听器中设置CheckBoxTableCell的可编辑性。另外,我可以在setCellFactory的{​​{1}}中进行设置。

但是,无论哪种方式,我首先必须获取与单击的TableView位于同一行的ListChangeListener 对象

我该怎么做?我被困了几天试图找出答案。

这是TextFieldTableCell的“选定”侦听器的代码段,其中显示了我要执行的操作和遇到的问题:

CheckBoxTableCell

我已经阅读并尝试了Make individual cell editable in JavaFX tableviewJavafx, get the object referenced by a TableCellTableview make specific cell or row editable。虽然我认为我了解它们,但我无法使其适应我想要做的事情。

这是上面显示的示例的MVCE。

我正在使用JavaFX8(JDK1.8.0_181),NetBeans 8.2和Scene Builder 8.3。

CheckBoxTableCell

1 个答案:

答案 0 :(得分:1)

应用用户kleopatra的建议后,我可以使它正常工作。

最简单的解决方案是,如果未勾选CheckBoxTableCell,则忽略编辑。 TreeTableView : setting a row not editable对此进行了说明,这也是我在下面的MVCE中使用的方法。

或者,可以通过将TextFieldTableCell绑定到editableProperty()的值来设置CheckBoxTableCell的可编辑性。在此处JavaFX weird (Key)EventBehavior接受答案之后,代码如下所示:

@Override
public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);
    doUpdate(item, getIndex(), empty);
}

@Override
public void updateIndex(int index) {
    super.updateIndex(index);
    doUpdate(getItem(), index, isEmpty());
}

private void doUpdate(String item, int index, boolean empty) {
    if ( empty || index == getTableView().getItems().size() ) {
        setText(null);
    } else {
        BooleanProperty checkboxProperty = getTableView().getItems().get(getIndex()).checkboxProperty();
        editableProperty().bind(checkboxProperty);
    }
}

虽然解决方案不是基于获取TextFieldTableCell对象(这是我认为我需要做的),但它确实可以满足我的需要(设置一个基于复选框值的文本字段的可编辑性)。谢谢kleopatra向我指出正确的方向。

这是演示解决方案的MVCE。

package test24;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.converter.DefaultStringConverter;

public class Test24 extends Application {

    private Parent createContent() {

        //********************************************************************************************
        //Declare the TableView and its underlying ObservableList and change listener
        TableView<TestModel> table = new TableView<>();

        ObservableList<TestModel> olTestModel = FXCollections.observableArrayList(testmodel -> new Observable[] {
                testmodel.checkboxProperty()
        });

        olTestModel.addListener((ListChangeListener.Change<? extends TestModel > c) -> {
            while (c.next()) {
                if (c.wasUpdated()) {
                    //...
                } 
            }
        });

        olTestModel.add(new TestModel(false, "A"));
        olTestModel.add(new TestModel(false, "B"));
        olTestModel.add(new TestModel(false, "C"));

        table.setItems(olTestModel);

        //********************************************************************************************
        //Declare the CheckBox column
        TableColumn<TestModel, Boolean> colCheckbox = new TableColumn<>("checkbox");
        colCheckbox.setCellValueFactory(cellData -> cellData.getValue().checkboxProperty());
        colCheckbox.setCellFactory(CheckBoxTableCell.forTableColumn(colCheckbox));

        //********************************************************************************************
        //Declare the text column whose editability needs to change depending on whether or
        //not the CheckBox is ticked
        TableColumn<TestModel, String> colText = new TableColumn<>("text");
        colText.setCellValueFactory(cellData -> cellData.getValue().textProperty());
        //Don't setEditable() to false here, otherwise updateItem(), updateIndex() and startEdit() won't fire
        colText.setEditable(true);
        colText.setCellFactory(cb -> {

            DefaultStringConverter converter = new DefaultStringConverter();
            TableCell<TestModel, String> cell = new TextFieldTableCell<TestModel, String>(converter) {

                @Override
                public void startEdit() {
                    boolean checkbox = getTableView().getItems().get(getIndex()).getCheckbox();
                    if ( checkbox == true ) {
                        super.startEdit();
                    }
                }

            };

            return cell;

        });

        //********************************************************************************************
        //Column to show what's actually in the TableView's data model for the checkbox
        TableColumn<TestModel, Boolean> colDMVal = new TableColumn<>("data model value");
        colDMVal.setCellValueFactory(cb -> cb.getValue().checkboxProperty());
        colDMVal.setEditable(false);

        table.getSelectionModel().setCellSelectionEnabled(true);
        table.setEditable(true);

        table.getColumns().add(colCheckbox);
        table.getColumns().add(colDMVal);
        table.getColumns().add(colText);

        BorderPane content = new BorderPane(table);

        return content;

    }

    public class TestModel {

        private BooleanProperty checkbox;
        private StringProperty text;

        public TestModel() {
            this(false, "");
        }

        public TestModel(
            boolean checkbox,
            String text
        ) {
            this.checkbox = new SimpleBooleanProperty(checkbox);
            this.text = new SimpleStringProperty(text);
        }

        public Boolean getCheckbox() {
            return checkbox.get();
        }

        public void setCheckbox(boolean checkbox) {
            this.checkbox.set(checkbox);
        }

        public BooleanProperty checkboxProperty() {
            return checkbox;
        }

        public String getText() {
            return text.get();
        }

        public void setText(String text) {
            this.text.set(text);
        }

        public StringProperty textProperty() {
            return text;
        }

    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setTitle("Test");
        stage.setWidth(500);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}