Swing компонент мерцает при частом обновлении - PullRequest
3 голосов
/ 21 марта 2009

У меня где-то пара тысяч строк кода, и я заметил, что мой JTextPane мерцает, когда я слишком сильно его обновляю ... Я написал здесь упрощенную версию:

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();
        }
        });

    }
}

Это для компонента графического интерфейса в стиле терминала (cmd) -

Я думаю, что я сделал все возможные оптимизации, включая \n в качестве конечной переменной, чтобы она не создавалась сотни раз. И все же мерцание заметно и недопустимо. Через несколько минут компонент полностью зависает. Я должен обновить компонент очень быстро, и панель должна быть прокручена до конца при обновлении.

Я думал о создании собственной версии JTextPane с нуля, но я хотел бы посмотреть, есть ли у вас, ребята, более простое решение.

Ответы [ 2 ]

8 голосов
/ 22 марта 2009

Часть вашей ошибки в том, что вы обращаетесь к компоненту Swing вне потока событий! Да, setText () является поточно-ориентированным, но методы Swing не являются поточно-ориентированными, если они явно не объявлены как таковые. Таким образом, setCaretPosition () не является потокобезопасным и должно быть доступно из потока событий. Это почти наверняка, почему ваше приложение в конечном итоге зависает.

ПРИМЕЧАНИЕ: JTextPane наследует свой метод setText() от JEditorPane и метод setCaretPosition от JTextComponent, что объясняет ссылки в предыдущем абзаце, не идущие на JTextPane Страница JavaDoc.

Чтобы быть потокобезопасным, вам действительно нужно по крайней мере вызвать setCaretPosition() из потока событий, что вы можете сделать с помощью следующего кода:

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

И поскольку вам нужно позвонить setCaretPosition() из потока событий, вы также можете позвонить setText() из того же места.

Возможно, вам не нужно вручную устанавливать положение каретки. Ознакомьтесь с разделом «Изменения каретки» в JavaDoc для JTextComponent .

Наконец, вы можете проверить серию из двух статей:

1 голос
/ 22 марта 2009

Не уверен, что это будет работать, но вы можете попробовать использовать метод insertString() экземпляра Document текстовой панели. Я попытался бы иметь один пробел в конце документа и держать каретку после этого пробела; но когда вы вставляете строку, вставьте ее перед пробелом. Таким образом, позиция каретки останется в конце документа автоматически.

Я думаю, что текстовая панель может перерисовываться дважды, один раз при вызове setText() и один раз при вызове setCaretPosition(), и это может способствовать мерцанию. Хотя не уверен (я давно работал с Swing).

...