Как связать со свойством в ObservableMap в JavaFX? - PullRequest
0 голосов
/ 13 апреля 2020

Я пытаюсь автоматически обновить 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 ...

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