user3223892
user3223892

Reputation: 13

Java FX Getting a custom control working using multiple FXML files

I am trying to work with custom controls in JavaFX and multiple FXML files. I create a custom control:

public class PetListGUIManager extends BorderPane
{
    @FXML ListView<String> petList;

    private PetManager pm;

    public PetListGUIManager() 
    {
        try
        {
           FXMLLoader loader = new  FXMLLoader( getClass().getResource("PetList.fxml"));

           loader.setRoot( this );
           loader.setController( this );

           loader.load();

        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        pm = new PetManager();

        ObservableList<String> items = FXCollections.observableArrayList( pm.getDisplayablePets() );

        petList.setItems( items );
    }

    @FXML
    public void handleButtonAction( ActionEvent event )
    {
        Button b = (Button) event.getSource();
        b.setText("Clicked!");
    }
}

Using this FXML file:

<fx:root type="javafx.scene.layout.BorderPane" xmlns:fx="http://javafx.com/fxml">
  <bottom>
    <Button onAction="#handleButtonAction" text="Click Me!" />
  </bottom>
  <center>
    <ListView fx:id="petList" prefHeight="200.0" prefWidth="200.0" />
  </center>
</fx:root>

Then I use this other main program:

public class TestMain extends Application
{
    PetListGUIManager pm;
    @FXML FlowPane mainPane;

    @Override
    public void start(Stage stage) throws Exception
    {

        Parent root = FXMLLoader
                .load(getClass().getResource("Main.fxml"));

        Scene scene = new Scene(root);

        stage.setTitle("Test Main");
        stage.setScene(scene);
        stage.show();


       pm = new PetListGUIManager();

    }
    /**
     * Purpose:
     * @param args
     */
    public static void main(String[] args)
    {
        Application.launch( args );
    }

    @FXML
    public void doSomething( ActionEvent ae )
    {
        System.out.println( "In do something: " + mainPane );
        ObservableList<Node> children = mainPane.getChildren( );
        System.out.println( "Children are " + children );
        children.add( pm );

    }
}

Which uses this FXML file:

<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="TestMain">
  <children>
    <FlowPane fx:id="mainPane" prefHeight="400.0" prefWidth="600.0" >
    <Button text="Click here to start" onAction="#doSomething"/>
    </FlowPane>
  </children>
</AnchorPane>

When I click the button in the main window - which should load the custom control I get a java.lang.reflect.InvocationTargetException exception caused by: java.lang.NullPointerException: Children: child node is null: parent = FlowPane[id=mainPane]

What am I missing here?

Second question: You may notice I arbitrarily added a button to my main window so when it was clicked I could then load my BorderPane custom control class. Ideally I would like to do this directly in the start method of TestMain but mainPane is null in the start method - when does it become not null?

Upvotes: 1

Views: 2483

Answers (1)

jewelsea
jewelsea

Reputation: 159576

You should never make your main Application class a controller - it's just too confusing and fraught with errors such as you have encountered.

What is happening is that when you load Main.fxml, the FXMLLoader will create a new instance of the Application class. When you click on the button defined in the main fxml UI, the doSomething method will be invoked on that new TestMain object, not the original TestMain object that was created when your application was launched.

The solution is to create a MainController.java which functions as the controller for the Main.fxml GUI (similar to what you have already done with PetListGUIManager) and remove any of the @FXML related notation completely from your main application class.

Upvotes: 4

Related Questions