TableVew - 抛出KeyEvent时编辑单元格 [英] TableVew - Edit cell when KeyEvent is thrown

查看:249
本文介绍了TableVew - 抛出KeyEvent时编辑单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  //将事件监听器添加到表
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());
}
});

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

  //下面是完整的代码。 
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
导入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
{
$ b @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;
}

私有静态类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());
}
});

$ b @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);



$ b public static void main(String [] args)
{
launch(args);



$ div $解析方案

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



似乎有几个不同的问题。我认为用Enter键发生的事情是,尽管这会在文本字段上产生一个 ActionEvent ,它提交了编辑等, keyTyped 事件仍然传播回表,导致它重新进入编辑模式。这个问题的解决方法似乎是在表上使用一个 keyPressed 处理程序(尽管老实说,这并不是非常强大的)。



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

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

我使用通常的 Person 例子重写了这个例子,并且包含了这两个修正。这个例子工作得很好,但是正如我所说的那样,一些零件觉得它们不是非常健壮的:

  import java.util。 function.Function; 

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
导入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 {

$ b @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));
$ b $ table.getItems()。addAll(
new Person(Jacob,Smith,jacob.smith@example.com),
new Person( (伊森,威廉姆斯,ethan.williams@example.com),
新人(Emma,Jones,emma.jones@example.com),
新人(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函数< Person,StringProperty>财产

EditCell(函数< Person,StringProperty>属性){
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);



$ b public static class Person {
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
private final StringProperty email = new SimpleStringProperty();
$ b $ 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);




$ b public static void main(String [] args){
launch(args);
}
}


I have an event listener on a TableView that listens for keyboard event.

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

I am having problems with updating the cell with the new data when a user clicks enter or changes focus to another cell. When you click enter or change focus, the cell becomes empty. I'm not sure why. How can I save the data and update the cell with the new data.

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

解决方案

These get really tricky; I think anything "behavior-related" (i.e. standard controls reacting to user input) is hard to change and generally not well supported in JavaFX. Hopefully this is an area of the API that will be improved...

There seem to be a couple of different issues. I think that what is happening with the Enter key, is that although this generates an ActionEvent on the text field, which commits the edit, etc, the keyTyped event still propagates back to the table, causing it to re-enter editing mode. A fix for this seems to be to use a keyPressed handler on the table instead (though to be honest this doesn't feel very robust).

The code relies on the default onEditCommit handler on the table column to actually change the property value. The onEditCommit handler is invoked by the default table cell's commitEdit method. The problem with calling commitEdit(...) on losing focus is that the default commitEdit method first checks if the cell is in an editing state, and does nothing if it's not. It appears that when the cell loses focus, it is taken out of the editing state before the focusProperty listener is invoked, so the onEditCommit handler is never called. (As an aside, this also prevents example 13-11 "Alternative solution of cell editing" (sic) from working correctly in the JDK 8 u25 (the current version).)

The only fix I can see for this second issue is to directly update the property from the commitEdit(...) method. This requires the cell have a reference to the property, which breaks the nice separation between the cell and the cell value.

I rewrote the example using the usual Person example and incorporated these two fixes. This example works quite well, though as I said some parts feel as though they are not very robust:

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

这篇关于TableVew - 抛出KeyEvent时编辑单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