Сопоставить целое число со строкой пользовательского класса в выпадающем списке - PullRequest
0 голосов
/ 05 января 2019

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

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

У меня есть метод, который возвращает группу из наблюдаемого списка, когда я предоставляю ей идентификатор. Это означает, что мне нужен идентификатор в cellfactory, но я не нашел способ сделать это. Мне также нужно отобразить название группы, а не ссылку на класс. Есть ли способ сделать это, или я должен изменить свой подход?

Назначенный класс

public class Appointee {

private SimpleIntegerProperty id;
private SimpleStringProperty firstname;
private SimpleStringProperty lastname;
private SimpleIntegerProperty group;
private SimpleIntegerProperty assigned;

public Appointee(int id, String firstname, String lastname, int group, int assigned){
    this.id = new SimpleIntegerProperty(id);
    this.firstname = new SimpleStringProperty(firstname);
    this.lastname = new SimpleStringProperty(lastname);
    this.group = new SimpleIntegerProperty(group);
    this.assigned = new SimpleIntegerProperty(assigned);
}

Групповой класс

public class Group {
private IntegerProperty id;
private StringProperty name;
private IntegerProperty members;
private IntegerProperty assigned;

public Group(int id, String name, int members, int assigned) {
    this.id = new SimpleIntegerProperty(id);
    this.name = new SimpleStringProperty(name);
    this.members = new SimpleIntegerProperty(members);
    this.assigned = new SimpleIntegerProperty(assigned);
}

Представление таблицы назначений

public AppointeeTableView() {
    // define table view
    this.setPrefHeight(800);
    this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    this.setItems(MainController.appointeeObervableList);
    this.setEditable(true);

    // define columns
    ...
    TableColumn groupCol = new TableColumn("Group"); // group
    groupCol.setCellFactory(col -> {
        TableCell<Group, StringProperty> c = new TableCell<>();
        final ComboBox<String> comboBox = new ComboBox(MainController.groupObservableList);
        c.graphicProperty().bind(Bindings.when(c.emptyProperty()).then((Node) null).otherwise(comboBox));
        return c;
    });
    groupCol.setEditable(false);  
    ...
}

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Трудно сказать только по небольшим фрагментам кода, но моя общая рекомендация при работе с внешними интерфейсами - различать модель и рендеринг на каждом уровне. Это относится и к приложениям JavaFX, Swing и Angular.

Назначенный TableView, скорее всего, должен быть TableView<Appointee>.

Для свойства appointee.group у вас есть два варианта: либо использовать Group, либо (например, когда это приведет к созданию слишком большого количества дублирующихся данных при десериализации / сериализации из / в JSON), а затем использовать бизнес-ключ. Первый вариант обычно проще реализовать и работать с ним Во втором варианте вам понадобится какой-нибудь сервис / код для преобразования обратно в Group и вам нужно подумать о том, где / на каком уровне именно вы хотите выполнить преобразование.

Давайте продолжим здесь со вторым вариантом, поскольку вы в настоящее время указали appointee.group как целое число.

В этом случае столбец группы должен быть TableColum<Appointee, Integer>. Ячейка группы тогда должна быть TableCell<Appointee, Integer>.

До сих пор мы говорили только о модели, а не о рендеринге, за исключением того, что мы хотим отобразить назначенных лиц в таблице.

Я рекомендую сделать это также на следующем уровне.

Не используйте ComboBox<String> для группового комбинированного списка, но ComboBox<Group>. Строка - это способ отображения группы внутри comboBox, а группа - модель. Кроме того, ComboBox<Integer>, тип бизнес-ключа, немного вводит в заблуждение (так как вам нужен comboBox для групп, а не целочисленный comboBox) и ограничивает гибкость вашего кода.

Используйте сервис преобразования / код, который я упоминал при предварительном выборе значения в поле со списком.

Ячейка группы должна иметь тип ListCell<Group>, а в методе updateItem, который касается способа отображения группы, вы можете, например, используйте свойство name, чтобы получить представление String.

Конечно, есть варианты этого подхода, но убедитесь, что на каждом уровне вы знаете, что такое модель элемента управления и что такое средство визуализации элемента управления. Всегда проектируйте свой код, используя модель и используйте типы рендеринга только на самом низком уровне рендеринга.

0 голосов
/ 05 января 2019

Переопределите метод updateItem TableCell, чтобы обновить ячейку, убедитесь, что новое значение сохраняется при изменении значения TableCell, и используйте cellValueFactory.

final Map<Integer, Group> groupById = ...
final ObservableList<Integer> groupIds = ...
TableColumn<Group, Number> groupCol = new TableColumn<>("Group");
groupCol.setCellValueFactory(cd -> cd.getValue().groupProperty());

class GroupCell extends ListCell<Integer> {

    @Override
    protected void updateItem(Integer item, boolean empty) {
        super.updateItem(item, empty);

        Group group = groupById.get(item);

        if (empty || group == null) {
            setText("");
        } else {
            setText(group.getName());
        }
    }

}

groupCol.setCellFactory(col -> new TableCell<Group, Integer>() {

    private final ComboBox<Integer> comboBox = new ComboBox<>(groupIds);
    private final ChangeListener<Integer> listener = (o, oldValue, newValue) -> {
        Group group = (Group) getTableView().getItems().get(getIndex());
        group.setGroup(newValue);
    };

    {
        comboBox.setCellFactory(lv -> new GroupCell());
        comboBox.setButtonCell(new GroupCell());
    }

    @Override
    protected void updateItem(Number item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null) {
            setGraphic(null);
        } else {
            comboBox.valueProperty().removeListener(listener);
            setGraphic(comboBox);
            comboBox.setValue((Integer) item);
            comboBox.valueProperty().addListener(listener);
        }
    }

});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...