Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Java Build a JavaFX Application It's About Time Timeline Animation

Jonathan Grieve
MOD
Jonathan Grieve
Treehouse Moderator 91,253 Points

No response on Restart button: Runtime errors

Hi all,

me again.

I'm really struggling with Java. I've painstakingly followed the video and I believe I've got the code correct with no errors showing up on my IDE.

However when I click the restart button I get the following runtime errors that mean absolutely nothing to me. I have no idea how to fix.

I bow to your superior knowledge. :)

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:8413)
    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:380)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
    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$148(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:498)
    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:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769)
    ... 48 more
Caused by: java.lang.NullPointerException
    at com.teamtreehouse.pomodoro.model.Attempt.<init>(Attempt.java:14)
    at com.teamtreehouse.pomodoro.controllers.Home.prepareAttempt(Home.java:35)
    at com.teamtreehouse.pomodoro.controllers.Home.handleRestart(Home.java:96)
    ... 58 more
home.java
package com.teamtreehouse.pomodoro.controllers;

import com.teamtreehouse.pomodoro.model.Attempt;
import com.teamtreehouse.pomodoro.model.AttemptKind;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.util.Duration;

import java.lang.String;

/**
 * Created by Jonnie on 18/09/2016.
 */
public class Home {


    @FXML
    private VBox container;

    @FXML
    private Label title;
    private Attempt mCurrentAttempt;
    private StringProperty mTimerText;
    private Timeline mTimeline;

    private void prepareAttempt(AttemptKind kind){

        clearAttemptStyles();
        mCurrentAttempt = new Attempt(kind, "");
        addAttemptStyle(kind);
        title.setText(kind.getDisplayName());
        setTimerText(mCurrentAttempt.getRemainingSeconds() );
        mTimeline = new Timeline();
        mTimeline.setCycleCount(kind.getTotalSeconds());


        mTimeline.getKeyFrames().add(new KeyFrame(Duration.seconds(1), e -> {
            mCurrentAttempt.tick();
            setTimerText(mCurrentAttempt.getRemainingSeconds());
        }));
    }

    public Home() {
        mTimerText = new SimpleStringProperty();
        setTimerText("Hammer");
    }


    private void addAttemptStyle(AttemptKind kind) {
        container.getStyleClass().add(kind.toString().toLowerCase());
    }


    private void clearAttemptStyles() {
        for (AttemptKind kind : AttemptKind.values()) {
            container.getStyleClass().remove(kind.toString().toLowerCase());
        }
    }

    public void DEBUG(ActionEvent actionEvent) {
        System.out.println("Hi Mom!");
    }


    public String getTimerText() {

        return mTimerText.get();
    }

    public void setTimerText(String timerText) {
        mTimerText.setValue(timerText);
    }

    public void setTimerText(int remainingSeconds) {
        int minutes = remainingSeconds / 60;
        int seconds = remainingSeconds % 60;
        setTimerText(String.format("02d:%02d", minutes, seconds));
    }


    public void playTimer() {
        mTimeline.play();
    }

    public void pauseTimer() {
        mTimeline.pause();
    }

    public void handleRestart(ActionEvent actionEvent) {
        prepareAttempt(AttemptKind.FOCUS);
        playTimer();
    }
}
Attempt.java
   public void tick() {
        mRemainingSeconds--;
    }
}
Craig Dennis
Craig Dennis
Treehouse Teacher

Can you post your FXML too please Jonathan?

Alexander Nikiforov
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 Points

And also full Attempt.java and AttemptKind.java files.

It looks to me that error should be somewhere there, since

Caused by: java.lang.NullPointerException
    at com.teamtreehouse.pomodoro.model.Attempt.<init>(Attempt.java:14)

I just pasted your Home in s4v4 version of project downloaded from course, and no errors so far ...

handleRestart just works for me ...

It would be even greater if you can share whole project, for example on GitHub, and share link here if it is possible ...

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,253 Points

Hi Craig and Alexander!

Thanks for responding :)

Here's the rest of my code. I just thought I'd post what I thought were the most important files as in the past I've run out of screen paste when posting code on the modal. I'll think about posting code to a repo in future :)

attemptkind.java
package com.teamtreehouse.pomodoro.model;

/**
 * Created by Jonnie on 17/09/2016.
 */
public enum AttemptKind {

    BREAK(5*60, "Break"),
    FOCUS(5*60, "Focus");

