JavaFX - StackPane with Pane as EventDispatcher

129 Views Asked by At

In the event dispatcher pane occurs an mouse pressed event. The pane one should show the context menu of it's combobox when a event occurs.

That works fine if the event is only dipatched to pane one. When the event is dipatched to pane one and pane two the context menu of pane one doesn't show up. I suppose it has something to do with the event tail and event consuming.

Until now i doesn't had a look at the EventDispatcher Class of the JDK itself.

Here is what i got so far:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 *
 * @author Robert
 */
public class EventDispatcherExample extends Application {

    private Group root;
    private StackPane cStackPane;
    private Pane cPaneEventDispatcher;
    private Pane cPaneOne;
    private ComboBox cComboBox;
    private Pane cPaneTwo;

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        root = new Group();

        cStackPane = new StackPane();
        cStackPane.setPrefHeight(200.0);
        cStackPane.setPrefWidth(200.0);

        cPaneEventDispatcher = new Pane();
        cPaneEventDispatcher.setPrefHeight(200.0);
        cPaneEventDispatcher.setPrefWidth(200.0);
        cPaneEventDispatcher.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //System.out.println("Mouse pressed in Pane ED.");
                cPaneOne.fireEvent(event);
                cPaneTwo.fireEvent(event);
            }
        });

        cPaneOne = new Pane();
        cPaneOne.setPrefHeight(200.0);
        cPaneOne.setPrefWidth(200.0);
        cPaneOne.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //System.out.println("Mouse pressed in Pane One.");
                cComboBox.show();
            }

        });
        ObservableList<String> observableList = FXCollections.observableArrayList();
        observableList.add("1");
        observableList.add("2");
        observableList.add("3");
        cComboBox = new ComboBox();
        cComboBox.setLayoutX(50.0);
        cComboBox.setLayoutY(50.0);
        cComboBox.setPrefHeight(30.0);
        cComboBox.setPrefWidth(100.0);
        cComboBox.setItems(observableList);

        cPaneTwo = new Pane();
        cPaneTwo.setPrefHeight(200.0);
        cPaneTwo.setPrefWidth(200.0);
        cPaneTwo.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //System.out.println("Mouse pressed in Pane Two.");
                //Something will happen because of selected item in Combo Box of pane one...
            }
        });

        cPaneOne.getChildren().add(cComboBox);
        // add the nodes in reverse order
        cStackPane.getChildren().add(cPaneTwo);
        cStackPane.getChildren().add(cPaneOne);
        cStackPane.getChildren().add(cPaneEventDispatcher);
        root.getChildren().add(cStackPane);

        Scene scene = new Scene(root, 200, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

}

Any ideas how to handle this?

1

There are 1 best solutions below

0
RobRoy On

After some ideas I got a solution that at least works:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

/**
 *
 * @author Robert
 */
public class EventDispatcherExample extends Application {

    private Group root;
    private StackPane cStackPane;
    private Pane cPaneEventDispatcher;
    private Pane cPaneOne;
    private ComboBox cComboBox;
    private boolean cComboBoxClicked = false;
    private Pane cPaneTwo;

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

    public boolean isComboBoxClicked() {
        if (cComboBoxClicked == true) {
            cComboBox.show();
        } else {
            cComboBox.hide();
        }
        return cComboBoxClicked;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        root = new Group();

        cStackPane = new StackPane();
        cStackPane.setPrefHeight(200.0);
        cStackPane.setPrefWidth(200.0);

        cPaneEventDispatcher = new Pane();
        cPaneEventDispatcher.setPrefHeight(200.0);
        cPaneEventDispatcher.setPrefWidth(200.0);
        cPaneEventDispatcher.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //System.out.println("Mouse pressed in Pane ED.");
                cPaneOne.fireEvent(event);
                cPaneTwo.fireEvent(event);
            }
        });

        cPaneOne = new Pane();
        cPaneOne.setPrefHeight(200.0);
        cPaneOne.setPrefWidth(200.0);
        cPaneOne.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //System.out.println("Mouse pressed in Pane One.");

                Rectangle rect = new Rectangle(cComboBox.getLayoutX(), cComboBox.getLayoutY(),
                        cComboBox.getPrefWidth(), cComboBox.getPrefHeight());
                cComboBoxClicked = rect.contains(event.getX(), event.getY());
            }
        });

        ObservableList<String> observableList = FXCollections.observableArrayList();
        observableList.add("1");
        observableList.add("2");
        observableList.add("3");
        cComboBox = new ComboBox();
        cComboBox.setLayoutX(50.0);
        cComboBox.setLayoutY(50.0);
        cComboBox.setPrefHeight(30.0);
        cComboBox.setPrefWidth(100.0);
        cComboBox.setItems(observableList);

        cComboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                // if cComboBoxSelectedIndex == 1 do Color on pane two
                // if cComboBoxSelectedIndex == 2 do Size on pane two
                // if cComboBoxSelectedIndex == 3 do ...
                //System.out.println("newValue " + newValue);
            }
        });

        cPaneTwo = new Pane();
        cPaneTwo.setPrefHeight(200.0);
        cPaneTwo.setPrefWidth(200.0);
        cPaneTwo.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //System.out.println("Mouse pressed in Pane Two.");

                boolean cComboBoxClicked = isComboBoxClicked();
                if (cComboBoxClicked){
                    //System.out.println("Skip code internally managed by pane two.");
                    return;
                }

                // Internal code of pane two
                //...
            }
        });

        cPaneOne.getChildren().add(cComboBox);
        // add the nodes in reverse order
        cStackPane.getChildren().add(cPaneTwo);
        cStackPane.getChildren().add(cPaneOne);
        cStackPane.getChildren().add(cPaneEventDispatcher);
        root.getChildren().add(cStackPane);

        Scene scene = new Scene(root, 200, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

}

Perhaps a better approach comes up during the time of someone else. Am looking forward...