Открытие контроллера FXMLLoader

Я создаю приложение JAVA FX. Возможно ли, чтобы контроллер уже открыл окно в приложении JavaFX. Например, у меня есть mainScreen приложения, но когда я открыл другое модальное окно для ввода данных и, наконец, я ввел все данные и нажал кнопку «Сохранить». ModalWindow должен исчезнуть, а mainScreen должен обновиться. Я хотел сделать это, вызвав родительский контроллер, вызвав его из дочернего контроллера. Но при этом я получаю ошибки. Будут полезны любые другие предложения.

Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: Location is not set.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2428)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
at controllers.ExitDialogController.setLocaleToSave(ExitDialogController.java:92)
at controllers.AddDialogDepatureController.lambda$onClick$4(AddDialogDepatureController.java:221)
at controllers.AddDialogDepatureController$$Lambda$359/1446130991.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8216)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)

Мой класс дочернего контроллера

 if (new HttpRequests().departPost(jsonObject))
        {
            info.setStyle("-fx-text-fill: green");
            info.setText(myResourceBundle.getString("infoSave"));
            FXMLLoader fxmlLoader = new FXMLLoader();
            fxmlLoader.setLocation(getClass().getResource(FxmlViews.MainScreen.mainSc));
            try
            {
                AnchorPane frame = fxmlLoader.load();
                MainScreenController mainScreenController = (MainScreenController)fxmlLoader.getController();
                mainScreenController.updateTable(myResourceBundle);
            } catch (IOException e)
            {
                e.printStackTrace();
            }
            success = true;
        }

попробуйте, что произойдет, если вы измените аргумент fxmlLoader.setLocation ... на ... .getResource(/FXMLViews/MainScreen/mainSc.fxml):

benji2505 18.01.2019 14:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
290
3

Ответы 3

Когда я смотрю на Stacktrace, я обнаруживаю, что он не жалуется на создание контроллера.

Он жалуется, что не может загрузить файл FXML в первую очередь. Как-то не находит. Таким образом, он прерывается - еще до того, как он достигнет строки, в которой вы хотите загрузить контроллер (эта строка выглядит нормально):

Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: Location is not set. at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2428) at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)

Возможно, вы захотите рассмотреть значение «FxmlViews.MainScreen.mainSc». Скорее всего, это указывает на какой-то неправильный путь.

Пример загрузки контроллера дважды:

       String filename = "yourfxm.fxml";
        FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
        var node = loader.load();
        var controller = loader.getController();
        loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
        node = loader.load();
        controller = loader.getController();

Спасибо, сэр, за ответ. Да, вы совершенно правы. Он не может загрузить FXml, который уже открыт. Что я могу сделать, чтобы загрузить его правильно, закрыть и снова открыть, или что вы мне предложите?

Jahongir Sabirov 18.01.2019 14:35

Я отредактировал свой ответ выше и добавил код, который отлично загружается. Открытие файла fxml несколько раз не должно быть проблемой! Плюс ваш код жалуется, что не может найти файл fxml. Пишет, что расположение файла неверное. Он смотрит не в то место.

kai 18.01.2019 14:55

Может быть, я лучше понимаю, если бы вы могли сказать мне, что заставляет вас полагать, что причина ошибки в том, что файл уже открыт или что контроллер уже был загружен? (из вашего поста этого не видно)

kai 18.01.2019 15:17

API JavaFX позволяет получать ссылки на элементы управления только с помощью метода FXMLLoader.load(). С экземпляром FXMLLoader вы можете сделать что-то вроде этого (как вы уже делали :-)):

FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("MainForm.fxml"));
Parent root = (Parent) loader.load();

// as soon as the load() method has been invoked, the scene graph and the 
// controller instance are availlable:
MainFormController controller = loader.getController();

