Hello folks,
Today I would like to blog about the FXML define
and include
tag which can be very useful for those who are very keen to use FXML in their application. The FXML is an XML file which is loaded by javafx using FXMLLoader
. It’s all loaded at the runtime and it’s really fast to load and easy to learn too. The previous blog about the FXML as Flexible XML is just a basic about FXML . Today in this blog here you will learn about how to include FXML files in your main FXML file.
I’m talking about the <fx:include>
tag of the FXML.
Let’s see the basic flow of how the
are loaded. Let’s assume there are two FXML <fx:include>
Main.fxml
and Child.fxml
Here in the above image you can see the Child.fxml is called inside Main.fxml embeded byΒ
Now you need to know that the <fx:define>
are used for defining any variables or any instances inside FXML.<fx:define>
Let’s see things in real . We are going to make one simple Tab based application which simply get’s it’s tab content from different FXML files. Firstly we’ll make Main.fxml which contains the TabPane.
Main.fxml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
" ]<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.shape.*?> <?import javafx.scene.effect.*?> <?import fxmlstuff.Main?> <Main xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlstuff.Main" > <fx:define> <fx:include source="Home.fxml" fx:id="homeContent" /> <fx:include source="About.fxml" fx:id="aboutContent" /> </fx:define> <center> <TabPane fx:id="tabpane" translateY="5" translateX="5" > <tabs> <Tab text="HOME" fx:id="homeTab" content="$homeContent" closable="false" /> <Tab text="ABOUT" fx:id="aboutTab" content="$aboutContent" closable="false"/> </tabs> </TabPane> </center> </Main> |
You can see the highlighted lines of which helps to load the content of
Home.fxml
and About.fxml
in the Main.fxml
. Also we ‘ve added fx:id
property for making instances available of Home and About class. Now let’s see the FXController
class of Main.fxml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package fxmlstuff; import java.net.URL; import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.layout.BorderPane; /** * @author Narayan */ public class Main extends BorderPane implements Initializable{ @FXML private Home homeContent; @FXML private About aboutContent; @Override public void initialize(URL url, ResourceBundle rb) { } } |
Here in the controller we have just made the instance of Home and About class with respective to their fx:id
Home.fxml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import fxmlstuff.Home?> <Home id="homeContent" xmlns:fx="http://javafx.com/fxml" spacing="10" translateY="40" translateX="20" fx:controller="fxmlstuff.Home" > <children> <Label text="Add New Dock of Home" /> <Button text="Add !" onAction="#handleAction" /> </children> </Home> |
Home.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package fxmlstuff; import java.net.URL; import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.layout.VBox; /** * @author Narayan */ public class Home extends VBox implements Initializable{ @FXML private void handleAction(ActionEvent event) { } @Override public void initialize(URL url, ResourceBundle rb) { } } |
About.fxml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import fxmlstuff.About?> <About id="aboutContent" xmlns:fx="http://javafx.com/fxml" spacing="10" translateY="40" translateX="20" fx:controller="fxmlstuff.About"> <children> <Label text="Add New Dock of About" /> <Button text="Add !" onAction="#handleButtonAction" /> </children> </About> |
About.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package fxmlstuff; import java.net.URL; import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.layout.VBox; /** * @author Narayan */ public class About extends VBox implements Initializable { @FXML private void handleButtonAction(ActionEvent event) { } @Override public void initialize(URL url, ResourceBundle rb) { } } |
Now you have finally finished the FXML stuffs of adding components inside the FXML. You can now just create one FXML Executor class which helps to execute and load your FXML using FXMLLoader.load() . I’m going to use the FXMLTest class as the executor of the FXML files in Stage.
FXMLTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
" ]package fxmlstuff; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; /** * * @author Narayan */ public class FXMLTest extends Application{ public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("Main.fxml")); Scene scene = new Scene(root,800,600); stage.setTitle("FXML Test"); stage.setScene(scene); stage.show(); } } |
The preview of this javafx class will be something like this.
The continue of this blog will be posted in coming week. The next blog post will contain the extended part of this application where you can take control over the event triggered from About.fxml and Home.fxml FXML component to the Main fxml.
That’s it for today. You can now easily include the fxml file inside the FXML file using things like this.
Have a πΒ good day and fell free on commenting your views about this post.
Thanks
Pingback: Java desktop links of the week, January 30 | Jonathan Giles
One caution: you’re doing something that doesn’t do what it looks like it’s doing — you’re specifying that the controller for your fxml tree is the same as the root of the tree. In fact, they’re not. The controller for Main.fxml is a *different instance* of Main than the root of its tree (and ditto for your other two classes).
That doesn’t really matter for your simple example, but it will bite you if you decide to add any interesting functionality to any of your classes. Suppose you define setInterestingFeature in your Main class to do something to the display, and in your start method, you try to call it on the instance of Main that you created there (it’s your root variable). However, *that* instance of Main is not the controller, and thus does not have any access to its @FXML-annotated fields (e.g., aboutContent), so it cannot do anything at all to the display.
If you changed the root element of your fxml files to be BorderPane or VBox (as appropriate), and made your controller classes not extend BorderPane or VBox, the example should work identically, but would not suffer this confusion. And, of course, your controller classes wouldn’t carry any of the baggage that comes with subclassing a display node.
This isn’t explained at all well in the FXML documentation. If you come from the WPF world, you can easily be misled by thinking of FXML as XAML, an analogy that only goes so far. I’ve been spending the last week or so exploring reasonable alternative design patterns to use with FXML.
Hi,
The Main fxml have all instances access like About, Home fx controller
Thr setFeature function as u told in main class can be called by other instances only if its the static function. You cannot call the function directly by fxml without static.
I think you are also talking about this same thing
One more thing The next coming blog will contain how will the fml does conversation with each other.
Thanks for your comment.
π
No, I wasn’t talking about using static methods, which wouldn’t make any sense except for controls that only occur once in your application, and even then it would be kludgy.
I look forward to seeing your approach to communication between controls.
I am with bill. I am doing (trying to) do exactly what you have said. Each tab has its own FXML file. However not sure how to get changes from ui components on one tab to affect another?
Finally a comprehensive sample about fx:include!
I was searching for it since a while. Maybe it needs some refinement in root class issue like above, but it definitely works. Official FXML introduction description did not help me much to realize this fx:include feature.
So thanks a lot Narayan!
Thanks for the blog. I have been trying to do the same in FXML. I can’t find good references.
@Duane
You are welcome !!
Thanks for the blog…. π
How can I include for loop in FXML ? Is it possible ?
I guess currently the programming logic like if, for, while is not possible inside the FXML. But you manipulate it from the controller class.
What’s up, of course this piece of writing is genuinely nice and I have learned lot of things from it regarding blogging.
thanks.
hey bro i want to know how to communicate to child of a main controller
for example i have mainController and it have two child Controller
i want to call method of child 2 from child 1,if that is posible, please give me example
thanks.
Hi Royel,
This thread might be useful. https://forums.oracle.com/message/10900157
Thanks
Very clear and helpful. It filled on quite a few gaps. I used -s on another project. So that time we reused the same header and footer instance in different pages.
What I’d like to see, is a patter for reuse of a block like an address block on the same page (via fx:include)? Something like those blocks with postal address, billing address and delivery address.
If you or anyone has seen a working example like that, I’d love to hear about it.
Hi again,
I have been playing with this example. Each controller has ‘defined’ a new element type; like AngularJS. That’s nice because it creates a more semantic UI mark-up.
Unfortunately the Scene Builder tool can’t be used with these custom elements.
There’s also a bit of a break with MVC convention. Because the controller for an element is normally called “AboutController”. Does the @FXML directive accept a “named as” parameter?
It is a pity about the Scene Builder. I suppose one may design a component as a write-once exercise, then name it.
It would be good to prevail on the JavaFX /Scene Builder project for more support for this “Flexible FXML” π
Hello sir,
please help, I’ve got an error.
“javafx.fxml.LoadException: Main is not a valid type.
/C:/Users/Android/workspace/MultipleScenes/Sample/bin/application/Main.fxml”
I have a question. If I want to bring up the About tab by clicking the button in the Home.java(controller). What do I need to do to make that work?
Hi David,
I would recommend for using the Master Template where you will have one Master Layout like AnchorPane, BorderPane and swap the children from that master layout when you need to show different page. Also one more thing you need to think about sharing the instance of that masterLayout so that it is accessible in all scope of sub-controller . The structure should be like this.
- Stage
- Scene
- MasterLayoutController [extends BorderLayout]
- HomeController[ must have masterLayout instance]
- AboutController[ must have masterLayout instance ]
Now your MasterLayoutController must have function like masterLayout.changePage(instance of Parent i.e. loaded FXML Home.fxml or about.fxml ). And you swap them by removing the node and adding new node in children list.
Congratulations, great tutorial. I followed, and works very well. But I have a question, and if I want to upgrade a home field for the About tab? All my attempts give nullpointexception. Thank you
Hello,
please help me. How can I pass parameters (object) to child view and child controller?