0

I'm trying to click a button in my GUI and switch to a separate scene within the same stage. This seems simple except that I get a NullPointerException in my Controller class when I click the button. The button is written in the FXML with fx:id="settings" and onAction="#handleSettings". The handleSettings method is located in the controller.

I'm trying to import the primaryStage from Main.java into Controller.java by writing public Stage primaryStage; at the top, but I'm clearly missing something. The GUI launches fine but the error occurs when clicking Settings button. The full code is below along with the error. The error is pointing to this line: primaryStage.setScene(sceneSettings);

Do I need to use get/set for primaryStage somehow? Clearly I'm at level 1 in skills. Anything helps, thanks.

Main.java

import ...

public class Main extends Application {
          public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        Scene scene = new Scene(root, 450, 580);
        scene.getStylesheets().add("styleMain.css");
        primaryStage.initStyle(StageStyle.UTILITY);
        primaryStage.setTitle("Scene 1");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Controller.java

import ...

public class Controller{
    Scene sceneSettings;
    public Stage primaryStage;

    public void handleFieldData(){
        System.out.println("field data");
    }

    public void handleComments(){
        System.out.println("comments");
    }

    @FXML
    public void handleSettings() throws IOException {

        Button button2 = new Button("settings");
        StackPane layout = new StackPane();
        layout.getChildren().add(button2);
        sceneSettings = new Scene(layout, 450, 580);
        primaryStage.setScene(sceneSettings);
        primaryStage.setTitle("Settings Menu");
        primaryStage.show();
    }
}

sample.fxml

<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1"
          fx:controller="Controller">

      <columnConstraints>
    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
  </columnConstraints>
  <rowConstraints>
    <RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
    <RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
  </rowConstraints>
   <padding>
      <Insets bottom="10.0" left="70.0" right="70.0" top="10.0" />
   </padding>
   <children>
      <Button fx:id="comments" mnemonicParsing="false" onAction="#handleComments" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
         <padding>
             <Insets bottom="15.0" left="50.0" right="50.0" top="90.0" />
         </padding>
      </Button>
       <Button fx:id="settings" mnemonicParsing="false" onAction="#handleSettings" text="Settings" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
           <padding>
               <Insets bottom="15.0" left="30.0" right="30.0" top="15.0" />
           </padding>
       </Button>
      <Label text="Comments" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="TOP" />
   </children>
</GridPane>

Error:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8411)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$355(GlassViewEventHandler.java:388)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
    ... 48 more
Caused by: java.lang.NullPointerException
    at Controller.handleSettings(Controller.java:38)
    ... 58 more
Mathomatic
  • 899
  • 1
  • 13
  • 38
  • Looks like you don't have a pointer to the primarystage. When you load the controller you should set the primary stage either in the constructor or with a setter. – JeramyRR Nov 13 '15 at 21:29

1 Answers1

1

When you load your controller you will need to pass it a reference to the primary stage.

public class Controller{
    Scene sceneSettings;
    public Stage primaryStage;

...
public void setPrimaryStage(Stage stage) {
  this.primaryStage = stage;
}
...

Main

 @Override
    public void start(Stage primaryStage) throws Exception{
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("sample.fxml"));
        Parent root = loader.load();
        loader.getController().setPrimaryStage(primaryStage);

        Scene scene = new Scene(root, 450, 580);
        scene.getStylesheets().add("styleMain.css");
        primaryStage.initStyle(StageStyle.UTILITY);
        primaryStage.setTitle("Scene 1");
        primaryStage.setScene(scene);
        primaryStage.show();
  ...
JeramyRR
  • 4,273
  • 3
  • 20
  • 20
  • Thank you Jeramy, that solved it. However, I had to tweak your answer for it to work. Care to explain why? If I simply used `loader.getController().setPrimaryStage(primaryStage);` then it said "cannot resolve method".. but if I use `( (Controller) loader.getController() ).setPrimaryStage(primaryStage);` it works fine. Controller is the controller class. Thanks again – Mathomatic Nov 13 '15 at 22:30
  • Why would you do any of this anyway? Why not just do `Stage primaryStage = (Stage) settings.getScene().getWindow()` instead of all the redundant wiring between the application class and the controller class? – James_D Nov 13 '15 at 22:52
  • Do that where exactly? And what would that replace? Redundancies are preferably avoided I agree. – Mathomatic Nov 14 '15 at 01:54
  • James_D's suggestion would work as well. There are always multiple ways to do the same thing. Some ways are better than others. James' way removes the dependency my suggestion created and would be preferable. – JeramyRR Nov 15 '15 at 20:38