Не удается получить этап JavaFx из узла, поскольку класс com.sun.javafx.stage.EmbeddedWindow не может быть приведен к классу javafx.stage.Stage

Я пытаюсь закрыть текущий fxml, чтобы перейти к следующему. Я последовал ответу на этот вопрос: закрыть окно fxml по коду, javafx:

@FXML private javafx.scene.control.Button closeButton;

@FXML
private void closeButtonAction(){
    // get a handle to the stage
    Stage stage = (Stage) closeButton.getScene().getWindow();
    // do what you have to do
    stage.close();
}

И я столкнулся с той же проблемой, что и комментарий без ответа ниже:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: com.sun.javafx.stage.EmbeddedWindow cannot be cast to javafx.stage.Stage

Все остальные ответы также не помогают. В EmbeddedWindow мало обсуждений, поэтому я понятия не имею, что делать дальше. Предыдущий экран был сделан с помощью javax.swing, а не JavaFx, и переход выглядит следующим образом:

import javafx.embed.swing.JFXPanel;

// more code

        JFXPanel fxPanel = new JFXPanel();
        this.add(fxPanel);
        
        this.setTitle("Title");
        this.setSize(1024, 768);
        this.setVisible(true);
        Platform.runLater(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    FXMLLoader loader = new FXMLLoader(getClass().getResource("<String url to my fxml file>"));
                    ScreenController controller = new ScreenController();
                    loader.setController(controller);
                    Parent root = loader.load();
                    fxPanel.setScene(new Scene(root));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

// more code

К тому времени, когда я закончил писать контекст, я думаю, что проблема может заключаться в использовании JFXPanel, но я также не могу найти решение. Так что помощь приветствуется. Спасибо!

Вам нужно смешивать JavaFX и Swing? Это не очень рекомендуется. Если вам действительно нужно это сделать, вам нужно будет передать ссылку на JFrame контроллеру, а контроллер вызовет setVisible(false) на JFrame (что нужно будет сделать в потоке диспетчеризации событий AWT, а не в FX). Тема приложения).

James_D 10.01.2023 19:24

В моем предыдущем комментарии я предполагаю, что вы хотите закрыть фактическое окно (что и сделал бы код, если бы вы отображали его на сцене). Очевидно, что если вы хотите отобразить другой FXML на той же панели, вам ничего из этого не нужно. В вашем вопросе говорится: «Я пытаюсь закрыть текущий fxml, чтобы перейти к следующему» (выделено мной), но вопрос, на который вы ссылаетесь, касается закрытия текущего окна. Что именно вы хотите сделать?

James_D 10.01.2023 19:35

@James_D следует инструкции в моем задании, и мне не разрешено ее менять. Я попробую ваше предложение и дам обновление позже.

Minh Long Vu 10.01.2023 19:37

Так что же на самом деле сказано делать? Закрыть окно? Или просто отобразить другой FXML?

James_D 10.01.2023 19:38

То, как я сейчас работаю, открывает новое окно для каждого файла fxml. Идея отобразить еще один FXML в той же панели не пришла мне в голову. На самом деле лучше так сделать. Однако мне все еще нужно вернуться к интерфейсу, созданному свингом. Для этого конкретного действия я должен сделать как ваш первый комментарий?

Minh Long Vu 10.01.2023 19:44

Следует также отметить, что актерский состав в исходном вопросе, который вы связали, не нужен. Вы можете просто сделать closeButton.getScene().getWindow().hide(), а для Stage (контекст исходного вопроса) close() эквивалентен методу суперкласса hide(). EmbeddedWindow, который возвращает getWindow(), когда сцена отображается в JFXPanel, конечно, является подклассом Window, поэтому вы можете сделать тот же вызов здесь, хотя я понятия не имею, что он на самом деле будет делать (т.е. я не знаю, что реализация EmbeddedWindow.hide() есть).

James_D 10.01.2023 22:07

«это соответствует инструкции в моем задании, и мне не разрешено его изменять» -> это уму непостижимо, что кто-то на самом деле создал задание, требующее смешивания JavaFX и Swing/AWT.

