<fx:root>
provides a solution to the issue of defining a reusable component with FXML.
As an example, imagine you want to define a simple custom component consisting of a TextField
and Button
contained in an HBox
. You need this to be represented by a subclass of Node
, so you can write code like
VBox vbox = new VBox(); vbox.getChildren().add(new MyComponent());
The issue is you need a Java class which is a subclass of Node
, as well as the FXML. In pure Java (no FXML), you could do this with:
public class MyComponent extends HBox { private TextField textField ; private Button button ; public MyComponent() { textField = new TextField(); button = new Button(); this.getChildren().addAll(textField, button); } }
Using FXML to define the custom component without the <fx:root>
element presents a problem, because you need the FXML to be some kind of node, and then another node instance to represent the class wrapping it:
<HBox> <TextField fx:id="textField"/> <Button fx:id="button" /> </HBox>
and
public class MyComponent extends HBox { @FXML private TextField textField ; @FXML private Button button ; public MyComponent() { try { FXMLLoader loader = new FXMLLoader(getClass().getResource("MyComponent.fxml")); loader.setController(this); HBox hbox = loader.load(); this.getChildren().add(hbox); } catch (IOException exc) { // handle exception } } }
This results in MyComponent consisting of an HBox wrapping an HBox wrapping the TextField and Button. The additional, redundant HBox is a result of needing one Node for the FXML root and one Node to represent the component.
<fx:root>
gives a mechanism to create the Node as the component (the Java class) and then to instruct the FXML file to use that node as its root:
<fx:root type="javafx.scene.layout.HBox"> <TextField fx:id="textField" /> <Button fx:id="button" /> </fx:root>
and
public class MyComponent extends HBox { @FXML private TextField textField ; @FXML private Button button ; public MyComponent() { try { FXMLLoader loader = new FXMLLoader(getClass().getResource("MyComponent.fxml")); loader.setController(this); loader.setRoot(this); loader.load(); } catch (IOException exc) { // handle exception } } }
Now MyComponent
has the same structure as the original all-Java version, an HBox
containing a TextField
and a Button
. You can’t do this using FXML without the <fx:root>
element.