Java 打开FXMLLoader';s控制器

Java 打开FXMLLoader';s控制器,java,intellij-idea,javafx,fxml,fxmlloader,Java,Intellij Idea,Javafx,Fxml,Fxmlloader,我正在创建JavaFX应用程序。是否有可能在JavaFX应用程序中打开控制器窗口。例如,我有应用程序的主屏幕,但当我打开其他modalWindow输入数据时,最后我输入了所有数据并单击保存按钮。ModalWindow应为不着色,主屏幕应刷新。我想打电话给家长控制器,从孩子控制器打电话。但是我在做这件事的时候出错了。任何其他的建议都是有用的 Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException

我正在创建JavaFX应用程序。是否有可能在JavaFX应用程序中打开控制器窗口。例如,我有应用程序的主屏幕,但当我打开其他modalWindow输入数据时,最后我输入了所有数据并单击保存按钮。ModalWindow应为不着色,主屏幕应刷新。我想打电话给家长控制器,从孩子控制器打电话。但是我在做这件事的时候出错了。任何其他的建议都是有用的

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

当我查看Stacktrace时,我发现它并不抱怨创建控制器

它首先抱怨无法加载FXML文件。不知怎的,它找不到它。因此,它会中止—甚至在到达要加载控制器的行之前(该行看起来很好):

线程“JavaFX应用程序线程”中出现异常 java.lang.IllegalStateException:未设置位置。 在javafx.fxml.fxmloader.loadImpl(fxmloader.java:2428) 在javafx.fxml.fxmloader.load(fxmloader.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();

JavaFXAPI只允许通过FXMLLoader.load()方法获取控件上的引用。对于FXMLLoader实例,您可以执行以下操作(就像您已经执行的一样:-):

这意味着:

  • 如果以后需要,最好在构建时间/加载时间保留控制器上的引用

  • 更好的方法是:如果需要从子控制器中访问父控制器,请三思。这可能是一个警告,说明应用程序的架构有问题

  • 如果您确实需要在子控制器和父控制器之间进行通信,那么最好执行“事件驱动”,即在子控制器中创建可观察的属性,并让父控制器侦听更改


  • 希望这有助于

    这里有一个从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:就我个人而言,目前我无法想象一个真正的项目中我会选择这样一种方法,因为当涉及到与应用程序其他部分的交互时,它很可能会引起头痛。但这不是由我来决定的

    尝试更改fxmlLoader.setLocation的参数时会发生什么。。。到getResource(/FXMLViews/MainScreen/mainSc.fxml):谢谢您的回答。是的,你在这里是完全正确的。它无法加载已经打开的FXml。我可以在这里做什么来正确地加载它并重新打开它,或者你会给我什么建议?我编辑了上面的答案,并添加了一些加载良好的代码。多次打开一个fxml文件应该不会有任何问题!另外,您的代码会抱怨找不到fxml文件。它说,文件的位置是错误的。它看错了地方。如果你能告诉我是什么让你相信的,错误的原因是文件已经打开或者控制器已经完全准备好加载,也许我能更好地理解?(我从你的帖子上看不出来)谢谢你的回复。但是它仍然会给出以前的错误。无法再次加载父Fxml,因为它已经打开。请不要发布多个答案,而是编辑一个并添加第二个答案的内容。猜你是正确的。原因是,op有两个问题:“我可以在这里做什么来正确地加载它关闭并重新打开”,另一个是stacktrace显示的错误。
    <?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>