我是 JavaFX 新手,想要创建一个 TableView。
我选择了以下包含 ArrayList 的 Person 类示例。
OneToMany-relation(1:n) 应该像这样显示。
╔════╤════════════════════╤════════════════════╗
║ │ name │ car ║
║ id ├──────────┬─────────┼──────────┬─────────╢
║ │ forname │ surname │ brand │ model ║
╠════╪══════════╪═════════╪══════════╪═════════╣
║ 0 │ John │ Doe │ Audi │ A3 ║
║ │ │ │ VW │ Golf3 ║
╟────┼──────────┼─────────┼──────────┼─────────╢
║ 1 │ Jane │ Doe │ BMW │ i5 ║
╚════╧══════════╧═════════╧══════════╧═════════╝
人员类别:
class Person
{
private SimpleStringProperty forname;
private SimpleStringProperty surname;
private List<Car> cars;
public Person(String forname, String surname, List<Car> cars)
{
this.forname.set(forname);
this.surname.set(surname);
this.lehrveranstaltungen = lehrveranstaltungen;
}
public Person()
{
this("","",new ArrayList<Car>());
}
public String getForname()
{
return forname.get();
}
public String getSurname()
{
return surname.get();
}
public List<Car> getCars()
{
return cars;
}
}
汽车类别看起来与此类似
最简单的方法是什么?
我遇到的主要问题 是为每个汽车对象创建一个子行。我该如何为 carColumn 设计 CellFactory ?
我尝试了这个例子JavaFX populate tableview with a OneToMany relationship 但是如何用汽车类的属性填充汽车的子列呢?它仅适用于 1 个属性。我是否必须向每个子列声明汽车的属性?
最佳答案
最简单的方法是将“品牌”列和“型号”列的数据值设置为汽车列表;然后使用单元工厂将单元格的文本设置为每辆车的适当值,并用换行符分隔。
这有一些缺点:不能绝对保证具有多行文本的列表单元格中所有行的高度相等,因此不能完全保证这些行完全对齐。我认为对于这个用例来说它可以正常工作。如果您想要更多控制,您可以创建 VBox
您将其用作单元格的图形,并用单独的标签填充它,每辆车一次。这样您就可以根据需要控制标签的高度;您可能可以设置标签样式以提供边框效果,因此它看起来确实像“子单元格”。
此外,如果在显示表格时更改数据,这些单元格将不会更新,尽管这更多是由于您使用普通 List<Car>
造成的。对于汽车。这可以通过使用适当的 ObservableList
来修复s,如果需要的话也许可以使用提取器。
最后,这仅使用单个单元格来呈现汽车品牌和汽车型号的每个列表,因此您无法选择单个品牌或型号。
简单的解决方案如下所示:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TableViewWithList extends Application {
// Cell implementation used later to create cells with multiline text
// from a cell item that is a List
public static class MultilineCell<S, T, U extends List<T>> extends TableCell<S, U> {
// function mapping each element of the list to a string
private final Function<T, String> textMapper ;
public MultilineCell(Function<T,String> textMapper) {
this.textMapper = textMapper ;
}
@Override
protected void updateItem(U items, boolean empty) {
super.updateItem(items, empty);
if (empty) {
setText(null);
} else {
// map each element of the list to a string, and join them with
// a new line between each
setText(
items.stream()
.map(textMapper)
.collect(Collectors.joining("\n"))
);
}
}
}
// Utility method to create a table column with a given title and function mapping
// the row value to a property to be used as the data for cells in that column
private <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col ;
}
@Override
public void start(Stage primaryStage) {
TableColumn<Person, List<Car>> brandCol = column("Brand",
person -> new SimpleObjectProperty<>(person.getCars()));
TableColumn<Person, List<Car>> modelCol = column("Model",
person -> new SimpleObjectProperty<>(person.getCars()));
brandCol.setCellFactory(tc -> new MultilineCell<>(Car::getBrand));
modelCol.setCellFactory(tc -> new MultilineCell<>(Car::getModel));
TableView<Person> table = new TableView<>();
TableColumn<Person, Void> nameCol = new TableColumn<>("Name");
TableColumn<Person, Void> carCol = new TableColumn<>("Car");
table.getColumns().add(nameCol);
table.getColumns().add(carCol);
nameCol.getColumns().add(column("First Name", Person::firstNameProperty));
nameCol.getColumns().add(column("Last Name", Person::lastNameProperty));
carCol.getColumns().add(brandCol);
carCol.getColumns().add(modelCol);
Car a3 = new Car("Audi", "A3");
Car golf = new Car("VW", "Golf GTI");
Car i5 = new Car("BMW", "i5");
table.getItems().addAll(
new Person("John", "Doe", a3, golf),
new Person("Jane", "Doe", i5)
);
Scene scene = new Scene(table);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Car {
private final String brand ;
private final String model ;
public Car(String brand, String model) {
this.brand = brand;
this.model = model;
}
public String getBrand() {
return brand;
}
public String getModel() {
return model;
}
}
public static class Person {
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
private final List<Car> cars ;
public Person(String firstName, String lastName, Car...cars) {
setFirstName(firstName);
setLastName(lastName);
this.cars = new ArrayList<>(Arrays.asList(cars));
}
public List<Car> getCars() {
return cars ;
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final String lastName) {
this.lastNameProperty().set(lastName);
}
}
public static void main(String[] args) {
launch(args);
}
}
呈现为
关于JavaFX 一对多(1 :n) In TableView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48927203/