简体   繁体   English

setOnMouseEntered 不适用于 ListView 中的 ImageView

[英]setOnMouseEntered not Working for ImageView in ListView

i have a problem with setOnMouseEntered on JavaFx for ImageViews.我在 JavaFx 上为 ImageViews 设置了 setOnMouseEntered 有问题。 I'm trying to change the brightness of ImageViews placed in a Listview with ColorAdjust.我正在尝试使用 ColorAdjust 更改放置在 Listview 中的 ImageViews 的亮度。 The effect itself works for ImageViews that are not in the ListView.该效果本身适用于不在 ListView 中的 ImageView。

I guess that only the ListView triggers the setOnMouseEntered, but not the ImageViews, which is my goal.我想只有 ListView 触发了 setOnMouseEntered,而不是 ImageViews,这是我的目标。 The same problem is caused by the hover effects of the ImageViews, which are not triggered as soon as they are in a ListView.同样的问题是由 ImageViews 的悬停效果引起的,当它们在 ListView 中时不会立即触发。

fxml:文件:

 <ListView fx:id="cardsView" />

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

Later, for each of these ImageViews will be added:稍后,将为这些 ImageView 中的每一个添加:

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

While debugging I figured out that things like css and the setOnMouseEntered are added correctly.在调试时,我发现像 css 和 setOnMouseEntered 这样的东西被正确添加。 So it seems to be somehow blocked by the ListView that the ChildNodes get the setOnMouseEntered or Hover effect instead of the ListView所以它似乎被 ListView 以某种方式阻止了 ChildNodes 获得 setOnMouseEntered 或 Hover 效果而不是 ListView

Your problem is basically the same as this one: Adding EventHandler To ImageView contained in a Label .您的问题与此基本相同:将 EventHandler 添加到包含在 Label 中的 ImageView All Cell specializations, including ListCell , inherit from Labeled and all their default skins inherit from LabeledSkinBase , which is the source of your problem.所有Cell ,包括ListCell ,都继承自Labeled ,它们的所有默认皮肤都继承自LabeledSkinBase ,这是您的问题的根源。 As a fix to a bug (see other Q&A) when an ImageView is used as the graphic of a Labeled it is set to be mouse-transparent.作为对错误的修复(请参阅其他问答),当ImageView用作Labeled的图形时,它被设置为鼠标透明。 Since the the ImageView is mouse-transparent your MOUSE_ENTERED handler can never be invoked for obvious reasons.由于ImageView是鼠标透明的,因此您的MOUSE_ENTERED处理程序永远不会因显而易见的原因被调用。

If you're not aware, the default cell factory of ListView returns a ListCell implementation that, when the item is an instance of Node , sets the graphic of the cell to the item.如果您不知道, ListView的默认单元工厂会返回一个ListCell实现,当项目是Node的实例时,将单元的graphic设置为项目。 An easy fix is to use your own ListCell implementation that wraps the ImageView in another node, such as Pane .一个简单的解决方法是使用您自己的ListCell实现,该实现将ImageView包装在另一个节点中,例如Pane Here's an example:下面是一个例子:

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

This will prevent the ImageView from becoming mouse-transparent.这将防止ImageView变得鼠标透明。


As a side note, it's typically not a good idea to use GUI objects (eg ImageView ) as the model item of a ListView (or any other virtualized control).作为旁注,使用 GUI 对象(例如ImageView )作为ListView (或任何其他虚拟化控件)的模型项通常不是一个好主意。 In this case, it may be an even worse idea since this set-up encourages holding every Image related to your application in memory simultaneously.在这种情况下,这可能是一个更糟糕的主意,因为这种设置鼓励将与您的应用程序相关的每个Image同时保存在内存中。 Depending on how many images there are, as well as how large those images are, this can easily lead to an OutOfMemoryError or at least consume an unnecessary amount of your users' RAM.根据有多少图像,以及这些图像有多大,这很容易导致OutOfMemoryError或至少消耗不必要的用户 RAM。

You may want to consider using Card as the model item combined with a memory-constrained cache of Image objects (see WeakReference / SoftReference , though you could also look for a third-party caching library).您可能需要考虑使用Card作为模型项,并结合Image对象的内存受限缓存(请参阅WeakReference / SoftReference ,但您也可以寻找第三方缓存库)。 The Card class could hold the location of its associated image or the cache could derive the location based on the state of the Card . Card类可以保存其关联图像的位置,或者缓存可以根据Card的状态派生该位置。

You would still use an ImageView as the graphic of your ListCell , however, so you would still need to use the workaround mentioned above.但是,您仍将使用ImageView作为ListCell的图形,因此您仍然需要使用上述解决方法。 What using a memory-constrained cache helps with is that, if a Card isn't being displayed in a ListCell then its associated Image possibly becomes eligible for garbage collection, thus reducing the memory demands of your application.使用内存受限缓存的帮助在于,如果Card未显示在ListCell那么其关联的Image可能有资格进行垃圾回收,从而减少应用程序的内存需求。

The cache also allows you to use the same Image everywhere in your application (the same Image can be shared between multiple ImageView s) and means you don't always load a new Image when a particular one is needed (as it could still be in memory when requested).缓存还允许您在应用程序中的任何地方使用相同的Image (相同的Image可以在多个ImageView之间共享),这意味着当需要特定的Image时,您并不总是加载新的Image (因为它可能仍然在请求时的内存)。 In other words, the typical functionality provided by any cache.换句话说,任何缓存提供的典型功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM