-1

I'm creating JAVA FX application. Is it a possible to get controller already opened window in JavaFX application.For Example I have mainScreen of Application but when I opened other modalWindow to enter data and finally I entered all data and clicked saved button. ModalWindow should be dissapear and mainScreen should be refreshed. I wanted to do it calling Parents Controller calling it from Children Controller. But I'm getting errors while doing it.Any other suggestions would be usefull.

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)

My ChildController Class

 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;
        }
Jahongir Sabirov
  • 460
  • 1
  • 8
  • 24
  • try what happens if you change the argument of the fxmlLoader.setLocation ... to ... .getResource(/FXMLViews/MainScreen/mainSc.fxml): – benji2505 Jan 18 '19 at 13:28

3 Answers3

0

When I look at the Stacktrace, I find, that it doesn't complain about creating the controller.

It complains that it can't load the FXML file in the first place. It somehow can't find it. So it aborts - before it even reaches the line where you want to load the controller(that line looks fine):

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)

You might want to look closer at the value of "FxmlViews.MainScreen.mainSc". It very likely points to some wrong path.

Example of loading a contoller twice:

       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();
kai
  • 894
  • 1
  • 7
  • 15
  • Thank you sir for answer. Yes you are totally true here.It can't load FXml which already opened.What I could do here to load it properly close and reopen it agian or what you will suggest to me ? – Jahongir Sabirov Jan 18 '19 at 13:35
  • I edited my answer above and added some code that loads just fine. Openeing a fxml file multiple times shouldn't be a problem at all! Plus your code complains, that it can't *find* the fxml file. It says, the location of the file is wrong. It looks at the wrong place. – kai Jan 18 '19 at 13:55
  • Maybe I understand better, if you could tell me what makes you believe, that the reason for the error is that the file is already open or that the controller was allready loaded? (I can't see that from your post) – kai Jan 18 '19 at 14:17
0

The JavaFX API only lets you obtain references on controlles via the FXMLLoader.load() method. With an instance of FXMLLoader you may do something like this (like you already do :-) ):

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();

This implies:

  1. Better keep references on the controllers on construction time/load time if you need them later.

  2. Even better: Think twice if you need to access a parent controller from within a child controller. This may be a warning that there is something wrong with the architecture of the app.

  3. If you really need communication between child controller and parent controller, better do it "event driven", i.e., create observable properties in the child controller and have the parent controller listen on changes.

Hope that helps ...

Robert Rohm
  • 331
  • 1
  • 7
0

Here is a controller that replaces itself from an FXML - file. It's simple and only has the single one button that triggers the replacment but that it does. The Stage, Scene and Controller are stored as static variables, to keep everything in one file. You can of couse store them wherever else you want.

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

And a 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>

I edited it so the button openens additionally a modal child dialog. Now this dialog is again created from the same fxml. From that modal dialog you can again press the replaceme button and open another modal dialog and from that third again and so on.

Whenever a modal dialog is closed(dialog done), the root controller gets replaced. For all children that were created.

So now you have also that modal dialog. Once the dialog is closed, the root gets replaced(and its always the root). And of couse you can also use a different FXM for the dialog.

FWIW: Personally, for now I can not imagine a real project in which I would choose such an aproach as it very likely causes headache when it comes interactions with other parts of the application. But thats not for me to decide.

kai
  • 894
  • 1
  • 7
  • 15
  • please don't post several answers, instead edit one and add the content of the second – kleopatra Jan 19 '19 at 11:02
  • guess you are righ. Reason was,,that the op has two questions:" tWhat I could do here to load it properly close and reopen" and the other is the error the stacktrace shows. – kai Jan 19 '19 at 23:48