0

I'm trying to make a Stopwatch application, but I keep on running into the same runtime exceptions. I've been struggling with it for days, and I am not sure how to fix it. Any advice would be greatly appreciated! This is my first decent length project in Java, so I'm determined to figure it out; just having quite a bit of trouble, and I am unsure of how to get past this.

TimerStopWatch.java

import java.text.DecimalFormat;
import java.util.Optional;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.TextInputDialog;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.util.Duration;

class TimerStopWatch {
    private ImageView dialImageView = new ImageView();
    private ImageView handImageView = new ImageView();
    private String dialImageName = "clockface.png";
    private String handImageName = "hand.png";
    private Image dialImage = new Image(getClass().getResourceAsStream(dialImageName));
    private Image handImage = new Image(getClass().getResourceAsStream(handImageName));
    private StackPane analogContainer = new StackPane();
    
    private Text digitalLabel = new Text();
    private Text timerLabel = new Text();
    private Label championLabel = new Label();
    private VBox timeInfoBox = new VBox();
    
    private Label lapTimeLabel = new Label();
    private Text record1Label = new Text();
    private Text record2Label = new Text();
    private Text record3Label = new Text();
    private VBox recInfoBox = new VBox();
    
    private HBox infoBox = new HBox();
    
    private Button funcButton = new Button("Record");
    private Button recButton = new Button("Start");
    private HBox buttonsBox = new HBox();
    
    private GridPane grid = new GridPane();
    
    private double tickTimeInSeconds = 0.01;
    private double angleDeltaPerSeconds = 6.0;
    double secondsElapsed = 0;
    private Timeline timeline;
    private KeyFrame keyFrame;
    
    private String timeInfo = "00:00.00";
    
    private int timerStartTime = 60;
    private double timerSecondsLeft = 60.00;
    private int timeUpTag = 0;
    private Alert notNumbersAlert = new Alert(Alert.AlertType.ERROR,"Insert only integers!", ButtonType.CLOSE);
    
    private DecimalFormat dfTimer = new DecimalFormat("#.00");
    private DecimalFormat dfRec = new DecimalFormat("00");
    
    private double oldTime = 0.00;
    private int numberOfRecords = 0;
    
    public TimerStopWatch(){
        setupTimer();
        setupUI();
        setupTimeline();
        setupButtonAction();
    }
    
    private void setupTimer(){
        TextInputDialog dialog = new TextInputDialog("");
        dialog.setTitle("Timer Start Time Set Up");
        dialog.setHeaderText("Set up the start time:");
        dialog.setContentText("Please set up the start time (Integer):");
        boolean legalTime = false;
        
        while(!legalTime){
            Optional<String> input = dialog.showAndWait();
            if(input.isPresent()){
                if((input.get().matches("[0-9]+") && input.get().length() > 0 ) == false){
                    notNumbersAlert.showAndWait();
            }else{
                    timerStartTime = Integer.valueOf(input.get());
                    legalTime = true;
                }
            }
        }
        timerSecondsLeft = timerStartTime;
    }
    
    private void setupUI(){
        dialImageView.setImage(dialImage);
        handImageView.setImage(handImage);
        analogContainer.getChildren().addAll(dialImageView, handImageView);
        
        digitalLabel.setText(timeInfo);
        digitalLabel.setFont(Font.font ("Verdana", 30));
        timerLabel.setText("Timer: " + String.valueOf(timerSecondsLeft) + ".00");
        timerLabel.setFont(Font.font ("Verdana", 20));
        championLabel.setText("Champion: 00:00:00");
        championLabel.setFont(Font.font ("Verdana", 20));
        
        lapTimeLabel.setText("Lap Time");
        lapTimeLabel.setFont(Font.font ("Verdana", 20));
        record1Label.setText("Rec 00 +00:00.00");
        record1Label.setFont(Font.font ("Verdana", 18));
        record2Label.setText("Rec 00 +00:00.00");
        record2Label.setFont(Font.font ("Verdana", 18));
        record3Label.setText("Rec 00 +00:00.00");
        record3Label.setFont(Font.font ("Verdana", 18));
        
        infoBox.setAlignment(Pos.CENTER);
        infoBox.setSpacing(20);
        infoBox.getChildren().addAll(timeInfoBox, recInfoBox);
        
        timeInfoBox.setAlignment(Pos.CENTER);
        timeInfoBox.setSpacing(10);
        timeInfoBox.getChildren().addAll(digitalLabel, timerLabel, championLabel);
        
        recInfoBox.setAlignment(Pos.CENTER);
        recInfoBox.setSpacing(5);
        recInfoBox.getChildren().addAll(lapTimeLabel, record1Label, record2Label, record3Label);
        
        buttonsBox.setAlignment(Pos.CENTER);
        buttonsBox.setSpacing(10);
        buttonsBox.getChildren().addAll(funcButton, recButton);
        
        grid.setVgap(30);
        grid.setHgap(10);
        grid.setAlignment(Pos.CENTER);
        
        grid.add(analogContainer, 0, 0);
        grid.add(infoBox, 0, 1);
        grid.add(buttonsBox, 0, 2);
    }
    