Из этого следует:

  1. Лучше сохраняйте ссылки на контроллеры во время строительства/времени загрузки, если они понадобятся вам позже.

  2. Еще лучше: подумайте дважды, если вам нужно получить доступ к родительскому контроллеру из дочернего контроллера. Это может быть предупреждением о том, что что-то не так с архитектурой приложения.

  3. Если вам действительно нужна связь между дочерним контроллером и родительским контроллером, лучше сделать это «управляемым событиями», то есть создать наблюдаемые свойства в дочернем контроллере и заставить родительский контроллер прослушивать изменения.

Надеюсь, это поможет ...

Спасибо, сэр, за ответ. Но он по-прежнему выдает предыдущие ошибки. Не удается загрузить Parent Fxml еще раз, потому что он уже открыт.

Jahongir Sabirov 18.01.2019 14:43

Вот контроллер, который заменяет себя из FXML-файла. Это просто и имеет только одну кнопку, которая запускает замену, но она это делает. Сцена, сцена и контроллер хранятся как статические переменные, чтобы все было в одном файле. Конечно, вы можете хранить их где угодно.

public class RootReplacingItselfController implements Initializable {
    public static RootReplacingItselfController controller = null;
    public static  Stage stage = null;
    public static Scene scene = null;
    public final static String filename = "/fxml/RootReplacingItself.fxml";

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    // TODO
    }    

    @FXML
    private void replaceme(ActionEvent event) {
        try {
           //open an additional modal Dialog 
           FXMLLoader dialogloader = new FXMLLoader(FXMLLoader.class.getResource(filename));
           Stage dialog = new Stage();

           dialog.setScene(new Scene(dialogloader.load()));
           dialog.initModality(Modality.APPLICATION_MODAL);
           dialog.initOwner(stage);
           dialog.showAndWait();

           //When the dialog is done replace myself:
           FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
            Parent node = loader.load();
            controller= loader.getController();
            scene.setRoot(node);
         } catch (IOException ex) {}
    }

    public static RootReplacingItselfController create(){

        try {
            FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
            Parent node = loader.load();
            controller= loader.getController();
            scene = new Scene(node);
            stage = new Stage();
            stage.setScene(scene);
            stage.show();
            return controller;
        } catch (IOException ex) {}
        return controller;
    }
}

И FXML:

<?xml version = "1.0" encoding = "UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane id = "AnchorPane" prefHeight = "151.0" prefWidth = "232.0" xmlns:fx = "http://javafx.com/fxml/1" xmlns = "http://javafx.com/javafx/11.0.1" fx:controller = "fxControls.RootReplacingItselfController">
   <children>
      <Button layoutX = "76.0" layoutY = "76.0" mnemonicParsing = "false" onAction = "#replaceme" text = "replaceme" />
   </children>
</AnchorPane>

Я отредактировал его, чтобы кнопка открывала дополнительно модальный дочерний диалог. Теперь этот диалог снова создается из того же fxml. Из этого модального диалога вы можете снова нажать кнопку replaceme и открыть другой модальный диалог, а из этого третьего снова и так далее.

Всякий раз, когда модальный диалог закрывается (диалог готов), корневой контроллер заменяется. Для всех детей, которые были созданы.

Итак, теперь у вас есть и этот модальный диалог. После закрытия диалога корень заменяется (и это всегда корень). И, конечно, вы также можете использовать другой FXM для диалога.

FWIW: Лично я пока не могу представить реальный проект, в котором я бы выбрал такой подход, так как он, скорее всего, вызывает головную боль, когда речь идет о взаимодействии с другими частями приложения. Но это не мне решать.

пожалуйста, не публикуйте несколько ответов, вместо этого отредактируйте один и добавьте содержание второго

kleopatra 19.01.2019 12:02

думаю, ты прав. Причина заключалась в том, что у оператора есть два вопроса: «Что я могу сделать здесь, чтобы загрузить его правильно, закрыть и снова открыть», а другой - ошибка, которую показывает трассировка стека.

kai 20.01.2019 00:48

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