【问题标题】:TableVew - Edit cell when KeyEvent is thrownTableVew - 抛出 KeyEvent 时编辑单元格
【发布时间】:2015-04-13 06:01:25
【问题描述】:

我在 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());
        }
    });

当用户单击输入或将焦点更改到另一个单元格时,我在使用新数据更新单元格时遇到问题。当您单击输入或更改焦点时,单元格变为空。我不确定为什么。如何保存数据并使用新数据更新单元格。

// 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);
}
}

【问题讨论】:

  • 你见过 this. 我还没有用最新的 javafx 测试过,但我永远无法让焦点监听器工作,除非单元格失去焦点到 TableView 之外的控件。
  • 我试过类似的东西,但没有看。我仍在试图弄清楚。我可以使用 KeyEvent 进入编辑模式。我在使用 Enter 保存时遇到问题。我有一种情况,我可以先输入保存,但之后我就不能再进入编辑模式了。非常奇怪的行为

标签: java javafx focus tableview


【解决方案1】:

这些变得非常棘手;我认为任何“与行为相关的”(即对用户输入做出反应的标准控件)都很难更改,并且通常在 JavaFX 中得不到很好的支持。希望这是 API 的一个可以改进的领域...

似乎有几个不同的问题。我认为 Enter 键发生的情况是,虽然这会在文本字段上生成一个 ActionEvent 提交编辑等,但 keyTyped 事件仍然传播回表,导致它重新输入编辑模式。解决这个问题的方法似乎是在桌子上使用keyPressed 处理程序(虽然老实说这感觉不是很健壮)。

代码依赖表列上的默认onEditCommit 处理程序来实际更改属性值。 onEditCommit 处理程序由默认表格单元格的commitEdit 方法调用。在失去焦点时调用commitEdit(...) 的问题是默认的commitEdit 方法首先检查单元格是否处于编辑状态,如果不是,则不执行任何操作。看来,当单元格失去焦点时,它会在调用focusProperty 侦听器之前退出编辑状态,因此永远不会调用onEditCommit 处理程序。 (顺便说一句,这也会阻止示例 13-11“单元格编辑的替代解决方案”(原文如此)在 JDK 8 u25(当前版本)中正常工作。)

对于第二个问题,我能看到的唯一解决方法是直接从 commitEdit(...) 方法更新属性。这要求单元格具有对属性的引用,这打破了单元格和单元格值之间的良好分离。

我使用通常的 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);
    }
}

【讨论】:

  • 我在 8u20、8u25 以及当前 ea 版本的 8u40 (b23) 和 9 (b49) 上进行了测试。
  • 函数很好用,我要开始关注java-8标签了。
  • 我实际上完全生成了EditCell,所以它是一个EditCell&lt;S,T&gt;,以StringConverter&lt;T&gt; 作为参数(连同property)。它实际上非常简洁,但我认为它混淆了手头的实际问题。
  • 更新(更好)版本here。有办法与单元共享属性并稍微改进用户体验。
  • 谢谢,喜欢你所拥有的所有要点。
猜你喜欢
  • 2015-04-14
  • 2013-05-05
  • 2016-08-07
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-25
  • 1970-01-01
相关资源
最近更新 更多