    private int mTotalSeconds;
    private String mDisplayName;

    public int getTotalSeconds() {

        return mTotalSeconds;
    }


    AttemptKind(int totalSeconds, String displayName) {

        mTotalSeconds = totalSeconds;
        mDisplayName = displayName;
    }

    public String getDisplayName() {
        return mDisplayName;
    }
}
attempt.java
package com.teamtreehouse.pomodoro.model;

/**
 * Created by Jonnie on 17/09/2016.
 */
public class Attempt {

    private String mMessage;
    private int mRemainingSeconds;
    private AttemptKind mKind;

   public Attempt(AttemptKind kind, String message) {
        mMessage = message;
        mRemainingSeconds = mKind.getTotalSeconds();
        mKind = kind;
    }
 /*
    public Attempt(AttemptKind kind, String message) {
        mKind = kind;
        mMessage = message;
        mRemainingSeconds = kind.getTotalSeconds();
    }*/

    public int getmRemainingSeconds() {
        return mRemainingSeconds;
    }

    public AttemptKind getmKind() {
        return mKind;
    }

    public void setMessage(String mMessage) {
        mMessage = mMessage;
    }

    public String getMessage() {
        return mMessage;
    }

    public int getRemainingSeconds() {
        return mRemainingSeconds;
    }

    public void tick() {
        mRemainingSeconds--;
    }
}
home.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.SVGPath?>
<VBox stylesheets="/css/main.css"
      xmlns="http://javafx.com/javafx/8"
      xmlns:fx="http://javafx.com/fxml"
      fx:id="container"
      fx:controller="com.teamtreehouse.pomodoro.controllers.Home">
    <children>

        <Label fx:id="title" text="Pomodoro"/>

        <Label fx:id="time" text="00:00"/>

        <HBox styleClass="buttons">
            <children>
                <StackPane>
                    <children>
                        <StackPane styleClass="nested-action,play">
                            <children>
                                <HBox styleClass="svg-container">
                                    <SVGPath styleClass="svg"
                                             content="M1.6 17C1 17 0 16.2 0 15.6V1.3C0 .1 2.2-.4 3.1.4l8.2 6.4c.5.4.8 1 .8 1.7 0 .6-.3 1.2-.8 1.7l-8.2 6.4c-.5.2-1 .4-1.5.4z"/>
                                </HBox>
                                <Button text="Resume"/>
                            </children>
                        </StackPane>

                        <StackPane styleClass="nested-action,pause">
                            <children>
                                <HBox styleClass="svg-container">
                                    <SVGPath styleClass="svg"
                                             content="M10.2 17c-1 0-1.8-.8-1.8-1.8V1.8c0-1 .8-1.8 1.8-1.8S12 .8 12 1.8v13.4c0 1-.8 1.8-1.8 1.8z" />
                                    <SVGPath styleClass="svg"
                                             content="M10.2 17c-1 0-1.8-.8-1.8-1.8V1.8c0-1 .8-1.8 1.8-1.8S12 .8 12 1.8v13.4c0 1-.8 1.8-1.8 1.8z" />
                                </HBox>
                                <Button text="Pause"/>
                            </children>
                        </StackPane>
                    </children>
                </StackPane>

                <StackPane styleClass="nested-action,restart">
                    <children>
                        <HBox styleClass="svg-container">
                            <SVGPath styleClass="svg"
                                     content="M21 2.9C19.1 1 16.6 0 13.9 0c-1.1 0-2 .9-2 1.9s.9 1.9 2 1.9c1.7 0 3.2.6 4.4 1.8 2.4 2.4 2.4 6.3 0 8.7-1.2 1.2-2.7 1.8-4.4 1.8-1.7 0-3.2-.6-4.4-1.8-1.8-1.8-2.3-4.4-1.4-6.7L9.3 10c.2.4.5.7.9.8.4.1.8.1 1.2-.1.8-.4 1.1-1.3.8-2.1L10 4.3c0-.5-.2-1-.6-1.4l-.1-.1-.1-.2c-.2-.4-.5-.7-.9-.8-.4-.1-.8-.1-1.2.1L.9 4.8C.1 5.2-.2 6.1.2 6.9c.2.4.5.7.9.8.4.1.8.1 1.2-.1l2-.9c-1.2 3.5-.4 7.6 2.4 10.4C8.6 19 11.2 20 13.9 20s5.3-1 7.2-2.9C25 13.2 25 6.8 21 2.9z"/>
                        </HBox>
                        <Button text="Restart" onAction="#handleRestart" />
                    </children>
                </StackPane>
            </children>
        </HBox>

        <TextArea fx:id="message" promptText="What are you doing?"/>

        <ImageView>
            <image>
                <Image url="/images/pomodoro.png"/>
            </image>
        </ImageView>

    </children>
