Как удалить EventHandler в JavaFX?

217
15 апреля 2022, 19:20

Есть у меня приложение. Есть в нем вызываемое модальное окно. Stage модального окна я не закрываю, я вызываю в нем stage.show(), выполняю нужный мне код и вызываю stage.hide(). Не закрываю stage окна потому, что эвенты не просто не удалялись, а плодились с каждым закрытым stage. В модальном окне я определяю три EventHandler'а, один на кнопку "Esc" реагирует, второй на кнопку "закрытия" внутри модального окна, третий на клик вне модального окна, т.е. на клик его родителя, главного окна. Каждый делает scene.hide(), по выполнении некоего кода. И вот клик на родителя, я никакими средствами не могу удалить, он впивается мертвой хваткой, захватывая в итоге контроль над кнопкой, показывающей модальное окно. Я знаю как продолжить работу приложения, не смотря на оставшийся эвент, все будет функционировать, но я знаю что eventHandler's будут плодиться все время работы приложения, это будет заметно по выводу в консоль (если его определить) и по растущей сжираемой памяти. Что есть в документации Oracle:

Event handlers enable you to handle events during the event bubbling phase. A node can have one or more handlers for handling an event. A single handler can be used for more than one node and more than one event type. If an event handler for a child node does not consume the event, an event handler for a parent node enables the parent node to act on the event after a child node processes it and to provide common event processing for multiple child nodes.

Я не могу правильно перевести этот текст, я не понимаю его суть. Я читаю технический английский, мне все везде понятно, но тут абсолютный тупик. Как я понял, Event распространяется на всех детей и родителей node, на которой был вызван. Как это вирусное распространение удалить, если я верно диагностировал появление? Я ставлю эвент на node родительскую, которая определена в Main классе кодом:

@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Scene scene = new Scene(root, 420, 565, Color.TRANSPARENT);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.show();
Utility.setRoot(root);
}

Я пробовал (это код из документации Oracle):

// Remove an event handler
myNode1.removeEventHandler(DragEvent.DRAG_EXITED, handler);

Следом:

    //To remove an event handler that was registered by a convenience method, pass null to the convenience method, for example, 
node1.setOnMouseDragged(null).

Кусок моего проблемного кода. Utility.getRoot() - это получение главной node всего приложения. Удалены лишние детали и переименованы некоторые части, для ясности, оставлены выводы в консоль, поскольку мне даже debug уже не помог, по консольному выводу пытаюсь понять, где засел жук Event'а:

   public void modalWindow(){
    stage.show();
    setEventHandlers();
}
private static void textChecks(){
    // Некий код, проверка текста
    removeEventHandlers();
    stage.hide();
}
private static void removeEventHandlers(){
    System.out.println("removeEventHandlers");
    okButton.setOnMouseClicked(null);
    Utility.getRoot().setOnMouseClicked(null);
    stage.getScene().setOnKeyPressed(null);
    Utility.getRoot().getOnMouseClicked();
/*
okButtonPressedEvent = null;
primeStageClicked = null;
keyPressEvent = null;
okButton.removeEventHandler(MouseEvent.MOUSE_CLICKED, okButtonPressedEvent);
primeStageClicked.removeEventHandler(MouseEvent.MOUSE_CLICKED, primeStageClicked);
stage.removeEventHandler(KeyEvent.KEY_PRESSED, keyPressEvent);
*/
}
private static void setEventHandlers(){
    // okButton press event
    okButton.setOnMouseClicked(event -> {
        System.out.println("okButtonPressedEvent");
        event.consume();
        textChecks();
    });
    // On out of node click event
    Utility.getRoot().setOnMouseClicked(event -> {
        System.out.println("primeStageClicked");
        event.consume();
        textChecks();
    });
    // Close on Esc pressed event
    stage.getScene().setOnKeyPressed(event -> {
        if (event.getCode() == KeyCode.ESCAPE) {
            // ----
            System.out.println("keyPressEvent");
            event.consume();
            textChecks();
            // ----
        }
    });

        /*//  press event
        okButtonPressedEvent = new EventHandler<MouseEvent>() {
            int mouseButton = 0;
            @Override
            public void handle(MouseEvent event) {
                System.out.println("buttonPressedEvent");
                textChecks();
                event.consume();
                okButton.removeEventFilter(MouseEvent.MOUSE_CLICKED, this);
                stage.hide();
            }
        };
        okButton.addEventHandler(MouseEvent.MOUSE_CLICKED, okButtonPressedEvent); // add the event handler to the doneButton
        // On out of node click event
        primeStageClicked = new EventHandler<MouseEvent>() {
            int mousePrime = 0;
            @Override
            public void handle(MouseEvent event) {
                System.out.println("primeStageClicked");
                textChecks();
                event.consume();
                Utility.getRoot().removeEventFilter(MouseEvent.MOUSE_CLICKED, this);
                stage.hide();
            }
        };
        Utility.getRoot().addEventFilter(MouseEvent.MOUSE_CLICKED, primeStageClicked); // add the event handler to the root stage
        // Close on Esc pressed event
        keyPressEvent = new EventHandler<KeyEvent>() {
            int keyEsc = 0;
            @Override
            public void handle(KeyEvent event) {
                if (event.getCode() == KeyCode.ESCAPE) {
                    // ----
                    System.out.println("keyPressEvent");
                    textChecks();
                    event.consume();
                    stage.removeEventFilter(KeyEvent.KEY_PRESSED, this);
                    stage.hide();
                    // ----
                }
            }
        };
        stage.addEventHandler(KeyEvent.KEY_PRESSED, keyPressEvent);*/
}

В основном stage кнопка, которая вызывает метод, показывающий сцену модального окна - вызывает event, который в выводе в консоль числится, как "primeStageClicked". Это клик вне модального окна, на любую часть родительского окна. Эта кнопка вызывает этот event после того, как первый раз верно отработает, назначаются эвенты, после она не показывает модальное окно, просто срабатывает эвент. Закомментированный код, это те же эвенты, но развернуто, я пытался создавать объект, потом удалять removeEvent/FilterHandler, пытался назначать null, никакие средства не удаляют event. Я перепробовал все, что смог нагуглить, а гуглить уже нечего, везде одинаковые рекомендации, которые у меня не работают. Либо я вещей фундаментальных не понимаю, либо просто не вижу конкретную ошибку. Ткните, где я ошибся?

Answer 1

Нашел причину. Эвент инициализируется при запуске, что и приводило к его срабатыванию и завершению сцены, так ее и не показав.

READ ALSO
что делает двоеточие вне метода foreach в java?

что делает двоеточие вне метода foreach в java?

Когда я ставлю двоеточие после любого слова, которое даже не является какой-то переменной, код принимает этоДопустим, если напишу "gjsdlg:"...

136
Показать ошибку нет интернета используя Retrofit 2 и RxJava

Показать ошибку нет интернета используя Retrofit 2 и RxJava

для получения данных с сервера использую вот такой запрос:

175
Выборка данных из нескольких таблиц в Hibernate

Выборка данных из нескольких таблиц в Hibernate

Как запросом получить данные из двух таблиц? Есть классы Patient и Service

133
spring обновление данных чере sql и через jpa

spring обновление данных чере sql и через jpa

обновляю данные через sql всё просто находим запись и делаем инкремент

131