Добавление обработчика событий в ImageView, содержащееся в метке

Недавно я начал изучать Java FX и хочу создать собственную метку, внутри которой будет ImageView.

Это код для моей пользовательской метки.

Image image = new Image(getClass().getResourceAsStream("/img/remove.png"), 20, 20, true, true);
ImageView removeImageView = new ImageView(image);

Label customLabel = new Label(labelText, removeImageView);
customLabel.setFont(Font.font("Arial", FontWeight.BOLD, 20));

Вот так выглядит моя индивидуальная этикетка.

введите здесь описание изображения

Теперь я хочу добавить щелчок мышью EventHandler в ImageView. Это мой код для обработки щелчков мыши.

removeImageView.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
      @Override
      public void handle(MouseEvent event) {
        System.out.println("Imageview Clicked");
      }
    });

Но когда я нажимаю на изображение cross, событие не фиксируется.

Я немного поэкспериментировал и попытался добавить EventHandler в файл customLabel. Метка смогла зафиксировать щелчок мыши.

Мне кажется, что я столкнулся с этой проблемой, потому что ImageView содержится в метке. Я хочу знать, является ли это ограничением для JFX или есть какой-либо альтернативный способ достижения этой функциональности. Спасибо.


person Rito    schedule 30.09.2018    source источник
comment
Я не понимаю, почему это не сработает. Где вы устанавливаете обработчик событий?   -  person Sedrick    schedule 30.09.2018
comment
@Sedrick Я установил его чуть ниже строки: ImageView removeImageView = new ImageView(image);   -  person Rito    schedule 30.09.2018


Ответы (3)


Похоже, это следствие исправления JDK-8117199. исправление добавило в LabeledSkinBase#updateChildren() следующее:

// RT-19851 Only setMouseTransparent(true) for an ImageView.  This allows the button
// to be picked regardless of the changing images on top of it.
if (graphic instanceof ImageView) {
    graphic.setMouseTransparent(true);
}

Как видите, когда изображение элемента управления Labeled представляет собой ImageView, оно становится прозрачным для мыши. Обходным путем было бы установить прозрачность мыши ImageView обратно на false.

ImageView view = new ImageView();
view.mouseTransparentProperty().addListener((observable, oldVal, newVal) -> {
    if (newVal) {
        view.setMouseTransparent(false);
    }
});

Поскольку вы не используете CSS для изменения изображения в зависимости от состояния наведения/взведения, это не должно вызывать проблем, связанных с ошибкой. Однако я был бы осторожен; на всякий случай.


Лучший обходной путь, упомянутый @fabian, состоит в том, чтобы обернуть ImageView каким-то другим Node (например, Pane).

Label customLabel = new Label(labelText, new Pane(removeImageView));

Это делает графику Pane, что означает, что специальная обработка ImageView в updateChildren() не выполняется.

person Slaw    schedule 30.09.2018
comment
Я думаю, что вы правы насчет источника проблемы. Когда я изменил removeImageView на Text removeImageView = new Text("X");, обработчик событий отвечает, как и ожидалось. +1 . я исправлю свой ответ - person c0der; 30.09.2018

Другой обходной путь для ImageView прозрачности мыши (см. Slaw answer) состоит в том, чтобы обработать событие на ImageView родительском (Lable) и повторно огонь это:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class PropegateEvent extends Application {

    @Override
    public void start(Stage stage) {

        Image image = new Image("https://addons-media.operacdn.com/media/extensions/65/165965/1.1.0.0-rev1/icons/icon_64x64_6dd346d4c61d287ae74c612622d1353f.png");
        ImageView removeImageView = new ImageView(image);
        Label customLabel = new Label("rito", removeImageView);
        Pane root = new Pane(customLabel);
        stage.setScene(new Scene(root));

        //////////////////////////////////////////////////////////////
        //handle mouse event click on label -  refire it as image view event:
        customLabel.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> removeImageView.fireEvent(event));
        ///////////////////////////////////////////////////////////////

        removeImageView.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
              @Override
              public void handle(MouseEvent event) {
                System.out.println("Imageview Clicked");
                event.consume();
              }
            });
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
person c0der    schedule 30.09.2018

Один из способов справиться с этой ситуацией — использовать HBox. Вместо того, чтобы передавать ImageView в конструктор Label, установите ImageView и Label в качестве дочерних узлов HBox

ImageView removeImageView = new ImageView(image); 
Label customLabel = new Label("rito");
customLabel.setFont(Font.font("Arial", FontWeight.BOLD, 20));


HBox hbox = new HBox(removeImageView,customLabel);
root.getChildren().add(hbox);

removeImageView.setOnMouseClicked(e->{
            System.out.println("ImageView clicked");
        });


customLabel.setOnMouseClicked(e->{
            System.out.println("Lable clicked");
        });
person Umer Farooq    schedule 30.09.2018