是否可以在 JavaFX8 中逐行禁用 editable table 列?
Is it possible to disable editable table columns on a row basis in JavaFX8?
我有一个用例,我认为它是非常标准的,但是我一直无法找到关于具体如何执行此操作的示例,或者如果可能的话。
假设我有以下 TableView
First Name Last Name Street NewRecord
Tom Smith Main St. Yes
Mike Smith First St. No
在这种情况下,网格的前三个单元格应该是可编辑的,因为记录是新的,但是如果记录不是新的,那么应该禁用姓氏单元格。
我在 CellFactory 和 RowFactory 中尝试过这个 - 但还没有找到实现这个的方法。
感谢您的帮助。
最简单的方法是使用第三方绑定库:ReactFX 2.0 内置了此功能,如 here 所述。使用它你可以做到
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
TableCell<Person, String> cell = new TextFieldTableCell<>();
cell.editableProperty().bind(
// horrible cast needed because TableCell.tableRowProperty inexplicably returns a raw type:
Val.flatMap(cell.tableRowProperty(), row -> (ObservableValue<Person>)row.itemProperty())
.flatMap(Person::newRecordProperty)
.orElseConst(false));
return cell ;
});
(假设一个 Person
table 模型对象具有明显的 JavaFX 属性和方法)。
没有库,你需要一个非常糟糕的嵌套监听器列表:
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
TableCell<Person, String> cell = new TextFieldTableCell<>();
ChangeListener<Boolean> newRecordListener = (obs, wasNewRecord, isNewRecord) -> updateEditability(cell);
ChangeListener<Person> rowItemListener = (obs, oldPerson, newPerson) -> {
if (oldPerson != null) {
oldPerson.newRecordProperty().removeListener(newRecordListener);
}
if (newPerson != null) {
newPerson.newRecordProperty().addListener(newRecordListener);
}
updateEditability(cell);
};
ChangeListener<TableRow> rowListener = (obs, oldRow, newRow) -> {
if (oldRow != null) {
((ObservableValue<Person>)oldRow.itemProperty()).removeListener(rowItemListener);
if (oldRow.getItem() != null) {
((Person)oldRow.getItem()).newRecordProperty().removeListener(newRecordListener);
}
}
if (newRow != null) {
((ObservableValue<Person>)newRow.itemProperty()).addListener(rowItemListener);
if (newRow.getItem() != null) {
((Person)newRow.getItem()).newRecordProperty().addListener(newRecordListener);
}
}
updateEditability(cell);
};
cell.tableRowProperty().addListener(rowListener);
return cell ;
});
然后
private void updateEditability(TableCell<Person, String> cell) {
if (cell.getTableRow() == null) {
cell.setEditable(false);
} else {
TableRow<Person> row = (TableRow<Person>) cell.getTableRow();
if (row.getItem() == null) {
cell.setEditable(false);
} else {
cell.setEditable(row.getItem().isNewRecord());
}
}
}
使用 "legacy style" API 的替代方法是
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
TableCell<Person, String> cell = new TextFieldTableCell<>();
cell.editableProperty().bind(
Bindings.selectBoolean(cell.tableRowProperty(), "item", "newRecord"));
return cell ;
});
我不喜欢这个选项,因为它缺乏任何类型安全性(或者实际上根本没有任何编译器检查),此外,在某些早期版本的 JavaFX 中,如果 "chain" 有空值(在这种情况下,它们经常会出现)。我相信后一个问题已解决,但恕我直言,ReactFX 版本要好得多。
您始终可以通过设置事件处理程序来检查操作是否合法来停止编辑。
columnName.setOnEditStart(
new EventHandler<CellEditEvent<ItemClass, String>>(){
@Override
public void handle(CellEditEvent<ItemClass, String> event) {
if(event.getTableColumn().getCellData(3).compareTo("yes") == 0) {
event.getTableView().edit(-1, null);
//this prevents the editing in "progress"
}
}
}
);
我有一个用例,我认为它是非常标准的,但是我一直无法找到关于具体如何执行此操作的示例,或者如果可能的话。
假设我有以下 TableView
First Name Last Name Street NewRecord
Tom Smith Main St. Yes
Mike Smith First St. No
在这种情况下,网格的前三个单元格应该是可编辑的,因为记录是新的,但是如果记录不是新的,那么应该禁用姓氏单元格。
我在 CellFactory 和 RowFactory 中尝试过这个 - 但还没有找到实现这个的方法。
感谢您的帮助。
最简单的方法是使用第三方绑定库:ReactFX 2.0 内置了此功能,如 here 所述。使用它你可以做到
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
TableCell<Person, String> cell = new TextFieldTableCell<>();
cell.editableProperty().bind(
// horrible cast needed because TableCell.tableRowProperty inexplicably returns a raw type:
Val.flatMap(cell.tableRowProperty(), row -> (ObservableValue<Person>)row.itemProperty())
.flatMap(Person::newRecordProperty)
.orElseConst(false));
return cell ;
});
(假设一个 Person
table 模型对象具有明显的 JavaFX 属性和方法)。
没有库,你需要一个非常糟糕的嵌套监听器列表:
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
TableCell<Person, String> cell = new TextFieldTableCell<>();
ChangeListener<Boolean> newRecordListener = (obs, wasNewRecord, isNewRecord) -> updateEditability(cell);
ChangeListener<Person> rowItemListener = (obs, oldPerson, newPerson) -> {
if (oldPerson != null) {
oldPerson.newRecordProperty().removeListener(newRecordListener);
}
if (newPerson != null) {
newPerson.newRecordProperty().addListener(newRecordListener);
}
updateEditability(cell);
};
ChangeListener<TableRow> rowListener = (obs, oldRow, newRow) -> {
if (oldRow != null) {
((ObservableValue<Person>)oldRow.itemProperty()).removeListener(rowItemListener);
if (oldRow.getItem() != null) {
((Person)oldRow.getItem()).newRecordProperty().removeListener(newRecordListener);
}
}
if (newRow != null) {
((ObservableValue<Person>)newRow.itemProperty()).addListener(rowItemListener);
if (newRow.getItem() != null) {
((Person)newRow.getItem()).newRecordProperty().addListener(newRecordListener);
}
}
updateEditability(cell);
};
cell.tableRowProperty().addListener(rowListener);
return cell ;
});
然后
private void updateEditability(TableCell<Person, String> cell) {
if (cell.getTableRow() == null) {
cell.setEditable(false);
} else {
TableRow<Person> row = (TableRow<Person>) cell.getTableRow();
if (row.getItem() == null) {
cell.setEditable(false);
} else {
cell.setEditable(row.getItem().isNewRecord());
}
}
}
使用 "legacy style" API 的替代方法是
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
TableCell<Person, String> cell = new TextFieldTableCell<>();
cell.editableProperty().bind(
Bindings.selectBoolean(cell.tableRowProperty(), "item", "newRecord"));
return cell ;
});
我不喜欢这个选项,因为它缺乏任何类型安全性(或者实际上根本没有任何编译器检查),此外,在某些早期版本的 JavaFX 中,如果 "chain" 有空值(在这种情况下,它们经常会出现)。我相信后一个问题已解决,但恕我直言,ReactFX 版本要好得多。
您始终可以通过设置事件处理程序来检查操作是否合法来停止编辑。
columnName.setOnEditStart(
new EventHandler<CellEditEvent<ItemClass, String>>(){
@Override
public void handle(CellEditEvent<ItemClass, String> event) {
if(event.getTableColumn().getCellData(3).compareTo("yes") == 0) {
event.getTableView().edit(-1, null);
//this prevents the editing in "progress"
}
}
}
);