更新时摇摆组件闪烁很多

时间:2009-03-21 20:56:15

标签: java multithreading swing flicker jtextpane

我在某处有几千行代码,我注意到当我更新它时,我的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)样式的GUI组件 -

我想我已经完成了所有优化,包括将\n作为最终变量,因此不会构建数百次。然而,闪烁是显而易见的,也是不可接受的。几分钟后,组件完全冻结。我必须非常快速地更新组件,并且在更新时必须将窗格滚动到底部。

我一直在考虑从头开始创建自己的JTextPane版本,但我想看看你们是否有更简单的解决方案。

2 个答案:

答案 0 :(得分:8)

您的部分错误是您正在从事件线程外部访问Swing组件!是的,setText()是线程安全的,但Swing方法不是线程安全的,除非它们是明确声明的。因此,setCaretPosition()不是线程安全的,必须从事件线程访问。这几乎可以肯定您的应用程序最终冻结的原因。

注意:JTextPanesetText()继承了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 :(得分:1)

不确定这是否有效,但您可以尝试使用文本窗格的insertString()实例的Document方法。我会尝试在文档末尾留出一个空格,并将插入符号放在该空格之后;但是当您插入字符串时,请将其插入空格之前。这样,插入符号位置将自动保留在文档的末尾。

我认为文本窗格可能会重新绘制两次,一次调用setText()时,一次调用setCaretPosition(),这可能会导致闪烁。但不确定(自从我使用Swing以来已经有一段时间了)。