Aperfeiçoar código de um relogio

Fiz um relogio bem simples só num JLabel mesmo… Estou estudando Threads e queria dicas!

@Override
        public void run() {
            try {
                Date data = new Date();
                Calendar c = Calendar.getInstance();
                c.setTime(data);
                int hora = c.get(Calendar.HOUR_OF_DAY);
                int min = c.get(Calendar.MINUTE);
                int seg = c.get(Calendar.SECOND);
                while (true) {
                    tempo.setText(hora + ":" + min + ":" + String.format("%1$02d", seg++));
                    Thread.sleep(1000);
                    if (seg == 60) {
                        seg = 0;
                        ++min;
                    }
                    if (min == 60) {
                        min = 0;
                        ++hora;
                    }
                    if (hora == 24) {
                        hora = 0;
                    }
                }
            } catch (InterruptedException e) {
            }
        }

O código está funcionando, só queria dicas de aperfeiçoamento! Vlws!

edit: na literatura que estou lendo diz que uma thread depois que sai de um Thread.sleep(long m) não necessariamente VAI ser movida para o estado de execução… Entao uma duvida também é: como fazer que com CERTEZA a thread desse relogio, a qual dei sleep, volte para o estado de execução ao inves de outras thread entrarem no caminho!?

No way. O correto, no seu caso, é você pegar o horário atual sempre, já que você nunca vai saber exatamente quanto tempo seu Thread.sleep gastou EXATAMENTE.

Se você pedir Thread.sleep (1000), por exemplo, pode ser que o Java espere 1 segundo e 15 milissegundos, por exemplo. Portanto, do jeito que você fez, o seu relógio vai acabar ficando atrasado gradativamente. É melhor atualizar seu relógio de 500 em 500 ms, por exemplo, e sempre pegar o horário atual.

E nunca use um “while true” para modificar um JLabel, ou seja lá o que for.
No seu caso em particular, use um javax.swing.Timer ou um java.util.Timer.

Eu pensei em criar um objeto date e formatar dentro do jlabel, mas ai a thread criaria MTO objeto eu acho né?

Vou dar uma olhada nessas classes, vlw!

Mas gostaria de saber mais de:

Por que?

Concordo com o thingol, se vc usar Timer/TimerTask seu código fica mais limpo e fácil de entender, além de não ter que usar esse while true aí…

Além disso, utilize a classe SimpleDateFormat para formatar a hora para apresentar no JLabel.

Fiz assim… Legal esssa classe =P

[code]private Timer timia = new Timer(1000, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        tempo.setText(df.format(new Date()));
    }
});[/code]

Fazendo isso pode sobrecarregar a JVM? Criando muitos objetos date? Apesar de que eles podem ser GCed, isso não pode criar um uso de memoria em excesso?

Nunca usei o SimpleDateFormat, ele é muito melhor que o DateFormat? Eu acustumei a usar o DateFormat…

Vlws!

Um exemplo bobo de relógio codificado no NetBeans.


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.Timer;

/**
 * TesteRelogio.java
 *
 * Created on 30/06/2009, 13:56:56
 */
public class TesteRelogio extends javax.swing.JFrame {
    boolean canUpdate = false;
    /** Creates new form TesteRelogio */
    public TesteRelogio() {
        timer = new Timer (500, new ActionListener() {
            private DateFormat df = new SimpleDateFormat ("HH:mm:ss");
            public void actionPerformed(ActionEvent e) {
                if (canUpdate) {
                    String hhmmss;
                    hhmmss = df.format (new Date());
                    TesteRelogio.this.lblClock.setText (hhmmss);
                }
            }
        });
        initComponents();
        timer.start();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        lblClock = new javax.swing.JLabel();
        btnStart = new javax.swing.JButton();
        btnStop = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        lblClock.setText("--:--:--");

        btnStart.setText("Start!");
        btnStart.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStartActionPerformed(evt);
            }
        });

        btnStop.setText("Stop!");
        btnStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStopActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(29, 29, 29)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(lblClock, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addComponent(btnStart)
                        .addGap(18, 18, 18)
                        .addComponent(btnStop)))
                .addContainerGap(23, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(23, 23, 23)
                .addComponent(lblClock)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnStart)
                    .addComponent(btnStop))
                .addContainerGap(28, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

    private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {
        canUpdate = true;
    }

    private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {
        canUpdate = false;
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TesteRelogio().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JButton btnStart;
    private javax.swing.JButton btnStop;
    private javax.swing.JLabel lblClock;
    // End of variables declaration
    private Timer timer;
}

Vlw thingol… Consegui usar o javax.swing.Timer aqui

Gostaria de saber mais sobre o while(true) =P

Mestres,
e se o timer parar por alguma motivo? (essas “coisas” do java são acostumadas a fazer isso)…
uma thread não seria melhor solução não?

De fato, um Timer é implementado como uma thread, mas ela não é muito robusta. Se o método actionPerformed lançar alguma exceção, então o “timer para”. Você pode modificar o código que escrevi para

         timer = new Timer (500, new ActionListener() {  
             private DateFormat df = new SimpleDateFormat ("HH:mm:ss");  
             public void actionPerformed(ActionEvent e) {  
                 if (canUpdate) {  
                     try {
                         String hhmmss;  
                         hhmmss = df.format (new Date());  
                         TesteRelogio.this.lblClock.setText (hhmmss);  
                     } catch (Throwable ex) {
                     }
                 }  
             }  
         });  

para evitar alguns problemas.

Poisé… geralmente não é uma boa o catch não fazer nada. Porém ao se tratar de timer/task é melhor assim!

:wink: