-1

I am trying to display a synchronized clock in my Java FX GUI with the function given below.

This also includes a timer function which runs if Timer=true

private Calendar cal;
private int minute;
private int hour;
private int second;
private String am_pm;

private boolean Timer;
private Integer tseconds;
private void startClock() {
    Timeline clock = new Timeline(new KeyFrame(Duration.millis(Calendar.getInstance().get(Calendar.MILLISECOND)), new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {

            cal = Calendar.getInstance();
            second = cal.get(Calendar.SECOND);
            minute = cal.get(Calendar.MINUTE);
            hour = cal.get(Calendar.HOUR);
            am_pm = (cal.get(Calendar.AM_PM) == 0) ? "AM" : "PM";
            time.setText(String.format("%02d : %02d : %02d %s", hour, minute, second, am_pm));
            if (Timer) {
                if (tseconds == 0) {
                    Timer = false;
                    //timer.setText("Time Out");
                } else {
                    //timer.setText(tseconds.toString());
                    tseconds--;
                }
            }
        }
    }), new KeyFrame(Duration.millis(Calendar.getInstance().get(Calendar.MILLISECOND))));
    clock.setCycleCount(Animation.INDEFINITE);
    clock.play();
}

I tested this few times and found that many a times the clock updates at a variable speed.

Solved

Look for the solution below.

Midhun Monachan
  • 588
  • 4
  • 12
  • 1
    Use the `delay` property instead to delay starting the `Timeline` instead of using the current milliseconds as cycle length for your `Timeline` which results in a pretty random update frequency... – fabian Apr 15 '18 at 01:36
  • @fabian i already solved it. Thanks anyway – Midhun Monachan Apr 15 '18 at 05:05

2 Answers2

0

Use an AnimationTimer to listen for updates:

class MyClass extends AnimationTimer {
   private final static long INTERVAL = 1000L;
   private long nextUpdate;
   public void handle(long now) { 
      if (now >= nextUpdate) {
        ....
        nextUpdate = now + INTERVAL;
   }
}

...
MyClass foo = new MyClass(); 
foo.start();
M. le Rutte
  • 3,525
  • 3
  • 18
  • 31
0

Solved the issue.

I was setting the duration as the current milliseconds instead of milliseconds remaining for the next second.

Only the first KeyFrame should have the duration (1000-current millisecond) as the KeyFrame will run for a duration which is equal to the milliseconds left in the current second.

The following KeyFrames will be running at an interval of 1 second.

private void startClock() {
    Timeline clock = new Timeline(new KeyFrame(Duration.millis(1000 - Calendar.getInstance().get(Calendar.MILLISECOND)), new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {

            cal = Calendar.getInstance();
            second = cal.get(Calendar.SECOND);
            minute = cal.get(Calendar.MINUTE);
            hour = cal.get(Calendar.HOUR);
            am_pm = (cal.get(Calendar.AM_PM) == 0) ? "AM" : "PM";
            time.setText(String.format("%02d : %02d : %02d %s", hour, minute, second, am_pm));
            if (Timer) {
                if (tseconds == 0) {
                    Timer = false;
                    //timer.setText("Time Out");
                } else {
                    //timer.setText(tseconds.toString());
                    tseconds--;
                }
            }
        }
    }), new KeyFrame(Duration.seconds(1)));
    clock.setCycleCount(Animation.INDEFINITE);
    clock.play();
}
Midhun Monachan
  • 588
  • 4
  • 12