处理单元格中的空值 [英] Dealing with null values in Cell

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

问题描述

让JavaFX 2 TableView处理数据中的空值时遇到严重问题.其实有这么多麻烦,我整理了一个简单的问题演示,如下所示.

I'm having serious problems getting a JavaFX 2 TableView to deal with null values in my data. So much trouble in fact I've put together a simple demo of the problem which is shown below.

基本上,问题是我的某些数据可能为空,并且将空值强制为一个值(例如空字符串)无效,它必须为空.在我正在处理的真实代码中,我有一个空日期值,为使示例简单起见,我在下面显示了一个空字符串.

Essentially the problem is that some of my data may be null and coercing the null to a value, such as an empty string, is not valid, it must be null. In the real code I'm working on I have a null date value, to keep the example simple I've shown a null string below.

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

Rows 1 and 2 of the table have null values. The two columns are different, the first shows the behaviour of the TextFieldTableCell the second my implementation of an editable cell. Both show the same incorrect behaviour.

当前行为是这样:

  1. 单击单元格进入编辑模式
  2. 在单元格中输入一个值
  3. 按Enter提交修改
  4. 什么都没发生

在第4步中,我希望该列的onEditCommit处理程序被调用,但事实并非如此.看看javax.scene.control.TableCell的源代码,由于commitEdit的第一行是:

At step 4 I would expect the onEditCommit handler for the column to get called but it isn't. Having a look at the source for javax.scene.control.TableCell the commit isn't happening because of the first line of commitEdit is:

if (! isEditing()) return;

似乎因为单元格为空,所以编辑属性从未设置为true,尽管我承认我尚未遍历所有代码以查看为什么永远都不会切换为true.

It seems that because the cell is null the editing property never gets set to true although I admit I've not yet traced through all the code to see why it never get's switched to true.

一如既往地感谢您的帮助.

Thanks as always for any help.

示例

主要应用

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

推荐答案

自发布以来,我发现

Since posting I found another question that is basically identical. They took the approach of always just avoiding null values which is fine for strings (e.g. use an empty string) but not acceptable for dates or other data types where the is no obvious "empty" value.

解决方案是将false值传递给EditingCell.updateItem方法中的super.updateItem调用.我整理了一个

The solution is to pass a value of false into the super.updateItem call in the EditingCell.updateItem method. I've put together a full write up of this if anyone is interested in the complete analysis.

这篇关于处理单元格中的空值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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