jewelsea 11.01.2023 02:04
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
Лучшая компания по разработке спортивных приложений
Лучшая компания по разработке спортивных приложений
Ищете лучшую компанию по разработке спортивных приложений? Этот список, несомненно, облегчит вашу работу!
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Если вы являетесь веб-разработчиком или тестировщиком, вы можете быть знакомы с Selenium, популярным инструментом для автоматизации работы...
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Что такое Java 8 Streams API? Java 8 Stream API
Деревья поиска (Алгоритм4 Заметки к учебнику)
Деревья поиска (Алгоритм4 Заметки к учебнику)
(1) Двоичные деревья поиска: среднее lgN, наихудшее N для вставки и поиска.
0
7
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы закрыть содержащее JFrame в смешанном приложении Swing и JavaFX из контроллера JavaFX, вам необходимо предоставить контроллеру достаточную информацию, чтобы закрыть окно. Вероятно, лучший способ правильно отделить это — просто иметь Runnable в контроллере, который знает, как закрыть окно:

public class ScreenController {

    private Runnable windowCloser ;

    public void setWindowCloser(Runnable windowCloser) {
        this.windowCloser = windowCloser;
    }

    // ...

    @FXML
    private void closeButtonAction(){
        
        // do what you have to do

        // close the current window:
        windowCloser.run();
    }

    // ...
}

А потом:

    JFXPanel fxPanel = new JFXPanel();
    this.add(fxPanel);
    
    this.setTitle("Title");
    this.setSize(1024, 768);
    this.setVisible(true);

    // Assuming this is a JFrame subclass
    // (otherwise replace "this" with a reference to the JFrame):

    Runnable windowCloser = () -> SwingUtilities.invokeLater(
        () -> this.setVisible(false)
    );

    Platform.runLater(() -> {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("<String url to my fxml file>"));
            ScreenController controller = new ScreenController();

            controller.setWindowCloser(windowCloser);

            loader.setController(controller);
            Parent root = loader.load();
            fxPanel.setScene(new Scene(root));
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

Вам также следует подумать о том, чтобы просто загрузить FXML в текущий JFXPanel, что намного проще:

public class ScreenController {


    // ...

    @FXML
    private Button closeButton;

    @FXML
    private void closeButtonAction(){

        Parent root = /* load next FXML */ ;
        closeButton.getScene().setRoot(root);
    }

    // ...
}

Я не понимаю эту часть: Runnable windowCloser = () -> SwingUtilities.runLater(() -> this.setVisible(false));. Также это дает мне ошибку The method runLater(() -> {}) is undefined for the type SwingUtilities.

Minh Long Vu 10.01.2023 20:33

@MinhLongVu Извините, SwingUtilities.invokeLater(...) (мои знания Swing почти никогда не используются в наши дни). Что тебе не понятно в коде?

James_D 10.01.2023 20:41

@MinhLongVu SwingUtilties.invokeLater(...) планирует запуск Runnable в потоке отправки событий (EDT). Это поток пользовательского интерфейса Swing. Эквивалентом в JavaFX является Platform.runLater(...), который планирует запуск Runnable в потоке приложения JavaFX (потоке пользовательского интерфейса JavaFX). Биты () -> ... — это лямбда-выражения. Если вы не понимаете лямбда-выражения, посетите docs.oracle.com/javase/tutorial/java/javaOO/… или geeksforgeeks.org/lambda-expressions-java-8

Slaw 10.01.2023 20:41

Да, invokeLater сработал. Я также попытался изменить SwingUtilities.runLater(...) на Platform.runLater(...), и он также работал при закрытии окна. Они чем-то отличаются?

Minh Long Vu 10.01.2023 20:45

Если это «вложенная лямбда», которая сбивает с толку, просто считайте ее Runnable r = () -> this.setVisible(false);. Тогда r — это Runnable, который закрывает окно, но он должен быть запущен в потоке отправки событий AWT, поэтому, чтобы передать его контроллеру FXML, вам нужен Runnable windowCloser = () -> SwingUtilities.invokeLater(r);.

James_D 10.01.2023 20:45

@MinhLongVu Platform.runLater(...) здесь неверно. Это закроет окно Swing в потоке приложения FX, что запрещено.

James_D 10.01.2023 20:48

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