10 Replies Latest reply: May 17, 2012 8:07 AM by daniel RSS

    Loading and Unloading of FXML components at runtime

    932812
      Hi,
      i want to load and / or unload components at runtime in FXML and controller.

      Scenario ::

      say for example there are 3 FXMLs
      one parent and two children
      now by default child 1 will be loaded.
      now i want to load child 2 and unload child 1 (possibly from /in memory)

      is it possible if yes please let me know

      Thanks :)
        • 1. Re: Loading and Unloading of FXML components at runtime
          885691
          Yes, this is possible, though there's not really any concept of "unloading" FXML. The result of loading an FXML document is an object hierarchy (generally, some part of a scene graph). If you replace a previously loaded part of your scene graph with a new graph loaded from a different FXML file, the previous hierarchy will simply be garbage collected.
          • 2. Re: Loading and Unloading of FXML components at runtime
            932812
            Hi Greg ,
            Thanks for ur quick reply :)
            However my scenario is like there is parent fxml say for example parent.fxml containing a TabPane .*
            By default SplitPane is there as a content in the tab which is present in MySplitPane.fxml* and there a Button say "LoadGrid" and "LoadPrev" ; so now on click on that "LoadGrid" button i want to load a grid pane_ which is in third file say MyGridPane.fxml+ and that will now replace the entire area captured by splitpane . So now at the end there will be now GridPane and not the SplitPane . Suppose if now i click on "LoadPrev" button which is in parent tab then there will be SpliPane and not the GridPane.
            If possible please provide the sample code snippet :)
            • 3. Re: Loading and Unloading of FXML components at runtime
              885691
              As I said, there's no real difference between content loaded from FXML and content created in Java. If you can outline how you might approach this in Java, I can probably help translate it to FXML.

              Note that you'll still need to write some Java (or script) code here - FXML does not provide any built-in support swapping scene graph branches.
              • 4. Re: Loading and Unloading of FXML components at runtime
                932812
                Greg here i am posting a code snippet and use case scenario

                *1) DemoParent.fxml*



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

                <?import java.lang.*?>
                <?import java.util.*?>
                <?import javafx.scene.control.*?>
                <?import javafx.scene.layout.*?>
                <?import javafx.scene.paint.*?>
                <?import javafx.scene.text.*?>

                <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" fx:controller="DemoScreenControllert">
                <children>
                <TabPane id="tabPane1" prefHeight="400.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                <tabs>
                <Tab id="tab1" text="Home">
                <content>
                <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
                <children>
                <Text id="text1" layoutX="191.0" layoutY="110.0" stroke="#a533ff" text="Home Tab Selected">
                <font>
                <Font name="System Bold Italic" size="30.0" />
                </font>
                </Text>
                </children>
                </AnchorPane>
                </content>
                </Tab>
                <Tab id="tab2" text="One">
                <content>
                <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
                </content>
                </Tab>
                <Tab id="tab3" text="Two">
                <content>
                <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
                <children>
                <VBox id="vBox1" layoutX="14.0" layoutY="7.0" prefHeight="348.0" prefWidth="492.0" spacing="10.0">
                <children>
                <ToolBar id="toolBar1">
                <items>
                <Button id="button1" text="HORIZONTAL PANE" />
                <Button id="button2" text="VERTICLE PANE" onAction="#loadVerticlePane"/>
                </items>
                </ToolBar>
                <HBox id="hBox1" alignment="CENTER_LEFT" prefHeight="39.0" prefWidth="492.0" spacing="10.0">
                <children>
                <TextField id="textField1" prefWidth="200.0" text="TextField" />
                <Button id="button3" text="Search" />
                <Button id="button4" text="Clear" />
                </children>
                </HBox>
                <SplitPane id="splitPaneHorizontal1" dividerPositions="0.3" focusTraversable="true" prefHeight="244.0" prefWidth="492.0">
                <items>
                <AnchorPane id="anchorPane1" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
                <AnchorPane id="anchorPane2" minHeight="0.0" minWidth="0.0" prefHeight="242.0" prefWidth="305.0" />
                </items>
                </SplitPane>
                </children>
                </VBox>
                </children>
                </AnchorPane>
                </content>
                </Tab>
                </tabs>
                </TabPane>
                </children>
                </AnchorPane>

                end of DemoParent.fxml


                *2) DemoScreenController.java*


                /*
                * To change this template, choose Tools | Templates
                * and open the template in the editor.
                */


                import java.io.IOException;
                import java.net.URL;
                import java.util.ResourceBundle;
                import java.util.logging.Level;
                import java.util.logging.Logger;
                import javafx.event.ActionEvent;
                import javafx.fxml.FXML;
                import javafx.fxml.FXMLLoader;
                import javafx.fxml.Initializable;
                import javafx.scene.Parent;
                import javafx.scene.control.Label;
                /**
                *
                * @author amol.hingmire
                */
                public class DemoScreenController implements Initializable{


                     @FXML
                private void loadVerticlePane(ActionEvent event) {
                try {
                // TODO : Should perform something like following code so that the horizontal split pane(tab two) will get replaced by verticle pane which in verticlePane.fxml

                Parent root = FXMLLoader.load(getClass().getResource("verticlePane.fxml"));
                } catch (IOException ex) {
                Logger.getLogger(DemoScreenController.class.getName()).log(Level.SEVERE, null, ex);
                }
                }
                     
                @Override
                public void initialize(URL url, ResourceBundle rb) {

                //TODO
                }
                }


                end of  DemoScreenController.java

                *3) verticlePane.fxml*


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

                <?import java.lang.*?>
                <?import java.util.*?>
                <?import javafx.scene.control.*?>
                <?import javafx.scene.layout.*?>
                <?import javafx.scene.paint.*?>

                <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="252.0" prefWidth="345.0" xmlns:fx="http://javafx.com/fxml">
                <children>
                <SplitPane id="splitPaneVertical1" dividerPositions="0.5" focusTraversable="true" orientation="VERTICAL" prefHeight="252.0" prefWidth="345.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                <items>
                <AnchorPane id="anchorPane1" minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" />
                <AnchorPane id="anchorPane2" minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" />
                </items>
                </SplitPane>
                </children>
                </AnchorPane>

                end of verticlePane.fxml

                Use Case :

                run first  file
                goto tab "Two"
                click on "VERTICLE PANE" buttton
                after clicking on that  button the horizontal split pane should get replaced by verticle split pane present in verticlePane.fxml ; the remaining controls should remain the same .

                again clicking on "HORIZONTAL PANE" verticle pane should get replaced with the earlier horizontal pane.

                Edited by: 929809 on May 8, 2012 8:04 PM

                Edited by: 929809 on May 8, 2012 8:14 PM
                • 5. Re: Loading and Unloading of FXML components at runtime
                  937937
                  Good day to you sir.
                  you seem really prepared in this matter.

                  I Need HELP...really URGENT please.

                  Is there the possibility to access the objects created from the FXML file from java code directly?
                  I am STUCK and cant find anywhere:

                  i made the UI in JFX 2 Scene Builder but i cant access the nodes/instances as i could if hand coded directly in java...so now i cant dynamically expand my UI..nor access entered data...and root.lookup(#) just works in a limited way it wont access deep down in the hierarchy.

                  IS IT POSIBLE TO ACCESS THE OBJECTS/NODES MADE IN FXML directly from the aplication that loaded the file?
                  if it is..how to access those objects so that they can interact with the other java dinamic parts of the UI?
                  THANKS Really its important and i just cant find info about it.
                  • 6. Re: Loading and Unloading of FXML components at runtime
                    932812
                    Hi,
                    to answer your node.lookup("#element_id") ;
                    you can definitely perform your lookup of nodes . It totally depends upon how your FXML is structred and of course the scene graph currently generated .

                    for further information please post your code and use case

                    Thanks .
                    • 7. Re: Loading and Unloading of FXML components at runtime
                      daniel
                      Hi,

                      Yes, it is possible to access any object loaded by the FXML loader from within your application.
                      For each FXML file, you can write a corresponding Java controller class - in which any object loaded from FXML can be injected.

                      Let's say that your FXML UI contains a button, and you need to access this button from within your code.

                      It works this way:

                      Sample.fxml:
                      <AnchorPane ... fx:controller="my.sample.SampleController">
                          ....
                           <Button fx:id="okButton" ..../>
                      </AnchorPane>
                      In the FXML above - the controller class is specified by the fx:controller attribute in the FXML root object. The FXMLLoader will try to load and create an instance of my.sample.SampleController when it will load your FXML file at runtime. You can specify a controller class name from within SceneBuilder, by selecting the root node in the Hierarchy Panel (left hand side) and opening the 'Code' section of the inspector.

                      In the FXML above, the Button element as an fx:id attribute - whose value is "okButton". This means that the FXMLLoader will look for a field named "okButton" in the my.sample.SampleController class, and will assign the loaded button to that variable. The field must have the exact same name than the fx:id value - and be tagged with an @FXML annotation, as shown below. You can assign fx:id to objects from within SceneBuilder: look for a field named fx:id in the Properties section of the inspector.

                      SampleController.java (the class you will write to add logic to your FXML)
                      package my.sample;
                      ...
                      public class SampleController implements Initializable {
                          @FXML //  fx:id="okButton"
                          private Button okButton; // Value will be injected by FXMLLoader
                      
                          @Override // This method is called by the FXMLLoader when initialization is complete
                          public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
                              // initialize your logic here: all @FXML variables will have been injected
                          }
                      }
                      I suggest you take a look at the JavaFX SceneBuilder samples there (http://www.oracle.com/technetwork/java/javafx/downloads/devpreview-1429449.html)
                      and more particularly first at the HelloWorld sample - and then at the Login sample.

                      There is also a more detailed tutorial here:
                      http://docs.oracle.com/javafx/scenebuilder/1/get_started/jsbpub-get_started.htm

                      Hope this helps,

                      -- daniel
                      • 8. Re: Loading and Unloading of FXML components at runtime
                        937937
                        Thanks a lot.
                        gonna work all day long at it.
                        • 9. Re: Loading and Unloading of FXML components at runtime
                          937937
                          thanks a lot.
                          i am gonna work with a controller file for today and tomorrow..so i can get even with my work and once thats done
                          i want you to help me out with accessing the structure though this method.
                          i know its not DOM "i am very used to i from JavaScript" but if you can go around the hierarchy through functions
                          it would be very useful to know how.
                          i will post my files in a few days then.
                          and again thanks.
                          • 10. Re: Loading and Unloading of FXML components at runtime
                            daniel
                            Hi,

                            You can walk through most of the hierarchy using Parent.getUnmodifiableChildren() - provided that you wait until the skins have been initialized. The drawback is that you will see all nodes - including the nodes that are part of the skin.

                            You can also use Node.lookup("#<id>") / Node.lookupAll("#<id>") provided that you have set the id in FXML (as in id="somestring") and that you know for which id to look for.

                            Hope this helps,

                            -- daniel