打开FXMLLoader的控制器

时间:2019-01-18 12:20:23

标签: java intellij-idea javafx fxml fxmlloader

我正在创建JAVA FX应用程序。是否有可能让控制器已经在JavaFX应用程序中打开窗口。例如,我有Application的mainScreen,但是当我打开其他modalWindow输入数据,最后输入所有数据并单击“保存”按钮时。应该不显示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)

我的ChildController类

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

3 个答案:

答案 0 :(得分:0)

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

它抱怨它不能首先加载FXML文件。它以某种方式找不到。因此它中止了-在它甚至到达要加载控制器的行之前(那行看起来还不错):

  

线程“ JavaFX Application Thread”中的异常   java.lang.IllegalStateException:未设置位置。   在javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2428)   在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();

答案 1 :(得分:0)

JavaFX API仅允许您通过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. 如果您确实需要子控制器与父控制器之间的通信,则最好将其“事件驱动”,即在子控制器中创建可观察的属性,并让父控制器侦听更改。

希望有帮助...

答案 2 :(得分:0)

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