如何在嵌套对象的 TableView 中显示数据?

问题描述

我在控制器类中有一个 TableView<Marriage>

public class MarriageTableView extends AbstractTableViewController {

    @FXML
    private TableView<Marriage> tableView;

    @FXML
    private TableColumn<Groom,String> groomFirstNameColumn,groomLastNameColumn;

    @FXML
    private TableColumn<Bride,String> brideFirstNameColumn,brideLastNameColumn;

    @FXML
    private TableColumn<Marriage,LocalDate> marriageDateColumn;
    
    @FXML
    void initialize() {
        this.groomFirstNameColumn.setCellValueFactory(new PropertyValueFactory<Groom,String>("firstName")); // <- Exception here
        this.groomLastNameColumn.setCellValueFactory(new PropertyValueFactory<Groom,String>("lastName"));
        this.brideFirstNameColumn.setCellValueFactory(new PropertyValueFactory<Bride,String>("firstName"));
        this.brideLastNameColumn.setCellValueFactory(new PropertyValueFactory<Bride,String>("lastName"));
        this.marriageDateColumn.setCellValueFactory(new PropertyValueFactory<Marriage,LocalDate>("marriageDate"));
    }

initialize 方法中,我尝试为每个表列设置 CellValueFactory,以便我可以在我的 tableview 中显示 Marriage 对象。

然而,Marriage 对象包含另一个新郎和新娘类型的对象,我试图从中显示一些值。

public class Marriage {
    private Groom groom;
    private Bride bride;
    private LocalDate marriageDate;
}

public class Groom:
{
    private String firstName;
    private String lastName;
}

public class Bride:
{
    private String firstName;
    private String lastName;
}

异常:

java.lang.IllegalStateException: Cannot read from unreadable property firstName

如何设置 CellValueFactory 或编辑 TableColumn 的通用参数,以便显示嵌套对象的属性

解决方法

一种选择是使用自定义单元格实现,该实现知道如何显示 GroomBride 的所需数据。例如:

TableColumn<Marriage,Groom> groomCol = ...;
groomCol.setCellValueFactory(new PropertyValueFactory<>("groom"));
groomCol.setCellFactory(tc -> new TableCell<>() {

  @Override
  protected void updateItem(Groom item,boolean empty) {
    super.updateItem(item,empty); // must be called
    if (empty || item == null) {
      setText(null);
    } else {
      // replace with desired format
      setText(item.getFirstName() + " " + item.getLastName());
    }
  }
});

请注意,TableColumn 的第一个类型参数必须与 TableView(在本例中为 Marriage)的类型参数匹配。


顺便说一句,您真的需要 GroomBride 类吗?它们似乎具有相同的信息,并且可能合并为一个 Person 类。


另一方面,如果可以,您应该避免使用 PropertyValueFactory。它是在 lambda 表达式出现之前的时代设计的,目的是使代码更简洁。但是使用 lambda 表达式,您可以执行相同的操作,但具有编译时安全性(并且可以避免反射)。但请注意,如果您将模型的属性公开为 JavaFX 属性,则此方法效果最佳。例如:

// model class
public class Marriage {
  private final ObjectProperty<Groom> groom = new SimpleObjectProperty<>(this,"groom");
  public final void setGroom(Groom groom) { this.groom.set(groom); }
  public final Groom getGroom() { return groom.get(); }
  public final ObjectProperty<Groom> groomProperty() { return groom; }

  // other properties...
}
// table column configuration
TableColumn<Marriage,Groom> groomCol = ...;
groomCol.setCellValueFactory(data -> data.getValue().groomProperty());
groomCol.setCellFactory( ... );