0

I'm trying to create a clock which monitors the runtime of a program through using a dynamic UI label which changes every second. I've tried using the following code but keep getting a null pointer exception. This exception stems from the "clock" label which seems to be null on the JavaFX application thread, despite having declared it within the controller class. I also implemented Platform.runlater to make sure that the label updates would be running on the JavaFX thread as that is where the label has been declared, however, it is still throwing this exception. Any pointers as to why this is happening?

Controller:

  package GUI;


import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;

import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;


public class Controller implements Initializable {
    int secondspassed = 0;
    int minutespassed = 0;
    int hourspassed = 0;
    @FXML
    private Label XPTrackerlabel;
    @FXML
    private ProgressBar XPTracker;
    @FXML
    private ComboBox Minelocation;
    @FXML
    private Label clock;


    Timer timer = new Timer();
    TimerTask ticktime = new TimerTask(){
        public void run(){
            secondspassed++;
            if (secondspassed == 60){ secondspassed = 0; minutespassed++;}
            else if (minutespassed == 60){ minutespassed = 0; hourspassed++;}
            Platform.runLater(() -> clock.setText(hourspassed + ":" + minutespassed + ":" + secondspassed));
        }
    };

    public void start() {
        timer.scheduleAtFixedRate(ticktime, 1000, 1000);
    }

    public void PressButton(ActionEvent event){
        Controller startclock = new Controller();
        startclock.start();
        System.out.println("Hello World");
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        Minelocation.getItems().addAll("North", "South", "North-East");
        XPTracker.setProgress(0.5);
        double XP = XPTracker.getProgress() * 100;
        XPTrackerlabel.setText(XP + "%");
        clock.setText(hourspassed + ":" + minutespassed + ":" + secondspassed);
    }
}

FXML File:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>

<GridPane fx:id="UI" alignment="center" hgap="10" minHeight="300.0" minWidth="300.0" vgap="10" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="GUI.Controller">
   <columnConstraints>
      <ColumnConstraints />
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
      <RowConstraints />
   </rowConstraints>
   <children>
      <Button fx:id="start_btn" mnemonicParsing="false" onAction="#PressButton" stylesheets="@Style.css" text="Start" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="NEVER" GridPane.rowIndex="7" GridPane.valignment="CENTER" GridPane.vgrow="NEVER" />
      <ComboBox fx:id="Minelocation" prefWidth="150.0" promptText="Select Area" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
      <ProgressBar fx:id="XPTracker" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="11" />
      <Label fx:id="XPTrackerlabel" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="11" GridPane.valignment="CENTER" />
      <Label fx:id="clock" GridPane.columnIndex="1" GridPane.halignment="CENTER" />
   </children>
</GridPane>

Error:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at GUI.Controller$1.lambda$run$0(Controller.java:38)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
    at java.lang.Thread.run(Unknown Source)
Fabreze
  • 1
  • 1
  • 1
    The exception is thrown at `Controller.java:38` . Please mark this line with a comment so we'll know which line is 38. – c0der Dec 23 '18 at 07:31
  • Try Initializing `ticktime` within `initialize` method. – c0der Dec 23 '18 at 07:35
  • In `PressButton` you create a new instance of `Controller`, not loading via `FXMLLoader`. That is probably the root of your problem. – Itai Dec 23 '18 at 08:10
  • See e.g. [this question](https://stackoverflow.com/questions/33303167/javafx-can-application-class-be-the-controller-class)'s answer for more info. – Itai Dec 23 '18 at 08:12

1 Answers1

0

Turns out Itai was right, for some reason I thought it was a good idea to create a new instance of controller within the Pressbutton which is why the error kept getting thrown. Just having start() instead of creating a new instance and calling start() on that fixed the issue! Thanks for the help.

Heres the revised code:

package GUI;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;

import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;


public class Controller implements Initializable {
    int secondspassed = 0;
    int minutespassed = 0;
    int hourspassed = 0;
    @FXML
    private Label XPTrackerlabel;
    @FXML
    private ProgressBar XPTracker;
    @FXML
    private ComboBox Minelocation;
    @FXML
    private Label clocker;


    Timer timer = new Timer();
    TimerTask ticktime = new TimerTask(){
        public void run(){
            secondspassed++;
            if (secondspassed == 60){ secondspassed = 0; minutespassed++;}
            else if (minutespassed == 60){ minutespassed = 0; hourspassed++;}
            Platform.runLater(() -> clocker.setText(hourspassed + ":" + minutespassed + ":" + secondspassed));
        }
    };

    public void start() {
        timer.scheduleAtFixedRate(ticktime, 1000, 1000);
    }

    public void PressButton(ActionEvent event){
        start();
        System.out.println("Hello World");
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        Minelocation.getItems().addAll("North", "South", "North-East");
        XPTracker.setProgress(0.5);
        double XP = XPTracker.getProgress() * 100;
        XPTrackerlabel.setText(XP + "%");
        clocker.setText(hourspassed + ":" + minutespassed + ":" + secondspassed);
    }
}
Fabreze
  • 1
  • 1