JavaFX заполняет табличное представление отношением OneToMany

заполнить таблицу легко, если вы заполняете ее данными из одного класса, но что делать, если я хочу заполнить ее данными из отношения OneToMany?

Например:

Классовое лицо: идентификатор, имя, фамилия, автомобили (автомобили имеют однозначную связь с классовыми автомобилями, поэтому у одного человека может быть один или несколько автомобилей)

Теперь, если у человека есть две машины, как я могу добавить это в таблицу?

Это должно выглядеть примерно так:

ID  |  firstname  |  lastname  |  vehicleBrand(from cars)
==============================================
1   |  jack       | jackson    |  crysler
----------------------------------------------
    |             |            |  bmw
----------------------------------------------
2   |  sally      | jackson    |  ford

Если у меня есть наблюдаемый список от Person, я могу заполнить данные о человеке следующим образом:

firstNameCol.setCellValueFactory(
    new PropertyValueFactory<Person,String>("firstName")
);

но что-то вроде:

vehicleBrandCol.setCellValueFactory(
new PropertyValueFactory<Cars,String>("vehicleBrand")
);

or

vehicleBrandCol.setCellValueFactory(
new PropertyValueFactory<Person,String>("vehicleBrand")
);

не работает.

Изменить: приведенный ниже ответ работает для одного бренда. Если я попытаюсь добавить все, что пробовал, используя такой цикл:

for (Car aCars : cars) {
                return new SimpleObjectProperty<>(aCars.vehicleBrand());
            }

Но петля не зацикливается?! (Я напечатал размер машин и это не 1)


person Dusius    schedule 29.05.2016    source источник
comment
Он не зацикливается, потому что вы выходите из метода при первом нажатии оператора return.   -  person Khaled SAB    schedule 29.05.2016
comment
Хорошо, это имеет смысл ^^ Должен ли я составить список свойств SimpleObjectProperty и вернуть это?   -  person Dusius    schedule 29.05.2016
comment
Нет, в этом случае это не сработает, потому что ваш столбец должен содержать String значений, а не List значений.   -  person Khaled SAB    schedule 29.05.2016
comment
Хорошо, я немного работаю над этим, спасибо   -  person Dusius    schedule 29.05.2016


Ответы (1)


Это должно быть частью того, что вы ищете, вы можете сделать это:

  • Теперь я предполагаю, что у вас есть два класса Person и Car.
  • В классе Person есть ArrayList<Car> автомобилей.
  • В классе Person также есть метод getCars(), который возвращает коллекцию автомобилей этого человека (ArrayList).

Теперь, чтобы бренд из вашего Car класса отображался в TableView людей, вы можете установить CellValueFactory следующим образом:

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

Метод param.getValue() возвращает person, переданный в качестве параметра.

Обратите внимание, что в этом примере я возвращаю (отображаю) только первую марку автомобиля из коллекции автомобилей текущего человека, вы можете попробовать адаптировать этот пример к своему случаю.

Хорошо, это имеет смысл ^^ Должен ли я составить список свойств SimpleObjectProperty и вернуть это?

Нет, вы не можете этого сделать, потому что вы объявляете столбец, который должен содержать String объектов, а не List объектов.

Что вы можете сделать, так это создать пользовательские ячейки, которые позволят вам отображать все Car брендов каждого Person экземпляра, вы можете взглянуть на этот пример, чтобы получить представление о рендеринге ячеек, и вот мой пример, который может помочь вам в вашем случае:

Сначала установите тип содержимого ячеек в vehicleBrandCol на ArrayList<String>:

private TableColumn<Person, ArrayList<Car>> vehicleBrandCol;

Затем установите CellValueFactory следующим образом:

vehicleBrandCol.setCellValueFactory(new PropertyValueFactory<Person, ArrayList<Car>>("cars"));

а затем вам понадобятся пользовательские ячейки для отображения данных (автомобилей), содержащихся в этом ArrayList, поэтому установите CellFactory следующим образом:

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

Обратите внимание, что я создаю VBox и использую метки, вы можете использовать любые Node, которые вам нравятся, например, вы можете использовать ListView или GridPane и установить их как графику для Cell.

person Khaled SAB    schedule 29.05.2016
comment
Спасибо, это работает! но если я попытаюсь перебрать список, чтобы получить все бренды, цикл не зациклится. Я отредактировал код, который пытался ответить на свой вопрос. - person Dusius; 29.05.2016