JavaFX 在控件中显示属性

JavaFX Displaying properties in controls

我正在学习 Oracle 的 JavaFX 教程。在使用 Swing 多年(很久以前)之后,我对新的智能功能非常着迷,包括。特性。我很惊讶地看到这些示例(例如:https://docs.oracle.com/javafx/2/ui_controls/table-view.htm)没有按照我认为的方式使用它们 "proper"。

该示例创建一个 Person class,其中属性作为字段:

public static class Person {
    private final SimpleStringProperty firstName;
    ...

但是 getter 不是针对属性,而是针对它们的值

    public String getFirstName() {
        return firstName.get();
    }

所以当它将它们绑定到列中的 TableCells 时,它会将它们包装在一个新的 属性 中:

    emailCol.setCellValueFactory(
            new PropertyValueFactory<Person, String>("firstName"));

这对我来说似乎很复杂,并且错过了事件传播的真正优势,而不是简单地使用它:

    firstNameCol.setCellValueFactory( celldata -> 
        celldata.getValue().firstNameProperty());

我的问题:为什么这个示例不公开并直接在控件中使用 bean 的属性是有原因的吗?我在这里遗漏了什么吗?

注意:我确实以这种方式更改了代码,并且该示例工作得更好:立即传播另一个控件在 Person 实体中的更新,w/o 调用 table.refresh()例如

首先请注意,如果您遵循 expected pattern:

public class Person {

    private final StringProperty firstName = new SimpleStringProperty();

    public StringProperty firstNameProperty() {
        return firstName ;
    }

    public final String getFirstName() {
        return firstNameProperty().get();
    }

    public final void setFirstName(String firstName) {
        firstNameProperty().set(firstName);
    }
}

那么您的代码的任何一个版本都可以在不调用 table.refresh() 的情况下运行。这是 PropertyValueFactory 的预期用途,从 documentation.

可以清楚地看出

不过你是对的,lambda 表达式是比 PropertyValueFactory 更好的方法。除了您引用的原因之外,使用 lambda 表达式比 PropertyValueFactory 还具有其他主要优势。首先,也是最重要的,PropertyValueFactory 只是将 属性 的名称作为 String,这意味着没有 compile-time 检查它。因此,如果您拼错 属性:

的名称
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstname"));

这会编译得很好,你只会在列中得到空白单元格。这可能很难调试(本网站上寻求此类错误帮助的问题数量证明了这一点:例如 Javafx PropertyValueFactory not populating Tableview)。

其次,PropertyValueFactory 通过反射工作,这比 lambda 表达式慢得多。这可能会导致可衡量的性能差异,例如在对具有大量数据的 table 进行排序时。

引入PropertyValueFactory的原因基本上是历史原因。在 Java 8 之前,当然没有 lambda 表达式,因此没有这种便利的细胞工厂的最小实现 class 是通过匿名内部 class:

firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>>() {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> cellData) {
        return cellData.getValue().firstNameProperty();
    }
});

由于该代码真的很丑陋,JavaFX 团队引入了 PropertyValueFactory 只是为了使 API 更易于使用。

当使用 Java 8 及更高版本时,PropertyValueFactory 确实应该被视为遗留 class,并且应该首选 lambda 表达式。当然,早于 Java 8 的文档也仍然存在(事实上,您明确地 link 来自 JavaFX 2 的文档——尽管 most recent version 仍未更新) , 并且 - 坦率地说 - 有太多其他作家在没有适当考虑的情况下复制这种风格。完全弃用 PropertyValueFactory class 可能是一个很好的理由。

(所以:TL;DR:不,你没有遗漏任何东西。)