setOnMouseEntered не работает для ImageView в ListView - PullRequest
0 голосов
/ 20 февраля 2020

У меня проблема с setOnMouseEntered на JavaFx для ImageViews. Я пытаюсь изменить яркость ImageViews, помещенных в ListView с ColorAdjust. Сам эффект работает для ImageViews, которых нет в ListView.

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

f xml:

 <ListView fx:id="cardsView" />

java - Код:

@FXML private ListView<ImageView> cardsView;
private ObservableMap<ImageView, Card> hCards;

@FXML
public void initialize() {
  hCards= FXCollections.observableHashMap();
  cardsView.getItems().setAll(hCards.keySet());
  hCards.addListener(
    (MapChangeListener<ImageView, Card>)
        change -> {
          cardsView.getItems().removeAll(change.getKey());
          if (change.wasAdded()) {
            cardsView.getItems().add(change.getKey());
          }
        });
  }

Позже, для каждого из этих ImageViews будут добавлены:

private void addLightEffectOnMouseEntered(ImageView imageView) {
  imageView.setOnMouseEntered(
    t -> {
      ColorAdjust colorAdjust = new ColorAdjust();
      colorAdjust.setBrightness(0.4);
      imageView.setEffect(colorAdjust);
    });
}

Во время отладки я выяснил, что такие вещи, как css и setOnMouseEntered добавляются правильно. Так что ListView каким-то образом блокирует, что ChildNodes получают эффект setOnMouseEntered или Hover вместо ListView

1 Ответ

2 голосов
/ 20 февраля 2020

Ваша проблема в основном такая же: Добавление EventHandler к ImageView, содержащемуся в метке . Все Cell специализации, включая ListCell, наследуются от Labeled, а все их скины по умолчанию наследуются от LabeledSkinBase, что является источником вашей проблемы. Для исправления ошибки (см. Другие вопросы и ответы), когда ImageView используется в качестве графика c для Labeled, он устанавливается прозрачным для мыши. Поскольку ImageView прозрачен для мыши, ваш обработчик MOUSE_ENTERED никогда не может быть вызван по очевидным причинам.

Если вы не знаете, фабрика ячеек по умолчанию ListView возвращает реализацию ListCell что, когда элемент является экземпляром Node, для элемента устанавливается graphic ячейки. Простое решение - использовать собственную реализацию ListCell, которая оборачивает ImageView в другой узел, такой как Pane. Вот пример:

listView.setCellFactory(lv -> new ListCell<>() {

  private final Pane imageViewContainer = new Pane();

  @Override
  protected void updateItem(ImageView item, boolean empty) {
    super.updateItem(item, empty);
    if (empty || item == null) {
      imageViewContainer.getChildren().clear();
      setGraphic(null);
    } else {
      imageViewContainer.getChildren().setAll(item);
      setGraphic(imageViewContainer);
    }
  }
});

Это не позволит ImageView стать прозрачным для мыши.


В качестве примечания, обычно не рекомендуется использовать GUI объекты (например, ImageView) в качестве элемента модели ListView (или любого другого виртуализированного элемента управления). В этом случае это может быть еще худшая идея, поскольку эта настройка поощряет одновременное хранение в памяти каждого Image, связанного с вашим приложением. В зависимости от количества изображений, а также от их размера, это может легко привести к OutOfMemoryError или, по крайней мере, потреблению ненужного объема оперативной памяти ваших пользователей.

Возможно, вы захотите рассмотреть использование Card в качестве элемента модели в сочетании с ограниченным объемом памяти объектов Image (см. WeakReference / SoftReference, хотя вы также можете искать третий библиотека кэширования партий). Класс Card может содержать местоположение связанного с ним изображения, или кэш может получить местоположение на основе состояния Card.

. Вы все равно будете использовать ImageView в качестве графика c из вашего ListCell, однако, вам все равно придется использовать обходной путь, упомянутый выше. Помогает использование кэш-памяти с ограничением памяти: если Card не отображается в ListCell, то связанный с ним Image, возможно, становится пригодным для сбора мусора, что снижает требования к памяти вашего приложения.

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

...