【问题标题】:JavaFX TableView access aggregated ObjectsJavaFX TableView 访问聚合对象
【发布时间】:2021-08-05 08:38:30
【问题描述】:
public class C{
B b;
A a;
int d;
String str;
}

A 类和 B 类有自己的变量。 我有这样的代码,我想在 TableView 中使用 C 类,如何访问 A 类和 B 类的值?还有我要写什么column..setCellValueFactory(new PropertyValueFactory<>("???"));TableColumn<???, String> column = new TableColumn<>("Example");

【问题讨论】:

  • 根本不要使用 PropertyValueFactory ;) 而是设置一个自定义工厂来查找嵌套值
  • 怎么样?如果有帮助的话,我在另外两个课程中有吸气剂。
  • 完成一个关于如何使用 TableView 的教程,做一些研究(网站上有大量的例子,而且在野外)。当遇到具体问题时,请返回minimal reproducible example,以证明没有按预期工作。
  • 实现您自己的 Callback(通常作为 lambda 或方法引用)返回您需要的内容。

标签: java javafx tableview tablecolumn


【解决方案1】:

PropertyValueFactory 是一个没有人应该使用的类。它依赖于反射,这意味着如果你犯了错误,编译器无法通知你你的错误。它还有一个不愉快的习惯,就是默默地吞下任何异常,这使得错误更难被发现。

A cell value factory is a Callback,在功能上与 Java SE Function 完全相同。任何接受TableColumn.CellDataFeatures 作为参数并返回对应于该单元格中table item 的ObservableValue 的方法或lambda,都可以充当单元格值工厂。

所以,最好的办法是忘记 PropertyValueFactory,而是传递一个简单的 lambda。

做到这一点的最佳方法是确保每个数据对象的属性都采用 JavaFX 属性的样式。如果您曾经看过 documentation for NodeWindow 或 JavaFX 中的大多数其他类,您可能已经注意到,虽然普通 JavaBean 的每个属性都有两个方法(get-method 和 set-method ),一个JavaFX对象通常有三个方法:

  • get 方法
  • 一套方法
  • 一种属性访问器方法,它返回Property 本身,而不是属性值

一些例子:

你会想要在你的数据对象中做同样的事情。

为了清楚起见,我将使用 Person 和 Address 而不是 A、B 和 C:

public class Address {
    private final StringProperty street = new SimpleStringProperty();
    private final StringProperty postalCode = new SimpleStringProperty();

    public StringProperty streetProperty() {
        return street;
    }

    public String getStreet() {
        return street.get();
    }

    public void setStreet(String newStreet) {
        this.street.set(newStreet);
    }

    public StringProperty postalCodeProperty() {
        return postalCode;
    }

    public String getPostalCode() {
        return postalCode.get();
    }

    public void setPostalCode(String code) {
        this.postalCode.set(code);
    }
}

public class Person {
    private final StringProperty name = new SimpleStringProperty();
    private final ObjectProperty<LocalDate> dateOfBirth = new SimpleObjectProperty<>();
    private final ObjectProperty<Address> address = new SimpleObjectProperty<>();

    public StringProperty nameProperty() { 
        return name;
    }

    public String getName() {
        return name.get();
    }

    public void setName(String newName) {
        this.name.set(newName);
    }

    public ObjectProperty<LocalDate> dateOfBirthProperty() {
        return dateOfBirth;
    }

    public LocalDate getDateOfBirth() {
        return dateOfBirth.get();
    }

    public void setDateOfBirth(LocalDate date) {
        this.dateOfBirth.set(date);
    }

    public ObjectProperty<Address> addressProperty() {
        return address;
    }

    public Address getAddress() {
        return address.get();
    }

    public void setAddress(Address newAddress) {
        this.address.set(newAddress);
    }
}

每个属性都实现了 ObservableValue,所以现在你的单元格数据值可以是属性对象本身:

TableColumn<Person, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(cell -> cell.getValue().nameProperty());

由于上面的代码没有使用反射,编译器可以保证你显示的是一个合法的值。

为了解决你原来的问题,如果你想显示一个子对象的值,你可以使用Bindings的select*方法之一:

TableColumn<Person, String> streetColumn = new TableColumn<>();
streetColumn.setCellValueFactory(
    cell -> Bindings.selectString(cell.getValue().addressProperty(), "street"));

这确实有使用反射的缺点(虽然there is an open bug about that),但至少父对象被编译器检查了。

【讨论】:

    猜你喜欢
    • 2015-08-12
    • 2021-10-04
    • 2014-01-17
    • 2012-10-11
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 2014-06-27
    • 1970-01-01
    相关资源
    最近更新 更多