我在 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/