如何根据是否在 JavaFX8 TableView 中选择了 CheckBoxTableCell 来设置 TextFieldTableCell 的可编辑性?
How to set the editability of a TextFieldTableCell based on whether or not a CheckBoxTableCell is selected in a JavaFX8 TableView?
我正在尝试设置 TextFieldTableCell
的可编辑性,具体取决于 CheckBoxTableCell
(位于同一行)是否被勾选。因此,例如,如果如下所示勾选第二行中的复选框,则 "B" 处的文本应该是可编辑的。如果未选中该复选框,则 "B" 不应可编辑。
我的计划是在 CheckBoxTableCell
的 setCellFactory
的 "selected" 侦听器中设置 TextFieldTableCell
的可编辑性。或者,我可以在 TableView
的 ListChangeListener
.
中设置它
但是,无论哪种方式,我首先必须获得与单击的 CheckBoxTableCell
在同一行的 TextFieldTableCell
对象 。
我该怎么做?我已经被困了几天试图弄明白。
这是 CheckBoxTableCell
的 "selected" 侦听器的代码片段,它显示了我正在尝试做什么以及我被困在哪里:
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);
});
我已经阅读并试验过 Make individual cell editable in JavaFX tableview, Javafx, get the object referenced by a TableCell and 。虽然我认为我理解它们,但我无法使它们适应我正在尝试做的事情。
这是上面示例的 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);
}
}
在采纳了用户 kleopatra 的建议后,我成功了。
最简单的解决方案是在 CheckBoxTableCell
未勾选的情况下简单地忽略编辑。这在此处 的接受答案中有所描述,也是我在下面的 MVCE 中使用的内容。
或者,TextFieldTableCell
的可编辑性可以通过将其 editableProperty()
绑定到 CheckBoxTableCell
的值来设置。按照此处接受的答案 ,代码如下所示:
@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);
}
}
我正在尝试设置 TextFieldTableCell
的可编辑性,具体取决于 CheckBoxTableCell
(位于同一行)是否被勾选。因此,例如,如果如下所示勾选第二行中的复选框,则 "B" 处的文本应该是可编辑的。如果未选中该复选框,则 "B" 不应可编辑。
我的计划是在 CheckBoxTableCell
的 setCellFactory
的 "selected" 侦听器中设置 TextFieldTableCell
的可编辑性。或者,我可以在 TableView
的 ListChangeListener
.
但是,无论哪种方式,我首先必须获得与单击的 CheckBoxTableCell
在同一行的 TextFieldTableCell
对象 。
我该怎么做?我已经被困了几天试图弄明白。
这是 CheckBoxTableCell
的 "selected" 侦听器的代码片段,它显示了我正在尝试做什么以及我被困在哪里:
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);
});
我已经阅读并试验过 Make individual cell editable in JavaFX tableview, Javafx, get the object referenced by a TableCell and
这是上面示例的 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);
}
}
在采纳了用户 kleopatra 的建议后,我成功了。
最简单的解决方案是在 CheckBoxTableCell
未勾选的情况下简单地忽略编辑。这在此处
或者,TextFieldTableCell
的可编辑性可以通过将其 editableProperty()
绑定到 CheckBoxTableCell
的值来设置。按照此处接受的答案
@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);
}
}