Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX Live Time and Date

I am building currently an application using JavaFx with an extra feature that displays the current date and time in the top corner of the scene. Since I am new to JavaFX, I don't know how to implement this one.

I tried to use an old code in swing but I got an IllegalStateException Error.

Here's my code.

MainMenuController.java

@FXML private Label time;

private int minute;
private int hour;
private int second;

@FXML
public void initialize() {

    Thread clock = new Thread() {
        public void run() {
            for (;;) {
                DateFormat dateFormat = new SimpleDateFormat("hh:mm a");
                Calendar cal = Calendar.getInstance();

                second = cal.get(Calendar.SECOND);
                minute = cal.get(Calendar.MINUTE);
                hour = cal.get(Calendar.HOUR);
                //System.out.println(hour + ":" + (minute) + ":" + second);
                time.setText(hour + ":" + (minute) + ":" + second);

                try {
                    sleep(1000);
                } catch (InterruptedException ex) {
                     //...
                }
            }
        }
    };
    clock.start();
}

MainMenu.fxml

 <children>
   <Label fx:id="time" textFill="WHITE">
     <font>
       <Font name="Segoe UI Black" size="27.0" />
     </font>
   </Label>
   <Label fx:id="date" textFill="WHITE">
     <font>
       <Font name="Segoe UI Semibold" size="19.0" />
     </font>
   </Label>
 </children>

Main.java

public class Main extends Application {

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

   @Override
   public void start(Stage primaryStage) throws Exception {
       Parent root = FXMLLoader.load(getClass().getResource("view/MainMenu.fxml"));
       primaryStage.setScene(new Scene(root,1366, 768));
       primaryStage.show();
   }
}

As you notice, I tested it printing the live time in the console. Yeah it worked, but the label is still static.

like image 442
Bryan Reyes Avatar asked Feb 22 '17 06:02

Bryan Reyes


2 Answers

I think you need FX UI Thread Platform.runLater(...) for that, but you can do something like this using Timeline in you controller class,

@FXML
public void initialize() {

    Timeline clock = new Timeline(new KeyFrame(Duration.ZERO, e ->  
         time.setText(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
    ),
         new KeyFrame(Duration.seconds(1))
    );
    clock.setCycleCount(Animation.INDEFINITE);
    clock.play();
}

Alternative solution using AnimationTimer - suggested by @James_D,

AnimationTimer timer = new AnimationTimer() {
    @Override
    public void handle(long now) {
        time.setText(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
};
timer.start();

The second approach using AnimationTimer seems much cleaner and more accurate than with Timeline.


You can check the POC of both approaches here.

like image 66
Shekhar Rai Avatar answered Nov 06 '22 08:11

Shekhar Rai


The @Shekhar Rai answer works well, but here is a shorter version who works pretty well too.

@FXML
Label dateTime;

@Override
public void initialize(URL location, ResourceBundle resources) {
    initClock();
}

private void initClock() {

    Timeline clock = new Timeline(new KeyFrame(Duration.ZERO, e -> {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        dateTime.setText(LocalDateTime.now().format(formatter));
    }), new KeyFrame(Duration.seconds(1)));
    clock.setCycleCount(Animation.INDEFINITE);
    clock.play();
}

The main advantage is that you dont have to define every variables (seconds, minutes, ...)

like image 26
WEGSY85 Avatar answered Nov 06 '22 08:11

WEGSY85