0

I have a class which calls a super constructor. The super class loads an FXML wrapper layout, and then another FXML layout as a child of an element within the wrapper, as so:

// Reference 'outer' FXML
URL outer_url = getClass().getResource("/main/resources/fxml/RootNode.fxml");
FXMLLoader outer_loader = new FXMLLoader(outer_url);
outer_loader.setRoot(this);
outer_loader.setController(this);

// Reference 'inner' FXML
URL inner_url = getClass().getResource(fxml_path);
FXMLLoader inner_loader = new FXMLLoader(inner_url);

try {
    outer_loader.load();

    /* The root of inner_loader is a component of outer_loader FXML,
     * thus outer_loader.load() must be called first. */
    inner_loader.setRoot(outer_loader.getNamespace().get("vbox_center"));
    inner_loader.setController(controller);
    inner_loader.load();
} catch (IOException e) {
    e.printStackTrace();
}

I need the class to be the controller of inner_loader. Is this possible? I tried passing a reference to the class through the super constructor, however I cannot reference 'this' before the super constructor is called.

Any ideas? Thanks in advance.

EDIT: I also tried specifying the controller directly through the inner FXML file, however this caused problems.

EDIT 2: I forgot to specify, the superclass which loads the two FXML layouts is inherited by multiple nodes, which is why I cannot just create an instance of the Controller and pass it directly to inner_loader. I need to (somehow) pass an instance reference to the superclass and use that as the controller.

haz
  • 2,034
  • 4
  • 28
  • 52
  • Duplicate of: [JavaFx Nested Controllers (FXML )](http://stackoverflow.com/questions/12543487/javafx-nested-controllers-fxml-include)? – jewelsea Dec 08 '16 at 02:15
  • I did see that question - the difference with mine is that the superclass that loads the FXML is inherited by multiple different nodes, and as such an instance reference needs to be passed to it - I can't just create a new one each time. – haz Dec 08 '16 at 04:31
  • "I need to pass an instance reference to the superclass": I don't really understand what you mean by that statement. The current object (`this`) is of course an instance of its own class, and consequently also of the superclass. You could pass `this`, which would be strange because you would be using the same object as the controller for two different FXML files, and the `initialize()` method (if there is one) would be called twice. – James_D Dec 08 '16 at 13:10
  • Also note there should be no need to lookup `vbox_center` via the loader's namespace. Since `this` is the controller, it should be injected via `@FXML` at that point. – James_D Dec 08 '16 at 13:12

1 Answers1

2

It's not entirely clear what you're trying to do, but it looks like you are trying to use inheritance and FXML-based custom components to create a template with specializations.

This is possible. You can load the FXML in the usual way in the constructor. Because each constructor calls its superclass constructor, the superclass FXML will be loaded before the subclass FXML.

Project layout:

enter image description here

Template:

Template.fxml:

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

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.VBox?>

<fx:root xmlns:fx="http://javafx.com/fxml/1" type="BorderPane">
    <top>
        <MenuBar>
            <menus>
                <Menu text="File">
                    <items>
                        <MenuItem text="Quit" onAction="#quit"/>
                    </items>
                </Menu>
            </menus>
        </MenuBar>
    </top>

    <center>
        <VBox fx:id="vboxCenter"/>
    </center>

</fx:root>

Component (Template.java):

package template;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;

public class Template extends BorderPane {

    @FXML
    private VBox vboxCenter ;

    public Template() throws IOException {
        FXMLLoader loader = new FXMLLoader(Template.class.getResource("Template.fxml"));
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    }

    protected final VBox getCenterContentHolder() {
        return vboxCenter ;
    }

    @FXML
    private void quit() {
        vboxCenter.getScene().getWindow().hide();
    }
}

Specialization:

Home.fxml:

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

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Font?>

<fx:root xmlns:fx="http://javafx.com/fxml/1" type="VBox" alignment="CENTER">
    <Label fx:id="welcomeLabel" text="Welcome" />
</fx:root>

Component (Home.java):

package home;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.text.Font;
import template.Template;

public class Home extends Template {

    @FXML
    private Label welcomeLabel ;

    public Home() throws IOException {

        // not necessary to explicitly call super(), it is called by default
        // this call loads the template defined by the superclass
        super();

        FXMLLoader loader = new FXMLLoader(Home.class.getResource("Home.fxml"));
        loader.setRoot(getCenterContentHolder());
        loader.setController(this);

        loader.load();

        welcomeLabel.setFont(Font.font("Arial", 48));
    }
}

Application:

package application;

import java.io.IOException;

import home.Home;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        Scene scene = new Scene(new Home(), 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

enter image description here

James_D
  • 201,275
  • 16
  • 291
  • 322