简体   繁体   中英

JavaFX TableView access aggregated Objects

public class C{
B b;
A a;
int d;
String str;
}

Classes A and B have their own variables. I have code like this, and I want to use class C in TableView, how do I access values from class A and B? And what do I have to write in column..setCellValueFactory(new PropertyValueFactory<>("???")); and TableColumn<???, String> column = new TableColumn<>("Example");

PropertyValueFactory is a class no one should use. It relies on reflection, which means if you make a mistake, the compiler can't inform you of your mistake. It also has the unpleasant habit of silently swallowing any exceptions, which makes a mistake even harder to detect.

A cell value factory is a Callback , which functionally is exactly the same as a Java SE Function . Any method or lambda which accepts a TableColumn.CellDataFeatures as an argument, and returns an ObservableValue corresponding to the table item in that cell, can act as a cell value factory.

So, the best thing to do is to forget about PropertyValueFactory, and pass a simple lambda instead.

The best way to do this is to make sure every one of your data objects' properties is in the style of JavaFX properties. If you've ever looked at the documentation for Node or Window or most of the other classes in JavaFX, you've probably noticed that while an ordinary JavaBean has two methods for each property (a get-method and a set-method), a JavaFX object usually has three methods:

  • a get-method
  • a set-method
  • a property accessor method, which returns the Property itself, not the property value

Some examples:

You will want to do the same thing in your data objects.

For clarity, I will use Person and Address instead of A, B, and 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);
    }
}

Every Property implements ObservableValue, so now your cell data values can be the property objects themselves:

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

Since the above code is not using reflection, the compiler can guarantee you're displaying a legitimate value.

To address your original question, if you want to display a value of a child object, you can use one of the select* methods of Bindings :

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

This does have the disadvantage of using reflection (though there is an open bug about that ), but at least the parent object is checked by the compiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM