setOnMouseEntered 不适用于 ListView 中的 ImageView
setOnMouseEntered not Working for ImageView in ListView
我对 ImageView 的 JavaFx 上的 setOnMouseEntered 有疑问。
我正在尝试使用 ColorAdjust 更改放置在 Listview 中的 ImageView 的亮度。效果本身适用于不在 ListView 中的 ImageView。
我猜只有 ListView 触发 setOnMouseEntered,而不是 ImageViews,这是我的目标。
同样的问题是ImageViews的悬停效果,在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
returns 的默认单元工厂是一个 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
或至少消耗用户不必要的 RAM。
您可能需要考虑使用 Card
作为模型项并结合内存受限的 Image
对象缓存(请参阅 WeakReference
/ SoftReference
,但您也可以寻找第三个-方缓存库)。 Card
class 可以保存其关联图像的位置,或者缓存可以根据 Card
.
的状态导出位置
您仍然会使用 ImageView
作为 ListCell
的图形,但是,您仍然需要使用上述解决方法。使用内存受限缓存的好处是,如果 Card
未显示在 ListCell
中,则其关联的 Image
可能符合垃圾收集条件,从而减少内存您的应用需求。
缓存还允许您在应用程序的任何地方使用相同的 Image
(相同的 Image
可以在多个 ImageView
之间共享),这意味着您不必总是在需要特定的 Image
时加载一个新的 Image
(因为在请求时它可能仍在内存中)。换句话说,任何缓存提供的典型功能。
我对 ImageView 的 JavaFx 上的 setOnMouseEntered 有疑问。 我正在尝试使用 ColorAdjust 更改放置在 Listview 中的 ImageView 的亮度。效果本身适用于不在 ListView 中的 ImageView。
我猜只有 ListView 触发 setOnMouseEntered,而不是 ImageViews,这是我的目标。 同样的问题是ImageViews的悬停效果,在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
returns 的默认单元工厂是一个 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
或至少消耗用户不必要的 RAM。
您可能需要考虑使用 Card
作为模型项并结合内存受限的 Image
对象缓存(请参阅 WeakReference
/ SoftReference
,但您也可以寻找第三个-方缓存库)。 Card
class 可以保存其关联图像的位置,或者缓存可以根据 Card
.
您仍然会使用 ImageView
作为 ListCell
的图形,但是,您仍然需要使用上述解决方法。使用内存受限缓存的好处是,如果 Card
未显示在 ListCell
中,则其关联的 Image
可能符合垃圾收集条件,从而减少内存您的应用需求。
缓存还允许您在应用程序的任何地方使用相同的 Image
(相同的 Image
可以在多个 ImageView
之间共享),这意味着您不必总是在需要特定的 Image
时加载一个新的 Image
(因为在请求时它可能仍在内存中)。换句话说,任何缓存提供的典型功能。