</VBox>

4 Answers

Alexander Nikiforov
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 Points

So I've found number of inconsitencies...

I will start listing them, and one by one we'll get to the same App that he does:

First, change the following line in home.fxml:

        <Label fx:id="time" text="25:00"/>

To

        <Label fx:id="time" text="${controller.timerText}"/>

This way you'll attach timerText to your controller, and when pressing restart time should appear

Second, change this linein Home.setTimerText, because of the typo in string formatting:

        setTimerText(String.format("02d:%02d", minutes, seconds));
        setTimerText(String.format("%02d:%02d", minutes, seconds));

When you do this, in your timer when pressing Restart should appear 05:00, not 25:00 like Craig did because you set up both of your Break and Focus times to 5 in AttemptKind:

    BREAK(5*60, "Break"),
    FOCUS(5*60, "Focus");

I also noted this error line in Attempt class:

    public void setMessage(String mMessage) {
        mMessage = mMessage;
    }

Change it to

    public void setMessage(String mMessage) {
        this.mMessage = mMessage;
    }

Otherwise, you are setting the argument to the argument itself ... You can see how intellijidea will make both lines grey, meaning something is not right.

That is it for now.

I was not able to make the clock working, like in Video, will edit the answer when ready ...

Update GitHub project if possible, so I can see later problems if any ...

[EDIT]

Please add to Home:

    public StringProperty timerTextProperty() {
        return mTimerText;
    }

That will make your clock tick. That line apparently is needed to provide relationship between controller and fxml

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,253 Points

Hi Alexander,

Thanks for all this.

Regarding the greyed out setter, I had noticed this but again I didn't know how to fix that functional and assumed it was something that would be fixed in the next video.

There are probably some other things in the code that I missed too but but you've spent a serious amount of time looking into them so thanks. :D

Alexander Nikiforov
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 Points

The problem is in your Attempt class.

Actually, constructor that is commented - works:

    /*
    public Attempt(AttemptKind kind, String message) {
        mKind = kind;
        mMessage = message;
        mRemainingSeconds = kind.getTotalSeconds();
    }*/

If you uncomment it and replace it with the wrong one, things should work.

Why the new constructor is wrong?

Because you are trying to execute mKind.getTotalSeconds() while mKind is null

   public Attempt(AttemptKind kind, String message) {
        mMessage = message;
        // mKind is null here
        mRemainingSeconds = mKind.getTotalSeconds();
        // this line should be BEFORE mKind.getTotalSeconds obviously
        mKind = kind;
    }

You also have some problems in Attempt class, please compare it with the project files:

For example two methods doing the same :

    // "dangerous" getter naming
    public int getmRemainingSeconds() {
        return mRemainingSeconds;
    }
    // correct, conventional getter naming
    public int getRemainingSeconds() {
        return mRemainingSeconds;
    }
}

It is also very common practice for getters to be write as getRemainingSeconds. It is very important later if in some frameworks getter will be inferred (If you ever get to 'Java Spring Basics' course e.g.), so it is better stick to conventional naming.

So change getmKind() as well...

Again, if you feel confused, check out the project files, they are "gold" standart :)

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,253 Points

Thanks Alexander....

I've made the changes but what happens now is the background changes to black but there's no countdown so clearly something is working but I can't find the code that binds to the text property to change the countsdown.

I created a Repo for this and pushed the latest changes here! :) Thanks https://github.com/jg-digital-media/pomodoro-s4v1

Carl Stålhem
Carl Stålhem
24,726 Points

Thanks for this! My timer wasn't running and it turned out that I missed the curly braces around the controller binding for the timer text in the FXML file. Once fixed everything works!

Tudor Marin
Tudor Marin
4,868 Points

Hello,

Can somebody exmplain what is up with the: public StringProperty timerTextProperty() { return mTimerText; }

Why is it needed? How exactly does it provide a relationship between controller and fxml?