Как установить редактируемость TextFieldTableCell в зависимости от того, выбран или нет CheckBoxTableCell в JavaFX8 TableView?
Я пытаюсь установить редактируемость TextFieldTableCell
в зависимости от того, CheckBoxTableCell
(это в том же ряду) отмечен. Так, например, если флажок во второй строке отмечен, как показано ниже, текст в "B" должен быть редактируемым. Если флажок снят, "B" не должен редактироваться.
Мой план состоит в том, чтобы установить TextFieldTableCell
редактируемость в "выбранном" слушателе в CheckBoxTableCell
" s setCellFactory
, Кроме того, я мог бы установить его в TableView
" s ListChangeListener
,
Однако, так или иначе, я сначала должен получить TextFieldTableCell
объект, который находится в той же строке, что и нажатый CheckBoxTableCell
,
Как я могу это сделать? Я застрял на пару дней, пытаясь понять это.
Вот фрагмент кода для CheckBoxTableCell
"выбранный" слушатель, который показывает, что я пытаюсь сделать и где я застрял:
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 ответ
После применения предложений пользователя 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
Объект (который, как я думал, мне нужно было сделать), он делает именно то, что мне нужно (чтобы установить возможность редактирования текстового поля на основе значения флажка). Спасибо, Клеопатра, за то, что указал мне правильное направление.
Вот 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);
}
}