0

JavaFX2TableViewでデータのnull値を処理するのに深刻な問題があります。実際、非常に多くの問題があります。以下に示す問題の簡単なデモをまとめました。

基本的に問題は、一部のデータがnullである可能性があり、nullを値(空の文字列など)に強制変換することは無効であり、nullである必要があることです。私が取り組んでいる実際のコードでは、nullの日付値があります。例を単純にするために、以下にnull文字列を示しました。

表の行1と2の値はNULLです。2つの列は異なります。最初の列は、TextFieldTableCellの動作を示し、2番目の列は編集可能なセルの実装を示しています。どちらも同じ誤った動作を示しています。

現在の動作は次のとおりです。

  1. セルをクリックして編集モードに入ります
  2. セルに値を入力します
  3. Enterキーを押して、編集をコミットします
  4. 何も起こりません

ステップ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;
    }
}
4

1 に答える 1

2

投稿してから、基本的に同じである別の質問を見つけました。彼らは、文字列には問題ない(たとえば、空の文字列を使用する)null値を常に回避するというアプローチを取りましたが、明らかな「空の」値がない日付やその他のデータ型には受け入れられません。

解決策は、falseの値をEditingCell.updateItemメソッドのsuper.updateItem呼び出しに渡すことです。誰かが完全な分析に興味があるなら、私はこれの完全な記述をまとめました。

于 2012-09-28T09:20:32.580 に答える