java - setOnMouseEntered 不适用于 ListView 中的 ImageView

标签 java javafx javafx-8

我在 JavaFx 上的 ImageViews 上遇到 setOnMouseEntered 问题。 我正在尝试使用 ColorAdjust 更改放置在 Listview 中的 ImageView 的亮度。该效果本身适用于不在 ListView 中的 ImageView。

我猜只有ListView会触发setOnMouseEntered,但ImageViews不会,这是我的目标。 同样的问题是由 ImageView 的悬停效果引起的,它们在 ListView 中后不会立即触发。

fxml:

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

稍后,将为每个 ImageView 添加:

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

最佳答案

您的问题与此基本相同:Adding EventHandler To ImageView contained in a Label 。所有 Cell 特化(包括 ListCell)均继承自 Labeled,并且其所有默认外观均继承自 LabeledSkinBase,这是你的问题的根源。作为对错误的修复(请参阅其他问答),当将 ImageView 用作 Labeled 的图形时,它被设置为鼠标透明。由于 ImageView 是鼠标透明的,因此您的 MOUSE_ENTERED 处理程序由于明显的原因永远不会被调用。

如果您不知道,ListView 的默认单元工厂会返回一个 ListCell 实现,当该项是 Node 的实例时>,将单元格的图形设置为项目。一个简单的解决方法是使用您自己的 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 或至少消耗用户不必要的 RAM。

您可能需要考虑使用 Card 作为模型项,并结合 Image 对象的内存受限缓存(请参阅 WeakReference/SoftReference ,尽管您也可以寻找第三方缓存库)。 Card 类可以保存其关联图像的位置,或者缓存可以根据 Card 的状态导出位置。

但是,您仍然会使用 ImageView 作为 ListCell 的图形,因此您仍然需要使用上面提到的解决方法。使用内存受限缓存的帮助是,如果 Card 未显示在 ListCell 中,则其关联的 Image 可能会变为符合垃圾回收条件,从而减少应用程序的内存需求。

缓存还允许您在应用程序中的任何地方使用相同的Image(相同的Image可以在多个ImageView之间共享)这意味着当需要特定图像时,您并不总是加载新的图像(因为在请求时它可能仍然在内存中)。换句话说,任何缓存提供的典型功能。

关于java - setOnMouseEntered 不适用于 ListView 中的 ImageView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60310121/

相关文章:

java - 如何在方法之间进行交集

java - 尝试调用虚拟方法 'android.os.Parcelable android.os.Bundle.getParcelable(java.lang.String)'空对象引用

java - 在 Android 中制作时间表的最佳方式?

java - 是否可以根据函数动态生成 JavaFX TreeItem 的子项?

binding - JavaFX : Binding button disable property to ComboBox and DatePicker

java - GWT:SelectionChangeEvent.Handler 未检测到 CellTable 上行的取消选择

JavaFx - 为什么不能重写方法 "updateItem"?

java - 在 tableView 中显示列

JavaFX - 从不同线程调用 GUI 方法

java - TextField 中模糊的地方