[Resolvido] Utilizando thread dentro da classe interna

Olá, estou com o seguinte problema:

Preciso que meu JTextArea atualize em tempo real, com posso fazer isso?

Ja dei uma olhada em SwingWorker:

    public class Imprime extends SwingWorker{
          private String texto;
        public Imprime(String texto){
            this.texto = texto;
        }
        @Override
        protected JTextArea doInBackground() throws Exception {
            return null;
        }
        
        @Override
        protected void done(){
            jTextArea1.append(texto);
        }
        }

Chamo isso no método:

	public void imprimeTela(String texto) {
            texto = texto + "\r\n";
            new Imprime(texto).execute(); 
        }

E nada, o programa primeiro executa tudo para depois escrever no JTextArea.

O que devo fazer?

Não seria algo como invokeLater?

O invokeLater não vai só colocar a atualização na pilha de execução da interface?
Preciso de alguma coisa que tenha mais prioridade sobre a esta execução, ja tentei alterar a prioridade da thread e não consegui tambem. Teria alguma ideia ?

Uai, pensei que iria criar um exemplo em que invokeLater fizesse diferença, mas não fez :frowning: - tente rodar o programa abaixo.

package guj;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class ExemploInvokeLater extends JFrame {
    private JPanel panel;
    private JButton btnUsandoInvokelater;
    private JButton btnNaoUsandoInvokelater;
    private JScrollPane scrollPane;
    private JTextArea textArea;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ExemploInvokeLater frame = new ExemploInvokeLater();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public ExemploInvokeLater() {
        setBounds(100, 100, 450, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(getPanel(), BorderLayout.SOUTH);
        getContentPane().add(getScrollPane(), BorderLayout.CENTER);

    }

    private JPanel getPanel() {
        if (panel == null) {
            panel = new JPanel();
            panel.add(getBtnUsandoInvokelater());
            panel.add(getBtnNoUsandoInvokelater());
        }
        return panel;
    }

    private void addLineToJTextArea(String msg) {
        getTextArea().append(msg);
    }

    private JButton getBtnUsandoInvokelater() {
        if (btnUsandoInvokelater == null) {
            btnUsandoInvokelater = new JButton("Usando invokeLater");
            btnUsandoInvokelater.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    btnUsandoInvokelater.setEnabled(false);
                    new Thread(new Runnable() {
                        public void run() {
                            for (int i = 0; i < 100; ++i) {
                                final int x = i;
                                SwingUtilities.invokeLater(new Runnable() {
                                    public void run() {
                                        getTextArea().append(String.format("Linha %d\n", x));
                                    }
                                });
                                try {
                                    Thread.sleep(200);
                                } catch (InterruptedException ex) {
                                }
                            }
                            btnUsandoInvokelater.setEnabled(true);
                        }
                    }).start();
                }
            });
        }
        return btnUsandoInvokelater;
    }

    private JButton getBtnNoUsandoInvokelater() {
        if (btnNaoUsandoInvokelater == null) {
            btnNaoUsandoInvokelater = new JButton("N\u00E3o usando invokeLater");
            btnNaoUsandoInvokelater.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    btnNaoUsandoInvokelater.setEnabled(false);
                    new Thread(new Runnable() {
                        public void run() {
                            for (int i = 0; i < 100; ++i) {
                                final int x = i;
                                getTextArea().append(String.format("Linha %d\n", x));
                                try {
                                    Thread.sleep(200);
                                } catch (InterruptedException ex) {
                                }
                            }
                            btnNaoUsandoInvokelater.setEnabled(true);
                        }
                    }).start();
                }
            });
        }
        return btnNaoUsandoInvokelater;
    }

    private JScrollPane getScrollPane() {
        if (scrollPane == null) {
            scrollPane = new JScrollPane();
            scrollPane.setViewportView(getTextArea());
        }
        return scrollPane;
    }

    private JTextArea getTextArea() {
        if (textArea == null) {
            textArea = new JTextArea();
        }
        return textArea;
    }
}

Bah… tentei:

        public void colocaTela(String texto){
            final String element = texto;

                new Thread(new Runnable() {  
                        public void run() {  
                                SwingUtilities.invokeLater(new Runnable() {  
                                    public void run() {  
                                        jtextArea1.append(element + "\r\n");  
                                    }  
                                });  
                        }
                    }).start();  
        }

Mas não deu certo, primeiro foi executado todo o código e por ultimo foi executado o método de escrever, sendo que o método de escrever esta no meio do código.

Tem alguma ideia?

Não, eu queria que você escrevesse isto aqui:

public void colocaTela(String texto){  
    final String element = texto;  
  
                        SwingUtilities.invokeLater(new Runnable() {    
                            public void run() {    
                                jtextArea1.append(element + "\r\n");    
                            }    
                        });    
}

Você leu o meu código? Você tentou rodá-lo?

Sim, eu li e rodei ele aqui.
Mas não entendi como vou coloca-lo no meu código, estou com dificuldade de entender esta parte, pois, devo utilizar o invokeLater dentro do método que eu chamo? Ou na hora de chamar o método?
Alem disso, como o programa vai utilizar muita memória eu devo ter um espaço reservado pra isso, não ?

Basicamente é assim.

Digamos que você tem uma operação lenta, que você precisa mostrar a progressão (no seu caso, preenchendo uma JTextArea).
Essa operação lenta deve ser feita em uma thread separada, que normalmente é implementada como uma thread simples (como é o caso do meu exemplo) ou então com um SwingWorker (que é seu caso).

Como a thread separada não é a thread do Swing, então para acessar a tela, você precisa usar sempre um invokeLater para que as operações do Swing sejam executadas na thread do Swing.

Quanto a problemas de memória, não creio que haja só por causa disso. Entretanto, concordo com você que se você estiver criando um JTextArea que representa o andamento de um processo longo, com muitas linhas, você deve ter uma lógica para ir “podando” as linhas mais antigas do JTextArea para evitar que você estoure a memória por causa dele. Se você além disso precisar inspecionar, durante a execução, todas as linhas do JTextArea, como se fosse um visualizador de log, você não pode usar um JTextArea e sim algum controle customizado que alguém deve ter escrito e que representa uma visão virtual sobre um arquivo de log (por exemplo).

Resolvi tirar do programa o JTextArea, não era uma necessidade, fiz mais só para auxilio mesmo. Obrigado