3

I'm receiving the following exception trying to call setText() on my annotated label, from the start() method. I've seen a similar question, but the reason why it didn't work for that person is because his label isn't annotated, while mine is.

java.lang.NullPointerException
at io.github.blubdalegend.openbravery.OpenBravery.applyBuild(OpenBravery.java:67)
at io.github.blubdalegend.openbravery.OpenBravery.start(OpenBravery.java:58)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
at java.lang.Thread.run(Unknown Source)

This is my main class:

public class OpenBravery extends Application implements Initializable {

    @FXML
    private Button rerollButton;

    @FXML
    private Label champL;

    public static void main(String[] args) {
        System.out.println("Downloading files from Dropbox...");
        updateFiles();
        System.out.println("Download complete!");
        Application.launch(OpenBravery.class, (java.lang.String[]) null);

    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        rerollButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {

            }
        });
    }

    private static void updateFiles() {
        FileManager fm = new FileManager();
        fm.downloadChamps();
        fm.downloadItems();
    }

    @Override
    public void start(Stage stage) {
        try {
            Pane pane = (Pane) FXMLLoader.load(OpenBravery.class.getResource("build.fxml"));
            Scene scene = new Scene(pane);
            stage.setScene(scene);
            stage.setTitle("OpenBravery");
            stage.setResizable(false);
            applyBuild();
            stage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void applyBuild() {
        Build build = new Build();
        champL.setText(build.getChamp());
    }

}

My build.fxml starts like this:

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

<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
    minWidth="-Infinity" prefHeight="297.0" prefWidth="362.0"
    xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="io.github.blubdalegend.openbravery.OpenBravery">
    <children>
        <Label layoutX="14.0" layoutY="14.0" text="Your build:">
            <font>
                <Font size="32.0" />
            </font>
        </Label>
        <Label fx:id="champL" layoutX="14.0" layoutY="61.0" prefHeight="32.0"
            prefWidth="288.0" text="Label">
            <font>
                <Font size="17.0" />
            </font>
        </Label>

So what did I miss here?

James_D
  • 201,275
  • 16
  • 291
  • 322
Blub
  • 43
  • 6
  • `champL`is probably still null? Might have something to do with initialisation order. – ByteWelder Apr 02 '16 at 15:19
  • I doubt it doesn't find build.fxml because when I run without the setText() line it just creates the window (although obviously without settting the text of the label). Not sure about initialisation order. – Blub Apr 02 '16 at 15:20
  • Weird, won't `initialize()` be run before `applyBuild()`? If so, `rerollButton` is clearly not null by then. – Dan Getz Apr 02 '16 at 15:44
  • @DanGetz Yes, but `initialize()` is called on the controller, not on the `Application` instance. – James_D Apr 02 '16 at 19:17

1 Answers1

2

You're not calling applyBuild() on the controller, you're calling it on the application instance. The @FXML-annotated fields are only initialized in the controller. It's much better to make the controller and the application separate classes, to avoid this kind of confusion. It is also bad practice to create two instances of the Application class.

Write a separate class as the controller: do not use the Application subclass as the controller class.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Oh wow, so there ends up being two instances of this class? Where is the second created? – Dan Getz Apr 02 '16 at 19:19
  • The second one is created by the `FXMLLoader`, because the FXML file specifies this class as the controller class. – James_D Apr 02 '16 at 19:19
  • Can one access this second Controller object? e.g. to pass objects to the Controller – Michael Krejci Apr 02 '16 at 19:28
  • 1
    @MichaelKrejci Yes, of course: see http://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml/14190310#14190310 But I emphasize that each FXML file should have a dedicated `Controller` class, and shouldn't use the `Application` class. – James_D Apr 02 '16 at 19:30
  • Yep I got it working in a single class but I ended up making a seperate controller class. It's a lot more clean and readable that way. – Blub Apr 14 '16 at 18:23