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?
Thread + Swing?
9 Respostas
O que você falou não faz o menor sentido. Poste o código.
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...");
}
}
}
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
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();
}
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
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.
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;
}
}
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?
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?
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