Relogio na jlabel

3 respostas
fcmorini

esse é meu primeiro post…
espero que ajude aos colegas do forum…
chega de conversa e vamos ao que interessa…
um codigo simples para fazer de uma jlabel um relóginho na tela…
este código está dentro de uma JFrame…

private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

    public LoginFrm() {
        initComponents();
        controlaTempo();
    }

    public void controlaTempo() {
        new Thread() {

            @Override
            public void run() {
                while (true) {
                    try {
                        String data = sdf.format(new Date());
                        jlbData.setText(data.substring(0, data.indexOf(" ")));
                        jlbHora.setText(data.substring(data.indexOf(" ") + 1));
                        sleep(1000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(LoginFrm.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }.start();
    }

3 Respostas

ViniGodoy

A forma mais simples é com um javax.swing.timer

Agora, cuidado que você cometeu um errinho básico. Se você for atualizar componentes do Swing a partir de outras threads, deve chamar o comando EventQueue.invokeLater ou o comando EventQueue.invokeAndWait para que essa atualização seja feita na própria thread do Swing. Caso contrário, você pode experimentar alguns efeitos estranhos no seu JFrame.

Nesse tópico (e nos dois seguintes) tem exemplos de como montar um relógio na tela:
http://www.guj.com.br/posts/list/52964.java#279083

Usando threads (como você fez), e usando os dois timers disponíveis na API do Java.

fcmorini

não entendi…
bom, esse código é apenas pra mostrar o tempo corrigo em uma tela de login…

ViniGodoy

fcmorini:
não entendi…
bom, esse código é apenas pra mostrar o tempo corrigo em uma tela de login…

Só estava ressaltando que existem 2 threads. A que você criou (e que está rodando aquele método run()) e a do Swing, que é responsável por desenhar os componentes de tela em si.

Somente a thread do Swing pode chamar o método setText do JLabel. Entretanto, você está fazendo a chamada do setText diretamente do seu método run(), em outra thread. Isso pode gerar problemas no desenho do seu JFrame, e sua tela de login começar a desenhar lixo. Como o problema é esporádico e de difícil resolução, é melhor preveni-lo logo de cara.

Você pode ler esses dois artigos para mais detalhes:
http://java.sun.com/docs/books/tutorial/uiswing/concurrency/initial.html
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

Seu código corrigido ficaria assim:

private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

    public LoginFrm() {
        initComponents();
        controlaTempo();
    }

    public void controlaTempo() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        final String data = sdf.format(new Date());
                        EventQueue.invokeLater(new Runnable() {
                            public void run() {
                                jlbData.setText(data.substring(0, data.indexOf(" ")));
                                jlbHora.setText(data.substring(data.indexOf(" ") + 1));
                            });
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException ex) {}
            }
        })).start();
    }

Aproveitei e fiz outras correções:

  1. Fiz a InterruptedException parar o while. Tipicamente, quem chamará o interrupt() é a VM quando estiver matando sua aplicação. Isso fará com que a thread pare “graciosamente”. É a maneira certa de se tratar um interrupt, e logs geralmente não precisam ser gerados;
  2. Criei um Runnable para a classe Thread, ao invés de sobrescrever Thread diretamente. É considerada uma boa prática não sobrescrever Thread, pois isso separa a classe que dispara a thread (Thread) da classe que contém o código que será executado (filha de Runnable);
  3. Chamei o método sleep através de Thread.sleep, que é a maneira mais clara de se faze-lo. Como sleep trata-se de um método estático, é errado chamado através da instância, como você fez.
Criado 31 de maio de 2010
Ultima resposta 31 de mai. de 2010
Respostas 3
Participantes 2