如何将 TableView 列设为 LocalDate 并仅通过 FXML 设置它的值?

How to make a TableView Column as LocalDate and set it's value only via FXML?

如何仅将 LocalDate 值填充到 fxml 中的列?

在我的控制器中的某处class:

protected void addPerson(ActionEvent event) {       
    ObservableList<Person> data = tableView.getItems();
    data.add(new Person(firstNameField.getText(),lastNameField.getText(),emailField.getText(),checkBox.isSelected(),Integer.parseInt(numberField.getText()),LocalDate.now()));     
    firstNameField.setText("");
    lastNameField.setText("");
    emailField.setText("");
    checkBox.setSelected(false);
    numberField.setText("0");
    dateField.setText(""+LocalDate.now());

}

人 class:

public class Person {

private final SimpleStringProperty firstName = new SimpleStringProperty("");
private final SimpleStringProperty lastName = new SimpleStringProperty("");
private final SimpleStringProperty email = new SimpleStringProperty("");
private final SimpleBooleanProperty checked = new SimpleBooleanProperty(false);
private final SimpleIntegerProperty alter = new SimpleIntegerProperty();
private final ObjectProperty<LocalDate> date;

...

FXML:...

    <TableColumn prefWidth="75.0" text="Date">
        <cellValueFactory>
            <PropertyValueFactory property="date" />
        </cellValueFactory>
    </TableColumn>
    <TableColumn prefWidth="75.0" text="G" />
</columns>
<items>

    <FXCollections fx:factory="observableArrayList">
         <Person alter="1" checked="false"  
                 email="tester1.test@test.com"  firstName="Tester1"   
                 lastName="Test"/>                                                                      

    </FXCollections>
</items>

我试过了:

<Person alter="1" checked="false" email="tester1.test@test.com" firstName="Tester1" lastName="Test" date="2016.01.01"/> 

但是我得到一个 javafx.fxml.LoadException:

Caused by: java.lang.IllegalArgumentException: Unable to coerce 2016.01.01 to class java.time.LocalDate.
    at com.sun.javafx.fxml.BeanAdapter.coerce(BeanAdapter.java:496)
    at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:258)
    at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:54)
    at javafx.fxml.FXMLLoader$Element.applyProperty(FXMLLoader.java:512)
    at javafx.fxml.FXMLLoader$Element.processValue(FXMLLoader.java:363)
    at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:325)
    at javafx.fxml.FXMLLoader$Element.processInstancePropertyAttributes(FXMLLoader.java:235)
    at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:767)
    at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2823)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2532)
    ... 13 more

FXMLLoader 无法从 String 初始化 LocalDate 这让您有 2 个选择:

使用 valueOf + fx:value

在某些 class

中实现方法 public static LocalDate valueOf(String)
public final class Util {

    private Util() {
    }

    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy.MM.dd");

    public static LocalDate valueOf(String val) {
        return LocalDate.parse(val, DATE_FORMAT);
    }

    public static String toString(LocalDate date) {
        return date == null ? null : date.format(DATE_FORMAT);
    }

}

并像这样更改您的 fxml 文件:

<Person alter="1" checked="false" email="tester1.test@test.com" firstName="Tester1" lastName="Test">
    <date>
        <Util fx:value="2016.01.01"/>
    </date>
</Person>

使用 BuilderFactory

保持 fxml 不变并使用自定义 BuilderFactory that uses a Builder 创建 Person。对于 Person 中的每个 属性,此构建器都有 getters/setters 委托给产品的适当方法,但那些需要特殊处理的属性除外。对于这些属性,它还进行了转换 to/from String.

public class PersonBuilder implements Builder<Person> {

    private final Person product = new Person();

    @Override
    public Person build() {
        return product;
    }

    public void setAlter(int value) {
        product.setAlter(value);
    }

    public void setDate(String value) {
        product.setDate(Util.valueOf(value));
    }

    public void setEmail(String value) {
        product.setEmail(value);
    }

    ...

    public int getAlter() {
        return product.getAlter();
    }

    public String getDate() {
        return Util.toString(product.getDate());
    }

    public String getEmail() {
        return product.getEmail();
    }

    ...

}
FXMLLoader loader = new FXMLLoader(getClass().getResource("person.fxml"));
loader.setBuilderFactory(new BuilderFactory() {

    private final BuilderFactory fallback = new JavaFXBuilderFactory();

    @Override
    public Builder<?> getBuilder(Class<?> type) {
        return type == Person.class ? new PersonBuilder() : fallback.getBuilder(type);
    }

});

loader.load();