问题
to populate a table is easy when you populate it with data from one class, but what is when I want to populate it with data from a OneToMany relationship?
for example:
Class Person: Id, firstname, lastname, cars(cars have a onetomany relationship with Class Cars, so one person can have one or more cars)
Now, if a person got two cars, how can I add this to a table?
It should look something like this:
ID | firstname | lastname | vehicleBrand(from cars)
==============================================
1 | jack | jackson | crysler
----------------------------------------------
| | | bmw
----------------------------------------------
2 | sally | jackson | ford
If I have the observable list from Person I can populate the person data like this:
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person,String>("firstName")
);
but something like:
vehicleBrandCol.setCellValueFactory(
new PropertyValueFactory<Cars,String>("vehicleBrand")
);
or
vehicleBrandCol.setCellValueFactory(
new PropertyValueFactory<Person,String>("vehicleBrand")
);
does not work.
Edit: The answer below works for one brand. If I try to add all I tried it by using a loop like this:
for (Car aCars : cars) {
return new SimpleObjectProperty<>(aCars.vehicleBrand());
}
But the loop does not loop?! (I printed the size of cars and it is not 1)
回答1:
This should be part of what you are looking for, you can do this:
- Now I'm supposing you have the two classes
Person
andCar
. - The class
Person
has anArrayList<Car>
of cars. - The class
Person
has also a methodgetCars()
which returns this person's collection (theArrayList
) of cars.
Now to get the brand from your Car
class displayed in the TableView
of persons you can set the CellValueFactory
as follows:
vehicleBrandCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person,String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(CellDataFeatures<Person, String> param) {
ArrayList<Car> cars = new ArrayList<Car>();
cars = param.getValue().getCars();
if(cars!=null && !cars.isEmpty()) {
return new SimpleStringProperty(cars.get(0).getBrand());
}
}
}
);
The param.getValue()
method returns the person
passed as a parameter.
Notice that in this example I'm returning(displaying) only the first car brand from the collection of cars of the current person, you can try to adapt this example to your case.
Ok, that makes sense ^^ should I make a List of the SimpleObjectProperty and return this?
No you can't do this because you are declaring a column that should contain String
objects not List
objects.
What you can do is create custom cells that would allow you display all of the Car
brands of a each Person
instance, you can take a look at this example to get a grasp of Cell rendering, and here is my example that could help you in your case:
First set the type of the content of cells in vehicleBrandCol
to ArrayList<String>
:
private TableColumn<Person, ArrayList<Car>> vehicleBrandCol;
Then set the CellValueFactory
as follows:
vehicleBrandCol.setCellValueFactory(new PropertyValueFactory<Person, ArrayList<Car>>("cars"));
and then you'll need custom cells to display data (Cars) contained within this ArrayList
, so set the CellFactory
as follows:
vehicleBrandCol.setCellFactory(column->{
return new TableCell<Person, ArrayList<Car>>() {
@Override
protected void updateItem(ArrayList<Car> item, boolean empty) {
super.updateItem(item, empty);
if(item==null || empty) {
setGraphic(null);
} else {
VBox vbox = new VBox();
for(Car car : item) {
Label lbl = new Label(car.getBrand());
vbox.getChildren().add(lbl);
}
setGraphic(vbox);
}
}
};
});
Notice that I'm creating a VBox
and using Labels, you can use whatever Node
you like, for example you can use a ListView
, or a GridPane
and set them as graphic for the Cell
.
来源:https://stackoverflow.com/questions/37509031/javafx-populate-tableview-with-a-onetomany-relationship