Pergunta

Eu tenho um par mil linhas de algum código e tenho notado que minha JTextPane treme quando eu atualizá-lo muito .. Eu escrevi uma versão simplificada aqui:

import java.awt.*;
import javax.swing.*;

public class Test
{
    static JFrame f;
    static JTextPane a;
    static final String NL = "\n";

    public static void main(String... args)
    {
        EventQueue.invokeLater(new Runnable(){
        public void run()
        {
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        f.setSize(400, 300);
        f.setLocationRelativeTo(null);

        a = new JTextPane();
        f.add(new JScrollPane(a));

        new Thread(new Runnable(){
            public void run()
            {
                int i = 0;
                StringBuffer b = new StringBuffer();
                while(true)
                {
                    b.append(++i+NL);
                    a.setText(b.toString());
                    a.setCaretPosition(b.length());
                    try{Thread.sleep(10);}catch(Exception e){}
                }
            }
        }).start();
        }
        });

    }
}

Este é um componente terminal (cmd) estilo GUI -

Eu acho que eu fiz todas as otimizações que eu poderia aqui, incluindo ter \n como uma variável final, por isso não vai ser construído centenas de vezes. Ainda assim, a oscilação é perceptível e inaceitável. Depois de alguns minutos, o componente congela completamente. I deve atualizar o componente muito rapidamente, eo painel deve ser deslocado para a parte inferior e depois actualizada.

Eu estive pensando em fazer minha própria versão de JTextPane a partir do zero, mas eu gostaria de ver se vocês têm uma solução mais fácil.

Foi útil?

Solução

Parte do seu erro é que você está acessando um componente Swing de fora do segmento de eventos! Sim, setText ( ) é thread-safe, mas os métodos do balanço não são thread-safe, a menos que sejam explicitamente declarados como tais. Assim, setCaretPosition () não é thread-safe e deve ser acessado a partir do segmento de eventos. Isto é quase certamente por isso que a sua aplicação, eventualmente congela.

NOTA: JTextPane herda seu método setText() de JEditorPane e seu método setCaretPosition de JTextComponent, o que explica as ligações no parágrafo anterior não ir ao JTextPane página JavaDoc.

Para ser thread-safe, você realmente precisa de pelo menos setCaretPosition() chamada de dentro do segmento de eventos, o que você pode fazer com um código como este:

SwingUtilities.invokeAndWait(new Runnable() {
  public void run() {
    a.setText(b.toString());
    a.setCaretPosition(b.length());
  }
}

E uma vez que você tem que setCaretPosition() chamada de dentro do segmento de eventos, você também pode também chamar setText() do mesmo lugar.

É possível que você não pode precisar configurar manualmente a posição do cursor. Confira a seção "Caret Changes" no JavaDoc para JTextComponent .

Finalmente, você pode querer verificar para fora uma série de dois artigos:

Outras dicas

Não tenho certeza se isso vai funcionar, mas você pode tentar usar o método insertString() de exemplo Document do painel de texto. Gostaria de tentar ter um único espaço no final do documento e manter o cursor posicionado depois que o espaço; mas quando você inserir uma string, inseri-lo antes do espaço. Dessa forma, a posição do cursor permanecerá no final do documento automaticamente.

Estou pensando que o painel de texto pode estar recebendo redesenhado duas vezes, uma quando você chamar setText() e uma vez quando você chamar setCaretPosition(), e que pode estar contribuindo para a oscilação. Não tenho certeza, embora (já faz um tempo desde que eu trabalhei com Swing).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top