JavaFX OneToMany(1:n)在TableView中

时间:2018-02-22 12:16:32

标签: java javafx


我是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?
我试过这个例子official docs 但是,如何使用汽车类的属性填充汽车的子列?它只适用于1个属性。我是否必须将汽车的属性声明为每个子列?

1 个答案:

答案 0 :(得分:2)

最简单的方法是为&#34; Brand&#34;制作数据值。列和&#34;模型&#34;列列出汽车列表;然后使用单元工厂将单元格的文本设置为每个汽车的相应值,并用换行符分隔。

这有一些缺点:没有绝对保证列表单元格中具有多行文本的所有行的高度将相等,因此您无法完全保证这些行将完全对齐。我认为它适用于这个用例。如果您想要更多控制权,可以创建一个VBox作为单元格的图形,并使用单个标签填充它,每辆车一次。这样你就可以根据需要控制标签的高度;可能你可以设置标签的样式以产生边框的效果,所以它看起来真的像'#34; subcells&#34;。

此外,如果在显示表格时更改了数据,这些单元格将不会更新,但这更多是因为您对汽车使用普通List<Car>。这可以通过使用适当的ObservableList来修复,如果需要,也可以使用提取器。

最后,这只是使用一个单元格来呈现汽车品牌和汽车模型的每个列表,因此您无法选择单个品牌或型号。

简单的解决方案如下:

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);
    }
}

呈现为

enter image description here