Marcin Frąckiewicz
Marcin Frąckiewicz

Reputation: 69

Display text/shape at a specified time in JavaFX

I've got problem with javaFX. I want to display time in App Window every 1000ms.

public class Main extends Application {

StackPane root = new StackPane();
Time time;
Text t1;
@Override
public void start(Stage primaryStage) throws Exception{
    root.setStyle("-fx-background-color: #00FF00");
    primaryStage.setTitle("My App");
    primaryStage.setScene(new Scene(root, 1000, 800));
    primaryStage.show();
    checkTime();


    primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent t) {
            Platform.exit();
            System.exit(0);
        }
    });
}


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

public void checkTime(){
    time = new Time();
    time.start();
}

public void displayTime(int hour, int minute, int second){
    t1= new Text(200, 50, hour + ":" + minute + ":" + second);
    root.getChildren().add(t1);
}


}

And that's second class:

package sample;


import java.util.Calendar;

public class Time extends Thread {

Thread t;
public int hour;
public int minute;
public int second;
Calendar calendar;
Main main = new Main();


Time() {
}

public void run() {
    for (; ; ) {
        try {
            getTime();
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
    }
}

public void start() {
    t = new Thread(this);
    t.start();

}

public void getTime() {
    calendar = Calendar.getInstance();
    hour = calendar.get(Calendar.HOUR);
    minute = calendar.get(Calendar.MINUTE);
    second = calendar.get(Calendar.SECOND);
    System.out.println(hour + ":" + minute + ":" + second);
    main.displayTime(hour, minute, second);

}


}

I would like it to work in a similar way to a digital clock. In the next phases of the project I will want to use this way similarly to other 2D figures.

At this point, after switching on the application, the time spent in the console is correct. However, I would like exactly the same time to be displayed in the application window, at this moment only the background is displayed and nothing else.

Upvotes: 0

Views: 213

Answers (1)

Jai
Jai

Reputation: 8363

  1. Most of the time you wouldn't need to extend directly from Thread, because JavaFX has things like Timeline that can act as timers. Having that Time class is perfectly fine if you think it is necessary (due to other reasons which you did not specify).
  2. Extending from Thread and creating another Thread is definitely unnecessary though. When Time class extends Thread, it itself is already a Thread.
  3. You are creating a new instance of Main in Time. Main is supposed to create Time and pass in itself to Time, otherwise Time would not hold the reference of the original Main object.
  4. I think you will definitely get some exception at runtime even when you solve #3. You are directly modifying the scene graph via non-JavaFX Application Thread (i.e. your Time class thread). Furthermore, you are creating a new Text object each Time cycle, so even if there are no exceptions, these Text objects are going to overlap one another.

If you wants to retain the Time class for other special reasons, then this is generally what you should be doing:

public class Main extends Application {
    StackPane root = new StackPane();
    Time time;
    Text t1 = new Text(); // Instantiates only once

    @Override
    public void start(Stage primaryStage) throws Exception{
        root.setStyle("-fx-background-color: #00FF00");
        primaryStage.setTitle("My App");
        primaryStage.setScene(new Scene(root, 1000, 800));
        primaryStage.show();

        root.getChildren().add(t1);

        checkTime();


        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent t) {
                Platform.exit();
                System.exit(0);
            }
        });
    }


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

    public void checkTime(){
        time = new Time(this); // Pass ownself into Time
        time.start();
    }

    public void updateTime(int hour, int minute, int second){
        Platform.runLater(() -> t1.setText(200, 50, hour + ":" + minute + ":" + second));
    }
}
public class Time extends Thread {
    //Thread t; // Not needed
    public int hour;
    public int minute;
    public int second;
    Calendar calendar;
    Main main; // Don't instantiate

    // Pass in the main object
    Time(Main main) {
        this.main = main;
    }

    public void run() {
        for (; ; ) {
            try {
                getTime();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }

    // This is not needed, Time class has its own start() method, which will call its run() method.
    //public void start() {
    //    t = new Thread(this);
    //    t.start();
    //}

    public void getTime() {
        calendar = Calendar.getInstance();
        hour = calendar.get(Calendar.HOUR);
        minute = calendar.get(Calendar.MINUTE);
        second = calendar.get(Calendar.SECOND);
        System.out.println(hour + ":" + minute + ":" + second);
        main.updateTime(hour, minute, second); // Update main
    }
}

Upvotes: 1

Related Questions