Как делегировать события мыши всем базовым перекрывающимся панелям в JavaFX?
У меня есть некоторая верхняя панель оформления, которую я хочу обрабатывать / предварительно обрабатывать события мыши, но которая не должна поглощать их, т.е. все перекрывающиеся панели должны работать так, как если бы они не перекрывались панелью оформления.
Как это сделать? Я потерпел неудачу с нескольких попыток.
Ниже приведен код с 3 панелями. Зеленый "украшает". Задача состоит в том, чтобы сделать его прозрачным для событий мыши. Желтые и синие панели - рабочие панели. Они должны работать так, как будто они не перекрываются зеленой панелью.
Но зеленая панель должна получать события мыши.
Комментированные строки показывают, что я пытаюсь, а комментарии говорят, что оказалось не так:
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Created by dims on 13.10.2016.
*/
public class DelegateEventsToOverlappedNodes extends Application{
@Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
root.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
AnchorPane yellowPane = new AnchorPane();
yellowPane.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
yellowPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
System.out.println("yellowPane clicked");
}
});
root.getChildren().add(yellowPane);
Pane bluePane = new Pane();
bluePane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
bluePane.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
System.out.println("bluePane clicked");
}
});
AnchorPane.setLeftAnchor(bluePane, 200.);
AnchorPane.setRightAnchor(bluePane, 200.);
AnchorPane.setTopAnchor(bluePane, 200.);
AnchorPane.setBottomAnchor(bluePane, 200.);
yellowPane.getChildren().add(bluePane);
AnchorPane greenPane = new AnchorPane();
greenPane.setBackground(new Background(new BackgroundFill(Color.rgb(0, 255, 0, 0.9), CornerRadii.EMPTY, Insets.EMPTY)));
greenPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
System.out.println("greenPane clicked");
}
});
// greenPane.setVisible(false); // green pane invisible at all
// greenPane.setMouseTransparent(true); // green clicked doesn't occur
// greenPane.addEventHandler(Event.ANY, event -> yellowPane.fireEvent(event)); // works for yellow pane, but not for blue sub pane
root.getChildren().add(greenPane);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.setTitle("DelegateEventsToOverlappedNodes");
primaryStage.show();
}
public static void main(String[] args) {
DelegateEventsToOverlappedNodes.launch(args);
}
}
1 ответ
Вы могли бы установить greenPane
мышь снова прозрачна и добавьте фильтр событий в root
чтобы обработать события мыши здесь:
greenPane.setMouseTransparent(true);
root.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> System.out.println(event));
Фильтры получают события во время фазы захвата событий при обработке событий, тогда как обработчики запускаются во время фазы всплытия событий. Вы также можете использовать обработчик событий, но я думаю, что фильтр более идиоматичен в этом случае (подробнее здесь).
Ваш код:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class DelegateEventsToOverlappedNodes extends Application {
public static void main(String[] args) {
DelegateEventsToOverlappedNodes.launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
// Yellow pane.
AnchorPane yellowPane = new AnchorPane();
yellowPane.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
yellowPane.setOnMouseClicked(event -> System.out.println("yellowPane clicked"));
// Blue pane.
AnchorPane bluePane = new AnchorPane();
bluePane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
bluePane.setOnMouseClicked(event -> System.out.println("bluePane clicked"));
AnchorPane.setLeftAnchor(bluePane, 200.0);
AnchorPane.setRightAnchor(bluePane, 200.0);
AnchorPane.setTopAnchor(bluePane, 200.0);
AnchorPane.setBottomAnchor(bluePane, 200.0);
// Green pane.
AnchorPane greenPane = new AnchorPane();
greenPane.setBackground(new Background(new BackgroundFill(Color.rgb(0, 255, 0, 0.9), CornerRadii.EMPTY, Insets.EMPTY)));
greenPane.setMouseTransparent(true);
// Root pane.
StackPane rootPane = new StackPane();
rootPane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
rootPane.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> System.out.println(event));
// Layout and scene.
yellowPane.getChildren().add(bluePane);
rootPane.getChildren().addAll(yellowPane, greenPane);
primaryStage.setScene(new Scene(rootPane, 800.0, 600.0));
primaryStage.setTitle("DelegateEventsToOverlappedNodes");
primaryStage.show();
}
}
Если вы создали greenPane
только для предварительной обработки событий, в этом больше нет необходимости.