0

I am currently testing out some JavaFX code to get more into this language and I wanted to have a Window with a button called "Iconify" which does minimize the window when clicked. Here you can see how it looks like

I am working with FXML (Scene Builder) and so I usually do not initialize or declare Nods (Components) in my class. When I do all the stuff in the start(Stage primaryStage) method, minimizing does work, when I use this code: buttonIconify.setOnAction(event -> stage.setIconified(true)); So, actually, when I try to use .setIconified(true) in my start Method is works fine. But when I try to use it from another method like public void handleButtonAction(ActionEvent event) it doesn't for some reason.

Exception:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1787)
    at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8863)
    at javafx.controls/javafx.scene.control.Button.fire(Button.java:200)
    at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
    at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3876)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1300(Scene.java:3604)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1874)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2613)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
    at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1782)
    ... 47 more
Caused by: java.lang.NullPointerException
    at app.Main.handleButtonAction(Main.java:39)
    ... 58 more

Gigantic...

I have no idea, why it doesn't work outside the

@Override public void start(Stage primaryStage) throws Exception

method.

My full class code:

package app;

import javafx.application.*;
import javafx.event.*;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.stage.*;

public class Main extends Application {

    private Stage stage;

    @FXML
    private Button buttonIconify;
    @FXML
    private Button buttonExit;

    @Override
    public void start(Stage primaryStage) throws Exception {
        stage = primaryStage;
        stage.setTitle("JavaFX Test Range");

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

        Scene scene = new Scene(root);
        // scene.getStylesheets().add(getClass().getResource("Stylesheet.css").toExternalForm());
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @FXML
    public void handleButtonAction(ActionEvent event) {
        if (event.getSource() == buttonIconify) {
            stage.setIconified(true);
        }

        if (event.getSource() == buttonExit) {
            Platform.exit();
        }
    }
}

FXML:

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

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

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.Main">
    <HBox alignment="CENTER" prefHeight="400.0" prefWidth="600.0" spacing="30.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <Button fx:id="buttonIconify" mnemonicParsing="false" onAction="#handleButtonAction" prefHeight="70.0" prefWidth="170.0" text="Iconify" />
        <Button fx:id="buttonExit" mnemonicParsing="false" onAction="#handleButtonAction" prefHeight="70.0" prefWidth="170.0" text="Exit" />
    </HBox>
</AnchorPane>
SedJ601
  • 12,173
  • 3
  • 41
  • 59
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – MMAdams Mar 09 '18 at 15:00
  • @MMAdams Doesn't really explain why `stage` is null in this case. – James_D Mar 09 '18 at 15:01
  • 1
    @James_D, I realized that after I had flagged, whoops! I'll be more careful next time. – MMAdams Mar 09 '18 at 15:02

3 Answers3

1

Your handler method handleButtonAction is called on the controller. You only initialize the field stage in the instance of the Application class that is created when you call launch(): it is never initialized in the controller. Consequently when you try to call stage.setIconified() in the controller, you get a null pointer exception.

It is always a mistake to use the Application class as the class for the controller, as it leads to confusion about which fields are initialized in which instances.

Create a separate class for the controller, and access the window in it in the usual way:

@FXML
public void handleButtonAction(ActionEvent event) {
    if (event.getSource() == buttonIconify) {
        Stage stage = (Stage) buttonIconify.getScene().getWindow();
        stage.setIconified(true);
    }

    if (event.getSource() == buttonExit) {
        Platform.exit();
    }
}

For what it's worth, I recommend using different handlers for different actions, instead of one big handler with (potentially) a whole bunch of if statements.

James_D
  • 201,275
  • 16
  • 291
  • 322
0

I suggest you use NetBeans. It will set the project up for you. In your example, you are combining two different ways to set up a JavaFX projects. Look here.

enter image description here

In the image above you have JavaFX Application and JavaFX FXML Application. The project structure for these two types of applications is different. If you want to create a project that uses FXML and Controllers use JavaFX FXML Application. At this point in your coding, you should not have to write anything in the Main. Later, once you get to more advance MCV concepts you might.

SedJ601
  • 12,173
  • 3
  • 41
  • 59
0

You can add Platform.runLater() around your code, for example:

public static void winMin() {
    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            stage.setIconified(true);
        }
    });
}
barbsan
  • 3,418
  • 11
  • 21
  • 28