JavaFX - StackPane с панелью как EventDispatcher

В панели диспетчера событий возникает событие нажатия мыши. Панель должна отображать контекстное меню своего поля со списком при возникновении события.

Это отлично работает, если событие переносится только на одну панель. Когда событие переносится на панель 1 и панель 2, контекстное меню первой панели не отображается. Я полагаю, это как-то связано с хвостом события и потреблением события.

До сих пор я не смотрел на класс EventDispatcher самого JDK.

Вот что у меня получилось:

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();
    }

}

Есть идеи, как с этим справиться?

Проблема заключается в том, в каком порядке вы пересылаете событие нажатия мыши. Когда отображается всплывающее меню, подобное тому, что показано на ComboBox, оно скрывается при нажатии мыши в другом месте сцены / экрана. Если вы переворачиваете cPaneOne.fireEvent и cPaneTwo.fireEvent, ComboBox должен отображаться после нажатия кнопки мыши.

Slaw 01.01.2019 05:32

Спасибо за объяснение. Я уже пробовал опцию переворота, и она тоже работает, но мне не подходит. Чтобы быть более точным: будущая цель состоит в том, чтобы при нажатии поля со списком на панели 1 фильтр событий должен быть добавлен на панель 2. При отпускании поля со списком фильтр событий должен быть удален из второй панели. Если взаимодействие за пределами поля со списком на панели происходит, описанная логика с фильтром событий выше не должна быть действительной. Изобразите первую панель как контейнер для нескольких элементов управления, которые задают разные свойства второй панели.

RobRoy 01.01.2019 12:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
95
1

Ответы 1

После некоторых идей я получил решение, которое, по крайней мере, работает:

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();
    }

}

Возможно, лучший подход придет во времена кого-то другого. С нетерпением жду ...

Другие вопросы по теме