提问人:Hexadelta 提问时间:11/14/2023 最后编辑:Hexadelta 更新时间:11/15/2023 访问量:64
Javafx - 使 TableView 单元格在编辑后更改样式
Javafx - Making a TableView Cell Change Style After Being Edited
问:
我试图在这里制作一个 TableView,当单元格的值被修改时(用户可以单击单元格并键入一个新值),如果方法 isValid 返回 false,则单元格会从样式表中获得无效单元格样式。
目前,编辑部分工作正常,isValid 根据控制台输出返回它应该返回的内容。但是,当 isValid 返回 false 时,单元格未获得 invalid-cell 属性。
我知道无效单元格样式是可访问的,因为已将样式添加到整个列中,但我无法做到只是一次更改样式的修改单元格。有什么想法吗?谢谢。column.getStyleClass().add("invalid-cell");
public void loadTable(String tableName) throws SQLException {
//Clear existing columns and entries
tableView.getColumns().clear();
tableView.getItems().clear();
ObservableList<String> data = DBcontroller.getColumns(handler.getTable());
//For each column, add to table
for (int i = 0; i < data.size(); i++) {
int finalIdx = i;
TableColumn<ObservableList<String>, String> column = new TableColumn<>(data.get(i));
column.setPrefWidth(100); //Set width
//Factory (gets column data)
column.setCellValueFactory(param -> {
String cellValue = param.getValue().get(finalIdx);
return new SimpleStringProperty(cellValue);
});
//Make cells editable.
column.setCellFactory(TextFieldTableCell.forTableColumn(new DefaultStringConverter()));
column.setEditable(true);
column.setOnEditCommit(event -> {
ObservableList<String> rowData = event.getTableView().getItems().get(event.getTablePosition().getRow());
rowData.set(finalIdx, event.getNewValue());
TableCell<ObservableList<String>, String> currentCell = event.getTableColumn().getCellFactory().call(column);
if (isValid(event.getNewValue(), column.getText())) {
System.out.println("Input OK!");
currentCell.getStyleClass().remove("invalid-cell");
} else {
System.out.println("Input BAD");
currentCell.getStyleClass().add("invalid-cell");
}
});
tableView.getColumns().add(column);
}
目前使用包含的代码,即使 isValid 返回 false,也没有单元格获得样式。
答:
在这种情况下,我通常做的是将逻辑放在 .cellFactory
column.setCellFactory(x-> {
TableCell<EventVW, Date> cell = new TableCell<EventVW, Date>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
ObservableList<String> styleClass = getStyleClass();
styleClass.remove("err-class");
} else {
setText(item);
styleClass.remove("err-class");
if(!isValid(item)) {
styleClass.add("err-class");
}
}
}
};
因此,每当更新单元格值时,样式也会根据本例中的某个函数 () 进行更新isValid
如果使用 PseudoClasses 完成,这是最干净的。此外,无论验证例程是什么,它都需要足够简单,可以在“视图”中完成,而不需要数据库查找或复杂的业务逻辑。
public class ValidatingTableCell<S> extends TableCell<S, String> {
private static final PseudoClass redDisplay = PseudoClass.getPseudoClass("error");
public ValidatingTableCell() {
TextField textField = new TextField();
textField.textProperty().bind(itemProperty());
StackPane container = new StackPane(textField);
container.getStyleClass().add("cell-box");
container.setPadding(new Insets(8));
itemProperty().addListener(itemProperty -> container.pseudoClassStateChanged(redDisplay, validateValue()));
graphicProperty().bind(Bindings.createObjectBinding(() -> !isEmpty() ? container : null, emptyProperty()));
setText(null);
}
private boolean validateValue() {
String theValue = itemProperty().get();
return theValue == null || theValue.startsWith("A");
}
}
CSS 文件如下所示:
.cell-box {
-fx-background-color: green;
}
.cell-box:error {
-fx-background-color: red;
}
这种方法可能看起来有点奇怪,因为它不使用通常的方法,而是绑定到 ,并在创建布局的构造函数中执行所有连接。不过,结果是一样的。updateItem()
itemProperty()
Cell
Cell
在此示例中,任何值以“A”开头的内容都将被视为无效,并且将在 .验证作为逻辑的一部分包含在内,以表明它确实需要简单才能包含在布局中。TextField
Cell
如果验证逻辑更复杂,则应将数据转换为数据和有效标志的包含字段。然后,应在业务逻辑中定义数据本身和有效标志之间的链接。Cell
Object
评论