我在TilePane中有很多ImageViews,它位于StackPane内部,然后是ScrollPane.TilePane的子节点之间没有边框,填充或边距,因此我没有机会点击ImageView.当我点击图像时,我希望MouseEvent的目标是ImageViews,而不是它是TilePane.
如何让事件链在ImageView上结束而不是在TilePane的早期结束?
否则,有没有办法可以使用其他信息获取ImageView?也许使用事件的坐标?
我这样做的通常方法就是将鼠标监听器注册到我感兴趣的节点; 在你的情况下,这意味着每个都注册一个鼠标监听器ImageView.然后,让每个鼠标监听器都可以引用它所注册的特定图像视图,或者根据需要引用其他数据(例如文件名).
可能发生的一件事是:如果您的图像具有透明像素,则默认情况下,鼠标点击图像的该部分将"直通"到下面的节点.您可以通过调用imageView.setPickOnBounds(true);图像视图来更改此行为.
一些测试代码.如果你运行它,你会看到一些带有不同颜色背景的编号图像.大约四分之一的人有透明背景(它们看起来是白色的).如果单击这些(但不是数字的实际文本),您将看到在滚动窗格和堆栈窗格中注册的鼠标处理程序将窗格窗格作为目标,并且ImageView甚至不调用在其中注册的处理程序.对于那些没有透明背景的人来说,目标始终是ImageView.如果选中复选框,pickOnBounds则true所有ImageViews都是如此,透明和不透明图像的行为都符合您的要求.
import java.util.Random;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ImageViewClickTest extends Application {
private static final Random RNG = new Random();
@Override
public void start(Stage primaryStage) {
TilePane tilePane = new TilePane();
CheckBox pickOnBounds = new CheckBox("Pick on bounds");
pickOnBounds.setPadding(new Insets(16));
for (int i=1; i<=200; i++) {
ImageView imageView = createImageView(i);
imageView.pickOnBoundsProperty().bind(pickOnBounds.selectedProperty());
// mouse handler directly on image view:
// can access image-view specific data...
String message = "Clicked on Image "+i ;
imageView.setOnMouseClicked(e ->
System.out.println("From handler on ImageView: "+message));
tilePane.getChildren().add(imageView);
}
StackPane stack = new StackPane(tilePane);
stack.setOnMouseClicked(e -> {
// source will be the stack pane
// target will be the top-most node
// (i.e. the ImageView, in most cases)
System.out.println("From handler on stack pane: Source: "+e.getSource());
System.out.println("From handler on stack pane: Target: "+e.getTarget());
});
ScrollPane scroller = new ScrollPane(stack);
scroller.setFitToWidth(true);
scroller.setOnMouseClicked(e -> {
// source will be the scroll pane
// target will be the top-most node
// (i.e. the ImageView, in most cases)
System.out.println("From handler on scroller: Source: "+e.getSource());
System.out.println("From handler on scroller: Target: "+e.getTarget());
});
BorderPane root = new BorderPane(scroller, pickOnBounds, null, null, null);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private ImageView createImageView(int index) {
Label label = new Label(Integer.toString(index));
label.setAlignment(Pos.CENTER);
label.setMinSize(48, 48);
label.setStyle(randomStyle());
Image image = new Scene(label, Color.TRANSPARENT).snapshot(null);
ImageView imageView = new ImageView(image);
return imageView ;
}
private String randomStyle() {
StringBuilder style = new StringBuilder();
style.append("-fx-background-color: -fx-background;");
style.append("-fx-background: ");
if (RNG.nextDouble() < 0.25) {
style.append( "transparent;");
style.append(" -fx-text-fill: black;") ;
} else {
String bg = String.format("#%02x%02x%02x;",
RNG.nextInt(256), RNG.nextInt(256), RNG.nextInt(256));
style.append(bg);
}
return style.toString();
}
public static void main(String[] args) {
launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)