Как установить редактируемость TextFieldTableCell в зависимости от того, выбран или нет CheckBoxTableCell в JavaFX8 TableView? - PullRequest
0 голосов
/ 06 октября 2018

Я пытаюсь установить редактируемость TextFieldTableCell в зависимости от того, отмечен ли флажок CheckBoxTableCell (который находится в той же строке).Так, например, если флажок во второй строке отмечен, как показано ниже, текст в «B» должен быть редактируемым.Если флажок снят, «B» не должен редактироваться.

Example

Мой план состоит в том, чтобы установить возможность редактирования TextFieldTableCell в«выбранный» слушатель в CheckBoxTableCell s setCellFactory.Кроме того, я мог бы установить его в TableView ListChangeListener.

Однако, в любом случае, сначала я должен получить TextFieldTableCell объект , который находится в той же строке, что инажал CheckBoxTableCell.

Как мне это сделать?Я застрял в течение нескольких дней, пытаясь понять это.

Вот фрагмент кода для "10" выбранного слушателя CheckBoxTableCell, который показывает, что я пытаюсь сделать и где я 'm застрял:

selected.addListener((ObservableValue<? extends Boolean> obs, Boolean wasSelected, Boolean isSelected) -> {
    olTestModel.get(cbCell.getIndex()).setCheckbox(isSelected);
//=>TextFieldTableCell theTextFieldInThisRow = <HOW_DO_I_GET_THIS?>
    theTextFieldInThisRow.setEditable(isSelected);
});

Я читал и экспериментировал с Сделать отдельную ячейку редактируемой в JavaFX tableview , Javafx, получить объект, на который ссылается TableCell и Tableview делает редактируемой конкретную ячейку или строку .Хотя я думаю, что понимаю их, я не смог адаптировать их к тому, что я пытаюсь сделать.

Вот MVCE для примера, показанного выше.

Я использую JavaFX8 (JDK1.8.0_181), NetBeans 8.2 и Scene Builder 8.3.

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.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
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.Callback;

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()) {
                    boolean checkBoxIsSelected = olTestModel.get(c.getFrom()).getCheckbox().booleanValue();
                    //PLAN A:  Set editability here
                    //==>TextFieldTableCell theTextFieldInThisRow = <HOW_DO_I_GET_THIS?>
                    //theTextFieldInThisRow.setEditable(checkBoxIsSelected);
                } 
            }
        });

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

        table.setItems(olTestModel);

        //********************************************************************************************
        //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());        
        colText.setCellFactory(TextFieldTableCell.<TestModel>forTableColumn());        
        colText.setEditable(false);

        //********************************************************************************************
        //Declare the CheckBox column
        TableColumn<TestModel, Boolean> colCheckbox = new TableColumn<>("checkbox");

        colCheckbox.setCellValueFactory(cellData -> cellData.getValue().checkboxProperty());

        colCheckbox.setCellFactory((TableColumn<TestModel, Boolean> cb) -> {

            final CheckBoxTableCell cbCell = new CheckBoxTableCell<>();
            final BooleanProperty selected = new SimpleBooleanProperty();

            cbCell.setSelectedStateCallback(new Callback<Integer, ObservableValue<Boolean>>() {
                @Override
                public ObservableValue<Boolean> call(Integer index) {
                    return selected;
                }
            });

            selected.addListener((ObservableValue<? extends Boolean> obs, Boolean wasSelected, Boolean isSelected) -> {
                //Set the value in the data model
                olTestModel.get(cbCell.getIndex()).setCheckbox(isSelected);
                //PLAN B:  Set editability here
                //Set the editability for the text field in this row
                //==>   TextFieldTableCell theTextFieldInThisRow = <HOW_DO_I_GET_THIS?>
                //theTextFieldInThisRow.setEditable(isSelected);
            });

            return cbCell;
        });        

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

}

1 Ответ

0 голосов
/ 07 октября 2018

После применения предложений пользователя kleopatra я смог заставить это работать.

Самое простое решение - просто игнорировать изменения, если CheckBoxTableCell не отмечен.Это описано в принятом ответе здесь TreeTableView: установка строки недоступна для редактирования и это то, что я использовал в MVCE ниже.

В качестве альтернативы, редактируемость TextFieldTableCell может бытьустановить, привязав editableProperty() к значению CheckBoxTableCell.После принятого ответа здесь Странный JavaFX (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 s объект (что, как я думал, мне нужно было сделать), он делает именно то, что мне нужно (установить возможность редактирования текстового поля на основе значения флажка).Спасибо, Клеопатра, за то, что указал мне правильное направление.

Вот 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);
    }

}
...