Rob
Rob

Reputation: 2510

javafx fxml is null outside initialize()

In this code:

public class ESM extends Application {

private Stage primaryStage;

@FXML 
private ToolBar mainToolBar;


@Override
public void start(final Stage stage) throws Exception {
    try{
        this.primaryStage = stage;
        Parent root = FXMLLoader.load(getClass().getResource("/nz/co/great_ape/esm3/main_window.fxml"));

        Scene scene = new Scene(root, 800, 700);            
        //  Setup main stage to be full screen, no min or max buttons.
        //  TODO:  How will this handle multiple screens?  Apparently not well :-(
        Screen screen = Screen.getPrimary();
        Rectangle2D bounds = screen.getVisualBounds();
        primaryStage.setX(bounds.getMinX());
        primaryStage.setY(bounds.getMinY());
        primaryStage.setWidth(bounds.getWidth());
        primaryStage.setHeight(bounds.getHeight());
        primaryStage.initStyle(StageStyle.UNDECORATED); 
        primaryStage.setTitle("ESM three");
        primaryStage.setScene(scene);
        primaryStage.show();
        System.out.println("This will fail because mainToolBar is null.  Why?");
        assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";
    } catch (Exception ex) {
        Logger.getLogger(ESM.class.getName()).log(Level.SEVERE, null, ex);
    }           
}



/**
 * Use initialize() to setup widgets from scenebuilder files, it is
 * called by FXMLLoader.
 */
@FXML
public void initialize(){
    System.out.println("initialize() But when here all is good and mainToolBar is a ToolBar.");
    assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";     
}

/**
 * The main() method is ignored in correctly deployed JavaFX application.
 * main() serves only as fallback in case the application can not be
 * launched through deployment artifacts, e.g., in IDEs with limited FX
 * support. 
 *
 * @param args The command line arguments.
 */
public static void main(String[] args) {
    launch(args);

}

}

I cant see why it's got a value in the initialise() but in the start it's null. When debuging it's clear that initiialize() is called by FXMLLOader from inside start()

I was going to post the fxml but it does not seem to work as nothig shows in the preview. Any way, it's a real basic file, a BordePane and a ToolBar.

Any clues?

Upvotes: 1

Views: 7441

Answers (1)

jewelsea
jewelsea

Reputation: 159281

Always create a new class for your FXML Controller, don't try to reuse an Application class as a Controller class.

An Application instance is created by the JavaFX application launcher.

A Controller instance is created by the JavaFX FXML loader.

You don't supply the FXML that you use, but I am going to guess that it has it's Controller class erroneously set to be your application class.

So in your code, what happens is:

  1. An instance of the application is created when you run the program (via the launch method).
  2. In your application start method, you invoke the FXMLLoader, which instantiates a new Controller (in your case a new instance of the application class).
  3. The FXMLLoader injects the @FXML tagged members into the new application object and invokes the initialize on the new object.
  4. But your original application object doesn't know anything about the new application object and hence doesn't have a menu bar set in it.

In summary, to fix this:

  1. Create a new controller class that the FXMLLoader can instantiate.
  2. Change your fxml to reference the new controller class.

If your application really needs to reference the controller, then you can use the getController method on the FXML loader and in your controller class provide public methods to retrieve required elements (like your menu bar). See my answer to Passing Parameters JavaFX FXML for some more examples of this method.

import javafx.scene.control.ToolBar;
import javafx.fxml.FXML;

public class ESMController {
  @FXML 
  private ToolBar mainToolBar;
  public  ToolBar getMainToolBar() { return mainToolBar; }

  @FXML
  public void initialize(){
    assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";     
  }
}

Upvotes: 7

Related Questions