JavaFx按钮事件冒泡

时间:2014-05-21 07:51:11

标签: events button javafx pane

我正在使用java8中的javafx开发一个项目。 我关注一个奇怪的情况: 包含按钮(javafx.scene.control.Button)和另一个窗格的面板(类javafx.scene.layout.Pane)。我希望鼠标点击的事件可以冒泡到父级。但是,只有当我点击窗格时才会出现这种情况,而单击按钮时则不会发生这种情况。下面是具有此行为的一个非常简单的示例的代码。有没有人有解决这个问题的建议?我知道我可以根据窗格创建自己的按钮..但这只是一个讨厌的解决方法。 干杯

    package application;

    import javafx.animation.TranslateTransition;
    import javafx.application.Application;
    import javafx.event.Event;
    import javafx.event.EventHandler;
    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.Pane;
    import javafx.util.Duration;


    public class Main extends Application {

        double curScale;


        @Override
        public void start(Stage primaryStage) {
            try {
                BorderPane root = new BorderPane();
                Scene scene = new Scene(root,400,400);
                scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());


                Button btn = new Button("test");
                btn.setLayoutX(50);
                Pane p2 = new Pane();
                p2.setPrefSize(20,20);
                p2.setStyle("-fx-background-color: #440000");
                Pane p = new Pane();
                p.getChildren().add(btn);
                p.getChildren().add(p2);

                root.setTop(p);

                p.setOnMouseClicked(new EventHandler<Event>() {

                    @Override
                    public void handle(Event event) {
                        System.out.println("event source " + event.getSource() + " target : " + event.getTarget());

                    }
                });

                primaryStage.setScene(scene);
                primaryStage.show();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        public static void main(String[] args) {
            launch(args);
        }
    }

2 个答案:

答案 0 :(得分:8)

默认情况下,该按钮将使用鼠标单击事件,而窗格则不会。

如果要使用父窗格事件处理程序拦截鼠标单击按钮,则应使用event filter这样做(在捕获阶段而不是冒泡阶段拦截事件)。

如果您需要了解捕获与冒泡概念,请阅读event processing

答案 1 :(得分:1)

感谢jewelsea的回答,我想出了这个有效的例子:

package application;



import com.oracle.jrockit.jfr.EventToken;

import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;


    public class Main extends Application {

        double curScale;


        @Override
        public void start(Stage primaryStage) {
            try {
                BorderPane root = new BorderPane();
                Scene scene = new Scene(root,400,400);
                scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());


                Button btn = new Button("test");
                btn.setLayoutX(50);
                Pane p2 = new Pane();
                p2.setPrefSize(20,20);
                p2.setStyle("-fx-background-color: #440000");
                Pane p = new Pane();
                p.getChildren().add(btn);
                p.getChildren().add(p2);

                Pane p3 = new Pane();
                p3.getChildren().add(p);
                root.setTop(p3);

                p3.setOnMouseClicked(new EventHandler<Event>() {

                    @Override
                    public void handle(Event event) {
                        System.out.println("top pane got the clicked event");
                    }
                });


                // Define an event filter
                EventHandler filter = new EventHandler<Event>() {

                    @Override
                    public void handle(Event event) {
                        System.out.println("Filtering out event " + event.getEventType() +  "   source  " + event.getSource() + "   target " + event.getTarget());
                        Node node = (Node) event.getTarget();
                        try{
                            Button b = (Button)event.getSource();
                            node.fireEvent(new MyEvent( b.getText() ));
                        }catch(Exception e){
                            node.fireEvent(new MyEvent( "pane" ));
                        }

                event.consume();
                    }
                };

                btn.addEventFilter(MouseEvent.MOUSE_CLICKED, filter);
                p2.addEventFilter(MouseEvent.MOUSE_CLICKED, filter);

                p.addEventHandler(MyEvent.BUTTON_PRESSED, new MyEventHandler());

                primaryStage.setScene(scene);
                primaryStage.show();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        public static void main(String[] args) {
            launch(args);
        }



    // The Handler
    class MyEventHandler implements EventHandler<MyEvent> {

        @Override
        public void handle(MyEvent event) {

            System.out.println("MyEvent " + event.data);

        }
    }

    // The Event
        static class MyEvent extends Event {

            public final static EventType<MyEvent> BUTTON_PRESSED = new EventType(ANY, "BUTTON_PRESSED");

            public String data;

            public MyEvent() {
                this(BUTTON_PRESSED);
            }

            public MyEvent(String what){
                    this(BUTTON_PRESSED);
                    data = what;
            }

            public MyEvent(EventType<? extends Event> arg0) {
                super(arg0);
            }
            public MyEvent(Object arg0, EventTarget arg1, EventType<? extends Event> arg2) {
                super(arg0, arg1, arg2);
            }  
        }
    }