【发布时间】:2019-07-12 18:35:03
【问题描述】:
我正在尝试使用 Oracle 糟糕的教程创建可编辑单元格。我发现他们的EditCell 类仅在我单击我当前编辑的同一行或任何行之外时更新。如果我单击另一行,则会取消编辑。这是本教程的链接,在它的最后你可以找到EditCell 类,但这不是这个问题的重点:
https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm
此类创建TextField 用于编辑目的。单击另一行会启动cancel() 方法。还有这个代码行:
setText((String( getItem());
阻止编辑。我将其替换为:
setText((String) textField.getText());
现在编辑工作。但在编辑此单元格后,旧值再次加载到TextField。我猜ObservableList 在第一次编辑后没有更新。
这是 FXML 代码:
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<TableView GridPane.columnIndex="0" GridPane.rowIndex="1" items="${controller.data}" editable="true">
<columns>
<TableColumn fx:id="colName" text="name">
<cellValueFactory>
<PropertyValueFactory property="Name"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="colSurname" text="surname">
<cellValueFactory>
<PropertyValueFactory property="Surname"/>
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</GridPane>
在控制器中我声明ObservableList:
public class Controller {
@FXML
private TableColumn<Person, String> colName;
@FXML
private TableColumn<Person, String> colSurname;
@FXML
private ObservableList<Person> data;
public Controller(){
data = FXCollections.observableArrayList(
new Person("John", "S."),
new Person("Jane", "S.")
);
}
public TableColumn<Person, String> getColName() {
return colName;
}
public void setColName(TableColumn<Person, String> colName) {
this.colName = colName;
}
public TableColumn<Person, String> getColSurname() {
return colSurname;
}
public void setColSurname(TableColumn<Person, String> colSurname) {
this.colSurname = colSurname;
}
public ObservableList<Person> getData() {
return data;
}
public void setData(ObservableList<Person> data) {
this.data = data;
}
}
Person.java 代码:
public class Person {
private final SimpleStringProperty name;
private final SimpleStringProperty surname;
public Person(String name, String surname){
this.name = new SimpleStringProperty(name);
this.surname = new SimpleStringProperty(surname);
}
public String getName() {
return name.get();
}
public SimpleStringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getSurname() {
return surname.get();
}
public SimpleStringProperty surnameProperty() {
return surname;
}
public void setSurname(String surname) {
this.surname.set(surname);
}
}
在Main我声明控制器和可编辑列:
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = (Parent) loader.load();
primaryStage.setScene(new Scene(root, 300, 275));
Controller controller = loader.getController();
TableColumn<Person, String> colName = controller.getColName();
Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory =
(TableColumn<Person, String> p) -> new sample.EditCell();
colName.setCellFactory(cellFactory);
colName.setOnEditCommit(
(TableColumn.CellEditEvent<Person, String> t) -> {
((Person) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setName(t.getNewValue());
});
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我需要用ObservableList 绑定单元格吗?还是刷新一下?如何更新data 使 TextField 始终填充实际值?
这里是整个EditCell 类:
class EditCell extends TableCell<Person, String> {
private TextField textField;
public EditCell() {
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
//setText((String) textField.getText());
//This line updates cell, but textField keeps old value after next edit.
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(
(ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) -> {
if (!arg2) {
commitEdit(textField.getText());
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
【问题讨论】:
-
看看TableView doesn't commit values on focus lost event 是否有帮助。您可能还想考虑使用(或扩展)
TextFieldTableCell,而不是自己动手(或从头开始)。 -
您提到使用 TextFIeldTableCell,但是在我使用这行代码替换
CellFactory之后:colName.setCellFactory(TextFieldTableCell.<Person>forTableColumn());编辑不会发生。这一步也在我链接的 Oracle 教程中。此外,还有“掌握 FXML”部分,不幸的是,技术作者不想描述仅使用 FXML 进行编辑。