处理Cell中的空值

时间:2012-09-26 12:50:57

标签: javafx-2

我在使用JavaFX 2 TableView处理数据中的空值时遇到了严重问题。事实上,我已经把这个问题的简单演示放在一起,如下所示。

本质上问题是我的一些数据可能为null并且将null强制转换为值(例如空字符串)无效,它必须为null。在我正在处理的实际代码中,我有一个空日期值,为了保持示例简单,我在下面显示了一个空字符串。

表的第1行和第2行具有空值。这两列是不同的,第一列显示了TextFieldTableCell的行为,第二个是我可编辑单元格的实现。两者都表现出相同的错误行为。

目前的行为是:

  1. 单击单元格以进入编辑模式
  2. 在单元格中输入值
  3. 按Enter键提交修改
  4. 什么都没发生
  5. 在第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;
        }
    }
    

1 个答案:

答案 0 :(得分:2)

自发布以来,我发现another question基本相同。他们采用的方法总是避免使用对字符串很好的空值(例如使用空字符串),但对于没有明显“空”值的日期或其他数据类型则不可接受。

解决方案是将值false传递给EditingCell.updateItem方法中的super.updateItem调用。如果有人对整个分析感兴趣,我已经整理了full write up这个。

相关问题