我在TableView上有一个事件侦听器,用于侦听键盘事件。
// Add event listener to table table.setOnKeyTyped(event -> { TablePosition<SimpleStringProperty, String> focusedCell = table.getFocusModel().getFocusedCell(); if (focusedCell != null) { table.getItems().get(focusedCell.getRow()).set(event.getCharacter()); table.edit(focusedCell.getRow(), focusedCell.getTableColumn()); } });
当用户单击Enter或将焦点更改到另一个单元格时,使用新数据更新单元格时出现问题。当您单击输入或更改焦点时,该单元格将变为空。我不知道为什么。如何保存数据并使用新数据更新单元格。
// Here is the full code. import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.control.ContentDisplay; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TablePosition; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class TableViewEdit extends Application { @Override public void start(Stage primaryStage) { TableView<SimpleStringProperty> table = new TableView<SimpleStringProperty>(); table.getSelectionModel().setCellSelectionEnabled(true); table.setEditable(true); table.getColumns().add(this.createColumn()); ObservableList<SimpleStringProperty> rowData = FXCollections.observableArrayList(); //table.getItems().addAll(rowData); for (int j = 0; j < 10; j++) { rowData.add(new SimpleStringProperty(String.format("Cell [%d", j))); } table.setItems(rowData); table.setOnKeyTyped(event -> { TablePosition<SimpleStringProperty, String> focusedCell = table.getFocusModel().getFocusedCell(); if (focusedCell != null) { table.getItems().get(focusedCell.getRow()).set(event.getCharacter()); table.edit(focusedCell.getRow(), focusedCell.getTableColumn()); } }); Scene scene = new Scene(new BorderPane(table), 880, 600); primaryStage.setScene(scene); primaryStage.show(); } private TableColumn<SimpleStringProperty, String> createColumn() { TableColumn<SimpleStringProperty, String> col = new TableColumn<>("Column "); col.setCellValueFactory(cellData -> cellData.getValue()); col.setCellFactory(column -> new EditCell()); return col; } private static class EditCell extends TableCell<SimpleStringProperty, String> { private final TextField textField = new TextField(); EditCell() { this.textProperty().bind(this.itemProperty()); this.setGraphic(this.textField); this.setContentDisplay(ContentDisplay.TEXT_ONLY); this.textField.setOnAction(evt -> this.commitEdit(this.textField.getText())); this.textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> { if (!isNowFocused) { this.commitEdit(this.textField.getText()); } }); } @Override public void startEdit() { super.startEdit(); this.textField.setText(this.getItem()); this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); this.textField.requestFocus(); } @Override public void cancelEdit() { super.cancelEdit(); this.setContentDisplay(ContentDisplay.TEXT_ONLY); } @Override public void commitEdit(String text) { super.commitEdit(text); this.setContentDisplay(ContentDisplay.TEXT_ONLY); } } public static void main(String[] args) { launch(args); } }
这些变得非常棘手。我认为任何与“行为相关”的东西(即对用户输入做出反应的标准控件)都很难更改,并且JavaFX通常不提供很好的支持。希望这是API的一个可以改进的地方…
似乎有几个不同的问题。我认为Enter键发生的事情是,尽管这会ActionEvent在文本字段上生成一个,并提交编辑等,但该keyTyped事件仍会传播回表,从而使其重新进入编辑模式。解决此问题的方法似乎是keyPressed在表上使用处理程序(尽管老实说这并不十分健壮)。
ActionEvent
keyTyped
keyPressed
该代码依赖于onEditCommit表列上的默认处理程序来实际更改属性值。该onEditCommit处理程序由默认表单元格的commitEdit方法调用。调用commitEdit(...)时失去焦点的问题在于,默认commitEdit方法首先检查单元格是否处于编辑状态,否则将不执行任何操作。似乎当单元格失去焦点时,在focusProperty调用侦听器之前将其移出编辑状态,因此onEditCommit永远不会调用该处理程序。(顺便说一句,这也使示例13-11“单元格编辑的替代解决方案”(原文如此)无法在JDK 8 u25(当前版本)中正常工作。)
onEditCommit
commitEdit
commitEdit(...)
focusProperty
对于第二个问题,我看到的唯一解决commitEdit(...)方法是直接从方法中更新属性。这要求单元格具有对该属性的引用,这破坏了单元格与单元格值之间的良好分隔。
我使用通常的Person示例重写了该示例,并合并了这两个修复程序。尽管我说过某些部分似乎并不十分健壮,但该示例仍然运行良好:
Person
import java.util.function.Function; import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.scene.Scene; import javafx.scene.control.ContentDisplay; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TablePosition; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class TableViewEditOnType extends Application { @Override public void start(Stage primaryStage) { TableView<Person> table = new TableView<>(); table.getSelectionModel().setCellSelectionEnabled(true); table.setEditable(true); table.getColumns().add(createColumn("First Name", Person::firstNameProperty)); table.getColumns().add(createColumn("Last Name", Person::lastNameProperty)); table.getColumns().add(createColumn("Email", Person::emailProperty)); table.getItems().addAll( new Person("Jacob", "Smith", "jacob.smith@example.com"), new Person("Isabella", "Johnson", "isabella.johnson@example.com"), new Person("Ethan", "Williams", "ethan.williams@example.com"), new Person("Emma", "Jones", "emma.jones@example.com"), new Person("Michael", "Brown", "michael.brown@example.com") ); table.setOnKeyPressed(event -> { TablePosition<Person, ?> pos = table.getFocusModel().getFocusedCell() ; if (pos != null) { table.edit(pos.getRow(), pos.getTableColumn()); } }); Scene scene = new Scene(new BorderPane(table), 880, 600); primaryStage.setScene(scene); primaryStage.show(); } private TableColumn<Person, String> createColumn(String title, Function<Person, StringProperty> property) { TableColumn<Person, String> col = new TableColumn<>(title); col.setCellValueFactory(cellData -> property.apply(cellData.getValue())); col.setCellFactory(column -> new EditCell(property)); return col ; } private static class EditCell extends TableCell<Person, String> { private final TextField textField = new TextField(); private final Function<Person, StringProperty> property ; EditCell(Function<Person, StringProperty> property) { this.property = property ; textProperty().bind(itemProperty()); setGraphic(textField); setContentDisplay(ContentDisplay.TEXT_ONLY); textField.setOnAction(evt -> { commitEdit(textField.getText()); }); textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> { if (! isNowFocused) { commitEdit(textField.getText()); } }); } @Override public void startEdit() { super.startEdit(); textField.setText(getItem()); setContentDisplay(ContentDisplay.GRAPHIC_ONLY); textField.requestFocus(); } @Override public void cancelEdit() { super.cancelEdit(); setContentDisplay(ContentDisplay.TEXT_ONLY); } @Override public void commitEdit(String text) { super.commitEdit(text); Person person = getTableView().getItems().get(getIndex()) ; StringProperty cellProperty = property.apply(person); cellProperty.set(text); setContentDisplay(ContentDisplay.TEXT_ONLY); } } public static class Person { private final StringProperty firstName = new SimpleStringProperty(); private final StringProperty lastName = new SimpleStringProperty(); private final StringProperty email = new SimpleStringProperty(); public Person(String firstName, String lastName, String email) { setFirstName(firstName); setLastName(lastName); setEmail(email); } public final StringProperty firstNameProperty() { return this.firstName; } public final java.lang.String getFirstName() { return this.firstNameProperty().get(); } public final void setFirstName(final java.lang.String firstName) { this.firstNameProperty().set(firstName); } public final StringProperty lastNameProperty() { return this.lastName; } public final java.lang.String getLastName() { return this.lastNameProperty().get(); } public final void setLastName(final java.lang.String lastName) { this.lastNameProperty().set(lastName); } public final StringProperty emailProperty() { return this.email; } public final java.lang.String getEmail() { return this.emailProperty().get(); } public final void setEmail(final java.lang.String email) { this.emailProperty().set(email); } } public static void main(String[] args) { launch(args); } }