0

I am struggling to learn nested controllers in Java FX. I've read through some tutorials (most notably this one: https://www.youtube.com/watch?v=osIRfgHTfyg) and everything in my code looks okay... except my OuterController doesn't seem to have a reference to the InnerController.

To explain: I have an OuterController.java which controls the outer skeleton of my app. To keep this post brief, OuterController has a TabPane; the code of InnerController is meant to be the content of Tab1. (I've omitted the TabPane controller code for brevity.) "Tab1" has a single Button called "testMe".

Here's the Outer Controller. I'm certain the problem is in the "private @FXML InnerController myInnerController" line. When the code runs, the "myInnerController" variable is null:

// OuterController.java

package controllers;

import javafx.fxml.FXML;

public class OuterController{

    private  @FXML  InnerController  myInnerController;    // << doesn't pick up the InnerController
    Stage stage;

    public void start(Stage stage) throws Exception{
        this.stage = stage;
        if(myInnerController == null){
            System.out.println("Gack!  InnerController is null!");
        }
    }
}

Here's the FXML for OuterController:

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

<?import javafx.scene.control....lots of import statements here....?>

<AnchorPane fx:id="AnchorPaneRoot" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="781.0" prefWidth="1356.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.OuterController">
   <children>
      <TabPane fx:id="myTabPane" layoutX="14.0" layoutY="457.0" prefHeight="314.0" prefWidth="739.0" tabClosingPolicy="UNAVAILABLE">
        <tabs>
            <Tab text="Tab1">
               <content>
                  <!--  include statement ties me to the InnerController  -->
                  <fx:include fx:id="AnchorPaneInnerController" source="InnerController.fxml" />
               </content></Tab>
        </tabs>
      </TabPane>
   </children>
</AnchorPane>

Here's the Inner Controller:

// InnerController.java

package controllers;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class InnerController {

    @FXML  AnchorPane  AnchorPaneInnerController;   // not sure I need this
    @FXML  Button      testMe;

    private @FXML   void initialize(){
        System.out.println("Inner Controller started...!");

        testMe.setOnAction(event -> {
            System.out.println("testMe pressed!!!");
        });
    }
}

And for the sake of being complete, here's the FXML for the Inner Controller:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane fx:id="AnchorPaneInnerController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="246.0" prefWidth="740.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.InnerController.java">
   <children>
      <Button fx:id="testMe" layoutX="211.0" layoutY="108.0" mnemonicParsing="false" text="Test Me" />
   </children>
</AnchorPane>

The code compiles and runs; there are no error codes or warnings. This is the output, assuming you click "testMe" three times:

Inner Controller started...!
Gack!  InnerController is null!
testMe pressed!!!
testMe pressed!!!
testMe pressed!!!

You see the problem. InnerController runs just fine, and as a user I can click "testMe" to my heart's content. But why doesn't the OuterController's "myInnerController" variable "point to" the instantiation of the InnerController? Is this a strict naming convention thing?

Another question... I tend to think of the "@FXML thingee variableName" statement as an instruction to the Java controller file to mean "Look in your FXML file, you'll see an object of type 'thingee' with name 'variableName'; just load that as an instantiated object." If that's the case, then my "private @FXML InnerController myInnerController;" may be tripping up because the variables names "myInnerController" and "AnchorPaneInnerController" from the InnerController FXML don't match...? Not sure what else could be the problem here.

Any advice and/or criticism is wildly appreciated, thank you.

Pete
  • 1,511
  • 2
  • 26
  • 49

0 Answers0