在VBox中包含的TilePane中的ImageView中添加事件处理程序?

9
我有以下的架构:
  • 一个 VBox,它包含了一个 HBox 和一个 TilePane。

HBox 中有按钮、标签和文本框。

每次我点击根节点 (HBox),我都需要将 ImageView 添加到 tile pane 中。这个 ImageView 包含一张图片(例如:"2.jpg")。TilePane 最多只能容纳 5 个组件。

每次我点击图片时,我都应该将新的图片加载到被点击的 ImageView 中,例如:"1.jpg"。但是它并没有起作用。每当我点击图片时,它就像我点击了根节点一样,会创建另一个 TilePane 单元格。以下是代码,你能帮我解决吗?

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package dadao1;

import java.util.HashSet;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 *
 * @author Ambra
 */
public class Dadao1 extends Application {
    VBox root;
    HashSet dadi = new HashSet();
    //static int numeroDadi = 0;
    @Override
    public void start(Stage primaryStage) {       

        setGui();
        Scene scene = new Scene(root, 300, 300);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    } 
    /**
     *This private method sets up the GUI.
     * No parameters are required
     */
    private void setGui(){
        root = new VBox();
        HBox buttons = new HBox();
        final Button newGame = new Button("New Game");
        final Button print = new Button("Print");
        final Button animation = new Button("Moving");
        animation.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
            // this button is labeled "Moving" at the begin. If pressed it changes its label to "Dissolving" and viceversa.
            @Override
            public void handle(ActionEvent event) {
                if (animation.getText().equals(new String("Moving")))
                    animation.setText("Dissolving");
                else animation.setText("Mooving");
            }
        });
        final Label score = new Label("Total");
        final TextField points = new TextField();
        final Label pointsLabel = new Label("Score");
        root.setStyle("-fx-background-color: green");

        buttons.getChildren().addAll(newGame,print,animation,score,points,pointsLabel);
        final TilePane dadiPane = new TilePane();
        dadiPane.setVgap(10);
        dadiPane.setHgap(10);
        root.getChildren().addAll(buttons, dadiPane);

        root.setOnMouseClicked(new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {
                if(dadi.size()<5){
                    System.out.println("Adding img");
                    final ImageView img = new ImageView("2.jpg");
                    // should I put final in front of ImageView?
                    img.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {

                        @Override
                        public void handle(ActionEvent event) {
                            // I want that when a tile is pressed an event occours.
                            // that event should be "add a new image to the ImageView just clicked",
                            // for example: img is not "2.jpg" but "3.jpj", by the way, I'm not able neither 
                            // to to print the folowing messagge :(
                            // It's like my root is pressed even if my mouse ha clicked at the image in img var.
                            System.out.println("Tile pressed ");
                        }
                    });
                    dadi.add(img);
                    dadiPane.getChildren().add(img);
                }else System.out.println("You cannot create more than 5 dices");
            }
        });
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

尝试将 eventListener 添加到 ImageView 而不是根节点。 - ItachiUchiha
我必须为两者都添加一个事件处理器,因为它们需要执行不同的操作:当单击时,根节点必须向Tile面板添加一个ImageView,而ImageView必须在单击时更改图像。 - bog
3个回答

30

ImageView不会生成ActionEvent,因此您的事件处理程序从未被调用也就不足为奇了。由于鼠标事件没有被ImageView处理,所以它会向上传播到容器。

尝试:

img.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {

     @Override
     public void handle(MouseEvent event) {
         System.out.println("Tile pressed ");
         event.consume();
     }
});

它不起作用。它说Node类中的addEventHandler方法不能应用于给定的类型;需要:EventType<T>EventHandler<? super T>;找到:EventType<T><anonymous EventHandler<ActionEvent>> - bog
我认为我解决了这个问题,将new EventHandler<ActionEvent>()替换为new EventHandler<MouseEvent>()。编辑:它可以工作,但会调用img的事件和root的事件。 - bog
是的,打错字了...抱歉。为了防止事件在处理完后向上传播到HBox,请调用event.consume();。我已经修复了代码(包括打错的字和额外的调用)。 - James_D

5

@James_D 是正确的;但请注意,对于Java 8,您可以使用更简单的语法:

img.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
         System.out.println("Tile pressed ");
         event.consume();
     });

2
请注意,MouseEvent.MOUSE_CLICKED是javafx中的一个类,而不是java.awt.event包中的。最初的回答。
imgView. addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, event -> {
    //event clicked here
});

对于错误地导入了java.awt.event.MouseEvent类的人

最初的回答:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接