Thread + Swing?

9 respostas
lcn.andre

Boa tarde!
Estou fazendo um pequeno programinha de chat com interface gráfica. O servidor é executado dentro de uma classe Runnable e o cliente recebe as mensagens da mesma forma. O problema é que ao chamar essa thread pela interface gráfica, a janela trava e só a thread é executada. Como resolver isso?

9 Respostas

ViniGodoy

O que você falou não faz o menor sentido. Poste o código.

lcn.andre
Vou dar um exemplo mais simples:
package Teste;

public class TelaThread extends javax.swing.JFrame {
    TesteThread thread = new TesteThread();

    public TelaThread() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jProgressBar1 = new javax.swing.JProgressBar();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("Iniciar");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("Parar");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jProgressBar1.setIndeterminate(true);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jButton1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jButton2)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButton1)
                    .addComponent(jButton2))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

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

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        thread.executando = true;
        javax.swing.SwingUtilities.invokeLater(thread);
    }

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
        thread.executando = false;
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TelaThread().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JProgressBar jProgressBar1;
    // End of variables declaration

}
package Teste;

public class TesteThread implements Runnable {
    public boolean executando;

    public void run() {
        while(executando) {
            System.out.println("Executando thread...");
        }
    }

}
Naruffy

Ao invés da sua classe TesteThread implementar Runnable faça-a herdar de Thread, e no método jButton1ActionPerformed ao invés de usar javax.swing.SwingUtilities.invokeLater(thread); use thread.start().

[]s

lcn.andre

Eu já estava transformando a classe TesteThread num SwingWorker, mas testei do jeito que você sugeriu e funcionou!
Só uma última coisa: essa janela tem dois botões, um que inicia/retoma a thread e a outra que para. Só que quando clica-se novamente em Inicar, depois da thread ter sido parada, dá uma excessão de IllegalThreadState:

thread.executando = true; if (thread.isAlive()) { thread.run(); } else { thread.start(); }

—Edit: Já consegui!

thread.executando = true; if (thread.getState().equals(Thread.State.TERMINATED)) { thread.run(); } else if (thread.getState().equals(Thread.State.NEW)) { thread.start(); }

Naruffy

lcn.andre:
Eu já estava transformando a classe TesteThread num SwingWorker, mas testei do jeito que você sugeriu e funcionou!
Só uma última coisa: essa janela tem dois botões, um que inicia/retoma a thread e a outra que para. Só que quando clica-se novamente em Inicar, depois da thread ter sido parada, dá uma excessão de IllegalThreadState:

thread.executando = true; if (thread.isAlive()) { thread.run(); } else { thread.start(); }

Você não pode dar start em uma thread morta, por isso ocorre a exceção, você terá que criar uma nova thread

ViniGodoy

Mantenha sua classe implementado Runnable. É considerado uma má prática de programação herdar de thread. Aí crie sua thread assim:

Thread t = new Thread(seuRunnable); t.start();

O método SwingUtilities.invokeLater não dispara uma nova thread. O que ele faz é enfileirar a requisição de um runnable na thread do Swing. Como quem executa esse runnable é o swing, era por isso que sua aplicação travava.

É uma boa usar o SwingWorker, como vc estava planejando.

lcn.andre
Pois é.. agora estou tentando com SwingWorker. Eis a classe:
package Teste;

import javax.swing.SwingWorker;

public class TesteThread extends SwingWorker<Void, Void> {
    public boolean executando;

    @Override
    protected Void doInBackground() throws Exception {
        while(executando) {
            System.out.println("Executando thread...");
        }
        return null;
    }
}
E o trecho que inicia/retoma:
thread.executando = true;
        if (thread.getState().equals(SwingWorker.StateValue.DONE)) {
            try {
                thread.run();
            } catch (Exception ex) {
                Logger.getLogger(TelaThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if (thread.getState().equals(SwingWorker.StateValue.PENDING)) {
            thread.execute();
        }

Ele inicia a thread, para, inicia a segunda vez, mas aí a janela para de responder. O que pode ser?

guisantogui

ViniGodoy:
Mantenha sua classe implementado Runnable. É considerado uma má prática de programação herdar de thread. Aí crie sua thread assim:

Thread t = new Thread(seuRunnable); t.start();

O método SwingUtilities.invokeLater não dispara uma nova thread. O que ele faz é enfileirar a requisição de um runnable na thread do Swing. Como quem executa esse runnable é o swing, era por isso que sua aplicação travava.

É uma boa usar o SwingWorker, como vc estava planejando.

Por que herdar de Thread é uma má pratica de programação, só por curiosidade mesmo?

Naruffy

guisantogui:

Por que herdar de Thread é uma má pratica de programação, só por curiosidade mesmo?

Eu não sabia disso, mas fui dar uma pesquisada e pelo que entendi é uma má pratica devido ao conceito de agregação vs. herança.

Ao fazer sua classe herdar uma Thread seu objeto ganha toda a carga da Thread que é usada internamente para controlar os esquemas de Thread do Java, já a sua classe não tem que ter tudo isso, apenas a sua lógica em questão. então a sua classe(que implementa runnable) tem que ser agregada a uma thread ao invés de ser uma thread.

se eu estiver errado me corrijam.

[]s

Criado 28 de abril de 2010
Ultima resposta 28 de abr. de 2010
Respostas 9
Participantes 4