    private void setupTimeline(){
        if(isRunning()){
            timeline.stop();
        }
        keyFrame = new KeyFrame(Duration.millis(tickTimeInSeconds*1000), (ActionEvent event) -> {
            update();
        });
        timeline = new Timeline(keyFrame);
        timeline.setCycleCount(Animation.INDEFINITE);
    }
    
    private void setupButtonAction(){
        recButton.setOnAction((ActionEvent event) -> {
            if(timeline.getStatus() != Animation.Status.RUNNING){
                timeline.play();
                recButton.setText("Stop");
                funcButton.setText("Record");
            }else {
                timeline.stop();
                recButton.setText("Start");
                funcButton.setText("Reset");
            }
        });
        
        funcButton.setOnAction((ActionEvent event) -> {
            if(timeline.getStatus() == Animation.Status.RUNNING){
                if(timerLabel.getText() != "Time's Up!"){
                    numberOfRecords++;
                    if(numberOfRecords == 1){
                        championLabel.setText("Champion: " + getMessage(secondsElapsed));
                    }
                    if((numberOfRecords % 3) == 1){
                        record1Label.setText("Rec " + dfRec.format(numberOfRecords) + " +" + getMessage(secondsElapsed - oldTime));
                    }else if ((numberOfRecords % 3) == 2){
                        record2Label.setText("Rec " + dfRec.format(numberOfRecords) + " +" + getMessage(secondsElapsed - oldTime));
                    }else{
                        record3Label.setText("Rec " + dfRec.format(numberOfRecords) + " +" + getMessage(secondsElapsed - oldTime));
                    }
                    oldTime = secondsElapsed;
                }else{
                    timeUp();
                }
            }else{
                reset();
            }
        });
    }
    
    public void timeUp(){
        Alert alert = new Alert(Alert.AlertType.INFORMATION, "Time is up... No more records...");
        alert.setTitle("Time is up!!!");
        alert.setHeaderText("Alert");
        alert.show();
    }
    
    public void reset(){
        secondsElapsed = 0.0;
        timerSecondsLeft = timerStartTime;
        
        handImageView.setRotate(0.0);
        funcButton.setText("Record");
        
        digitalLabel.setText("00:00:00");
        timerLabel.setText("Timer: " + String.valueOf(timerSecondsLeft) + ".00");
        championLabel.setText("Champion: 00:00.00");
        record1Label.setText("Rec 00 +00:00.00");
        record2Label.setText("Rec 00 +00:00.00");
        record3Label.setText("Rec 00 +00:00.00");
        
        timeUpTag = 0;
        numberOfRecords = 0;
        oldTime = 0.00;
    }
    
    public boolean isRunning(){
        if(timeline != null){
            if(timeline.getStatus() == Animation.Status.RUNNING){
                return true;
            }
        }
        return false;
    }
    
    public void update(){
        secondsElapsed += tickTimeInSeconds;
        
        double rotation = secondsElapsed * angleDeltaPerSeconds;
        handImageView.setRotate(rotation);
        
        digitalLabel.setText(getMessage(secondsElapsed));
        
        timerSecondsLeft -= tickTimeInSeconds;
        if(timerSecondsLeft <= 0.0 && timeUpTag == 0){
            timerLabel.setText("Time's Up!");
            timeUpTag = 1;
        }else if(timeUpTag == 0){
            timerLabel.setText("Timer: " + dfTimer.format(timerSecondsLeft));
        }
    }
    
    public String getMessage(double secondsElapsed){
        timeInfo = (String.format("%02d:", (int)secondsElapsed/60) +
                    String.format("%02d.", (int)secondsElapsed%60) +
                    String.format("%02d", (int)((secondsElapsed*100)%100)));
        return timeInfo;
    }
    
    public Double getWidth(){
        if(dialImage != null)
            return dialImage.getWidth();
        else
            return 0.0;
    }
    
    public Double getHeight(){
        if(dialImage != null)
            return dialImage.getHeight();
        else
            return 0.0;
    }
    
    public Parent getRootGrid(){
        return grid;
    }
}
StopWatch.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class StopWatch extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        TimerStopWatch timerStopWatch = new TimerStopWatch();
        Scene scene = new Scene(timerStopWatch.getRootGrid(),
                                timerStopWatch.getWidth() + 200,
                                timerStopWatch.getHeight() + 220);
        
        primaryStage.setTitle("Timer Stopwatch");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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


Exception in Application start method
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 com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    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.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: stopwatch/TimerStopWatch
    at stopwatch.StopWatch.start(StopWatch.java:24)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(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$148(WinApplication.java:191)
    ... 1 more
Caused by: java.lang.ClassNotFoundException: stopwatch.TimerStopWatch
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 10 more
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Azoros
  • 13
  • 1
  • 4
    The package import statements are important for this example, but are not in the code you supplied. According the stack trace the package used is `stopwatch`. `TimerStopWatch` should be public. When posting code your should post a [mcve] (what you have is not minimal). If you decide to update it, make sure it is also complete. – jewelsea Oct 10 '21 at 08:02
  • Imports appear consistent; an incorrect value for `dialImageName` reproduces the exception. – trashgod Oct 12 '21 at 13:42

0 Answers0