2010-06-02 15 views
8

Desidero implementare un orologio nel mio programma per modificare la data e l'ora mentre il programma è in esecuzione. Ho esaminato il metodo getCurrentTime() e Timer s ma nessuno di loro sembra fare ciò che vorrei.Dynamic Clock in java

Il problema è che è possibile ottenere l'ora corrente quando il programma viene caricato ma non si aggiorna mai. Qualsiasi suggerimento su qualcosa da esaminare sarebbe molto apprezzato!

+1

non faccio swing ampiamente, quindi nessuna risposta dettagliata dalla mia, ma Google sembra dare sufficienti indizi: http: // www .google.com/search? q = java + swing + clock Al punto: è necessario aggiornare l'orologio * te * ogni volta in un thread in background. – BalusC

+1

@BalusC ma google estensivamente;) – Bozho

risposta

13

Quello che dovete fare è usare la classe Timer di Swing.

Basta farlo funzionare ogni secondo e aggiornare l'orologio con l'ora corrente.

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

Questo farà sì che la updateClockAction al fuoco una volta al secondo. Funzionerà su EDT.

si può fare la updateClockAction simile al seguente:

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()); 
    } 
} 

Perché questo aggiorna l'orologio ogni secondo, l'orologio sarà fuori da 999ms in uno scenario peggiore. Per aumentare ad un peggio caso margine di errore di 99ms, è possibile aumentare la frequenza di aggiornamento:

Timer t = new Timer(100, updateClockAction); 
+1

Ho fatto un test e l'aggiornamento era sempre di circa mezzo secondo indietro usando javax.swing.Timer ma, non so perché – OscarRyz

2

Questo suona come si potrebbe avere un problema concettuale. Quando crei un nuovo oggetto java.util.Date, verrà inizializzato all'ora corrente. Se si desidera implementare un orologio, è possibile creare un componente GUI che crea costantemente un nuovo oggetto Date e aggiorna il display con il valore più recente.

Una domanda che potresti avere è come fare ripetutamente qualcosa in base a un programma? Si può avere un ciclo infinito che crea un nuovo oggetto Date, quindi chiama Thread.sleep (1000) in modo che ottenga l'ora più recente ogni secondo. Un modo più elegante per farlo è usare un TimerTask. In genere, si fa qualcosa di simile:

private class MyTimedTask extends TimerTask { 

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

Poi, per invocarlo, si potrebbe fare qualcosa di simile:

Timer myTimer = new Timer(); 
myTimer.schedule(new MyTimedTask(), 0, 1000); // Start immediately, repeat every 1000ms 
+4

Questo codice probabilmente funziona bene, ma dal momento che stai usando Java.util.Timer, è necessario assicurarsi di utilizzare 'SwingUtilities.invokeLater()' per aggiornare la GUI. – jjnguy

+0

Definitivamente. Sono stato deliberatamente indeciso sul "Do Something", non volevo introdurre troppe cose contemporaneamente. – PhilDin

5

È necessario aggiornare il testo in un thread separato ogni secondo.

Idealmente si dovrebbe aggiornare componente Swing solo nel EDT (evento filo dispatcher), ma, dopo che ho provato sulla mia macchina, utilizzando Timer.scheduleAtFixRate mi ha dato risultati migliori:

java.util.Timer http://img175.imageshack.us/img175/8876/capturadepantalla201006o.png

Il javax.swing. versione timer era sempre circa mezzo secondo dietro:

javax.swing.Timer http://img241.imageshack.us/img241/2599/capturadepantalla201006.png

io davvero non so perché.

Ecco il sorgente completo:

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); 
    } 
} 

Ecco il sorgente modificato utilizzando 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(); 
    } 

Probabilmente dovrei cambiare il modo in cui la corda con la data viene calcolata, ma non credo che sia il problema qui

Ho letto, che, dal momento che Java 5 la consigliato è: ScheduledExecutorService Ti lascio il compito di implementarlo.

+0

Interessante, mi chiedo perché è un intero 0,5 secondi indietro. – jjnguy

+0

Non so, probabilmente era il tempo di avvio (per entrare nell'EDT o qualcosa del genere) ma non sono riuscito a recuperarli. – OscarRyz

3
public void start(){ 
     reset(); 
     ScheduledExecutorService worker = Executors.newScheduledThreadPool(3); 
     worker.scheduleAtFixedRate(new Runnable(){ 
      public void run(){ 
       if(currentSecond == 60) { 
        reset(); 
       } 
       time.setText(String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond)); 
       currentSecond++; 
      } 
     }, 0, 1000 ,TimeUnit.MILLISECONDS); 
    } 
0

Nota il metodo scheduleAtFixedRate è qui usato

 // Current time label 
     final JLabel currentTimeLabel = new JLabel(); 
     currentTimeLabel.setFont(new Font("Monospace", Font.PLAIN, 18)); 
     currentTimeLabel.setHorizontalAlignment(JTextField.LEFT); 

     // Schedule a task for repainting the time 
     final Timer currentTimeTimer = new Timer(); 
     TimerTask task = new TimerTask() { 
      @Override 
      public void run() { 
       currentTimeLabel.setText(TIME_FORMATTER.print(System.currentTimeMillis())); 
      } 
     }; 

     currentTimeTimer.scheduleAtFixedRate(task, 0, 1000);