tags:

views:

313

answers:

4

I want to implement a clock within my program to diusplay the date and time while the program is running. I have looked into the getCurrentTime() method and Timers but none of them seem to do what I would like.

The problem is I can get the current time when the program loads but it never updates. Any suggestions on something to look into would be greatly appreciated!

+3  A: 

What you need to do is use Swing's Timer class.

Just have it run every second and update the clock with the current time.

Timer t = new Timer(1000, updateClockAction);
t.start();

This will cause the updateClockAction to fire once a second. It will run on the EDT.

You can make the updateClockAction similar to the following:

ActionListener updateClockAction = new ActionListener() {
  public void actionPerformed(ActionEvent e) {
      // Assumes clock is a custom component
      yourClock.setTime(System.currentTimeMillis()); 
      // OR
      // Assumes clock is a JLabel
      yourClock.setText(new Date().toString()); 
    }
}
jjnguy
I did a test and the update was always about half second behind using javax.swing.Timer but, I don't know why
OscarRyz
A: 

This sounds like you might have a conceptual problem. When you create a new java.util.Date object, it will be initialised to the current time. If you want to implement a clock, you could create a GUI component which constantly creates a new Date object and updates the display with the latest value.

One question you might have is how to repeatedly do something on a schedule? You could have an infinite loop that creates a new Date object then calls Thread.sleep(1000) so that it gets the latest time every second. A more elegant way to do this is to use a TimerTask. Typically, you do something like:

private class MyTimedTask extends TimerTask {

   @Override
   public void run() {
      Date currentDate = new Date();
      // Do something with currentDate such as write to a label
   }
}

Then, to invoke it, you would do something like:

Timer myTimer = new Timer();
myTimer.schedule(new MyTimedTask (), 0, 1000);  // Start immediately, repeat every 1000ms
PhilDin
This code probably works fine, but since you are using Java.util.Timer, you need to make sure that you use `SwingUtilities.invokeLater()` to update the GUI.
jjnguy
Definitely. I was deliberately vague about the "Do Something" bit, I didn't want to introduce too many things simultaneously.
PhilDin
+1  A: 

You have to update the text in a separate thread every second.

Ideally you should update swing component only in the EDT ( event dispatcher thread ) but, after I tried it on my machine, using Timer.scheduleAtFixRate gave me better results:

java.util.Timer

The javax.swing.Timer version was always about half second behind:

javax.swing.Timer

I really don't know why.

Here's the full source:

package clock;

import javax.swing.*;
import java.util.*;
import java.text.SimpleDateFormat;

class Clock {
    private final JLabel time = new JLabel();
    private final SimpleDateFormat sdf  = new SimpleDateFormat("hh:mm");
    private int   currentSecond;
    private Calendar calendar;

    public static void main( String [] args ) {
        JFrame frame = new JFrame();
        Clock clock = new Clock();
        frame.add( clock.time );
        frame.pack();
        frame.setVisible( true );
        clock.start();
    }
    private void reset(){
        calendar = Calendar.getInstance();
        currentSecond = calendar.get(Calendar.SECOND);
    }
    public void start(){
        reset();
        Timer timer = new Timer();
        timer.scheduleAtFixedRate( new TimerTask(){
            public void run(){
                if( currentSecond == 60 ) {
                    reset();
                }
                time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond ));
                currentSecond++;
            }
        }, 0, 1000 );
    }
}

Here's the modified source using javax.swing.Timer

    public void start(){
        reset();
        Timer timer = new Timer(1000, new ActionListener(){
        public void actionPerformed( ActionEvent e ) {
                if( currentSecond == 60 ) {
                    reset();
                }
                time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond ));
                currentSecond++;
            }
        });
        timer.start();
    }

Probably I should change the way the string with the date is calculated, but I don't think that's the problem here

I have read, that, since Java 5 the recommended is: ScheduledExecutorService I leave you the task to implement it.

OscarRyz
Interesting, I wonder why it is a whole .5 seconds behind.
jjnguy
I don't know, probably it was the startup time ( to get into the EDT or something ) but I couldn't recover them.
OscarRyz
+1  A: 

For those preferring an analog display: Analog Clock JApplet.

trashgod