Я пытаюсь автоматически обновить JavaFX ListView, когда происходит изменение в свойстве, расположенном в ObservableMap.
Ниже представлена моя модель, где у меня есть проект, содержащий список мест и каждое место в свою очередь содержит карту типа <Layer, ObjectProperty<Category>>
.
. Я пытаюсь добиться привязки элемента пользовательского интерфейса к этому ObjectProperty<Category>
на карте.
Вот модель:
public class Seat {
private final DoubleProperty positionX;
private final DoubleProperty positionY;
private final MapProperty<Layer, ObjectProperty<Category>> categoryMap;
public Seat() {
this.positionX = new SimpleDoubleProperty();
this.positionY = new SimpleDoubleProperty();
this.categoryMap = new SimpleMapProperty(FXCollections.observableHashMap());
}
}
public class Project {
private ObservableList<Seat> seatList;
public Project() {
seatList = FXCollections.observableArrayList(
new Callback<Seat, Observable[]>() {
@Override
public Observable[] call(Seat seat) {
return new Observable[]{
seat.categoryMapProperty()
};
}
}
);
}
Элемент пользовательского интерфейса, который я хочу связать, представляет собой ListView с пользовательской ячейкой следующим образом:
public class CategoryCell extends ListCell<Category>{
private ToggleButton viewButton;
private Rectangle colorRect;
private Label name;
private Label count;
private GridPane pane;
public CategoryCell(ObservableList<Seat> seatList) {
super();
buildGui();
itemProperty().addListener((list, oldValue, newValue) -> {
if (newValue != null) {
//Bind color
colorRect.fillProperty().bind(newValue.colorProperty());
//Bind category name
name.textProperty().bind(newValue.nameProperty());
//Bind number of seats assigned to this category
LongBinding categorySeatNumProperty = Bindings.createLongBinding(() ->
seatList.stream().filter(seat -> seat.getCategory(newValue.getLayer()).equals(newValue)).count(), seatList);
count.textProperty().bind(categorySeatNumProperty.asString());
}
if (oldValue != null) {
name.textProperty().unbind();
count.textProperty().unbind();
colorRect.fillProperty().unbind();
}
});
}
private void buildGui() {
FontIcon hidden = new FontIcon("mdi-eye-off");
viewButton = new ToggleButton("");
viewButton.setGraphic(hidden);
viewButton.selectedProperty().addListener((observable,oldValue, newValue) -> {
Category category = itemProperty().get();
if (newValue == true) {
category.shownColorProperty().unbind();
category.setShownColor(Color.TRANSPARENT);
}else {
category.shownColorProperty().bind(category.colorProperty());
}
});
colorRect = new Rectangle(30,30);
name = new Label();
name.setMaxWidth(120);
pane = new GridPane();
count = new Label();
count.setPadding(new Insets(0,0,0,10));
ColumnConstraints nameCol = new ColumnConstraints();
nameCol.setHgrow( Priority.ALWAYS );
pane.getColumnConstraints().addAll(
new ColumnConstraints(40),
new ColumnConstraints(40),
nameCol,
new ColumnConstraints(40));
pane.addColumn(0, viewButton);
pane.addColumn(1, colorRect);
pane.addColumn(2, name );
pane.addColumn(3, count);
this.setText(null);
name.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getClickCount()==2) {
//launch the category editor TODO
}
}
});
}
Проблема заключается в том, что приведенный ниже код не запускается при изменении значения категории CategoryProperty в MapProperty Seat.
//Bind number of seats assigned to this category
LongBinding categorySeatNumProperty = Bindings.createLongBinding(() ->
seatList.stream().filter(seat -> seat.getCategory(newValue.getLayer()).equals(newValue)).count(), seatList);
count.textProperty().bind(categorySeatNumProperty.asString());
}
Любой совет, как этого добиться?
===== Разъяснения после комментария James_D ====
1) О модели: я на самом деле думал и немного колебался по этому поводу. Я хочу распределить категории по местам в концертных залах и сделать это на нескольких «слоях / уровнях». Скажем, например, ценовой «слой», где у меня может быть четыре категории ценников, и слой «продающей компании», где у меня будет 3 компании и т. Д. c ... Чтобы смоделировать это в моем классе Seat, у меня есть Map<Layer, Category>
, который выглядит как хороший выбор, поскольку место должно быть назначено только одной уникальной категории на слой. Затем мой класс Project отслеживает слои и их соответствующие категории, что на самом деле не нужно, но удобно для сохранения заданного пользователем порядка отображения.
2) Спасибо за обнаружение этой ошибки в CategoryCell! Порядок if (oldValue != null)
и if (newValue != null)
действительно должен быть обратным.
3) Теперь мне нужно ответить на мой первоначальный вопрос - это способ вызвать уведомление, когда категорияProperty в классе Map класса Seat имеет вид модифицирована. На самом деле, просто обновляя представление списка каждый раз, когда я изменяю свою Карту, это решает проблему, но это своего рода поражение цели обладания свойством Observable ...