4

我在某处有几千行代码,我注意到当我更新太多 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 版本,但我想看看你们是否有更简单的解决方案。

4

2 回答 2

8

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

注意: JTextPane从 继承其setText()方法JEditorPanesetCaretPosition从继承其方法JTextComponent,这解释了上一段中的链接不会转到JTextPaneJavaDoc 页面。

为了线程安全,您至少需要setCaretPosition()从事件线程中调用,您可以使用如下代码执行此操作:

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

而且由于您必须setCaretPosition()从事件线程中调用,您还不如setText()从同一个地方调用。

您可能不需要手动设置插入符号的位置。查看JTextComponent的 JavaDoc 中的“插入符号更改”部分。

最后,您可能想查看一系列两篇文章:

于 2009-03-22T02:54:41.493 回答
1

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

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

于 2009-03-21T21:12:33.453 回答