我在使用JavaFX 2 TableView处理数据中的空值时遇到了严重问题。事实上,我已经把这个问题的简单演示放在一起,如下所示。
本质上问题是我的一些数据可能为null并且将null强制转换为值(例如空字符串)无效,它必须为null。在我正在处理的实际代码中,我有一个空日期值,为了保持示例简单,我在下面显示了一个空字符串。
表的第1行和第2行具有空值。这两列是不同的,第一列显示了TextFieldTableCell的行为,第二个是我可编辑单元格的实现。两者都表现出相同的错误行为。
目前的行为是:
在第4步,我希望调用列的onEditCommit处理程序,但事实并非如此。看一下javax.scene.control.TableCell的源代码,因为commitEdit的第一行是:
if (! isEditing()) return;
似乎因为单元格为null,编辑属性永远不会设置为true,尽管我承认我还没有遍历所有代码,看看为什么它永远不会被切换为true。
一如既往地感谢您的帮助。
实施例
主要申请
package example;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Stage;
import javafx.util.Callback;
public class NullCellEditingExample extends Application {
private TableView table = new TableView();
private final ObservableList<Person> data =
FXCollections.observableArrayList( new Person(null, "Smith"), new Person("Isabella", null),
new Person("Ethan", "Williams"), new Person("Emma", "Jones"), new Person("Michael", "Brown"));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
TableColumn firstNameCol = createSimpleFirstNameColumn();
TableColumn lastNameCol = createLastNameColumn();
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol);
table.setEditable(true);
((Group) scene.getRoot()).getChildren().addAll(table);
stage.setScene(scene);
stage.show();
}
private TableColumn createSimpleFirstNameColumn() {
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
@Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue());
}
});
return firstNameCol;
}
private TableColumn createLastNameColumn() {
Callback<TableColumn, TableCell> editableFactory = new Callback<TableColumn, TableCell>() {
@Override
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(editableFactory);
lastNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
@Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
t.getRowValue().setLastName(t.getNewValue());
}
});
return lastNameCol;
}
}
编辑单元格
package example;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
@Override
public void startEdit() {
super.startEdit();
if( textField == null ) {
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
if (!arg2) { commitEdit(textField.getText()); }
}
});
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
String value = textField.getText();
if (value != null) { commitEdit(value); } else { commitEdit(null); }
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
人
package example;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
public Person(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public SimpleStringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public SimpleStringProperty lastNameProperty() {
return lastName;
}
}
答案 0 :(得分:2)
自发布以来,我发现another question基本相同。他们采用的方法总是避免使用对字符串很好的空值(例如使用空字符串),但对于没有明显“空”值的日期或其他数据类型则不可接受。
解决方案是将值false传递给EditingCell.updateItem方法中的super.updateItem调用。如果有人对整个分析感兴趣,我已经整理了full write up这个。