I have a TableView<Marriage>
in controller's class:
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"));
}
In initialize
method, I am trying to set CellValueFactory
for each table column, so I can show Marriage
object in my tableview.
However Marriage object consists of another objects of type Groom and Bride from which I am trying to show some values.
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;
}
Exception I get:
java.lang.IllegalStateException: Cannot read from unreadable property firstName
How to set CellValueFactory
or edit TableColumn
's generic parameters, so I can show properties of nested objects?
One option is to use a custom cell implementation that knows how to display the desired data of Groom
and Bride
. For example:
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());
}
}
});
Note that the first type argument of the TableColumn
must match the type argument of the TableView
(Marriage
in this case).
As an aside, do you really need both a Groom
and Bride
class? They seem to have the same information and could possibly be combined into a single Person
class.
As another aside, you should avoid PropertyValueFactory
if you can. It was designed in an era before lambda expressions as a way to make code more concise. But with lambda expressions you can do the same but with compile-time safety (and you avoid reflection). Though note this works best if you expose your model's properties as JavaFX properties. For example:
// 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( ... );