java - 大量更新时 Swing 组件闪烁

标签 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 作为最终变量,这样它就不会被构造数百次。尽管如此,闪烁仍然很明显且 Not Acceptable 。几分钟后,组件完全卡住。我必须非常快速地更新组件,并且更新时 Pane 必须滚动到底部。

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

最佳答案

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

注意:JTextPaneJEditorPane 继承了它的 setText() 方法,从 继承了它的 setCaretPosition 方法JTextComponent,它解释了上一段中的链接不会转到 JTextPane JavaDoc 页面。

要线程安全,您确实至少需要从事件线程中调用 setCaretPosition(),您可以使用如下代码来实现:

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

并且由于您必须从事件线程中调用 setCaretPosition(),因此您也可以从同一位置调用 setText()

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

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

关于java - 大量更新时 Swing 组件闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/669979/

相关文章:

java - AWT 中的摘要是什么

java - 如何从多个线程中获取信息? java

java - Spring /处女座 - java swing : JDialog starts behind other windows

java - 将 JPanel 上绘制的图片保存在文件中 [java]

java - 如何放大 Swing 面板中的文本字段?

java - SeekBar.onProgressChanged() 的未知重复

java - 在 servlet mvc 中创建 jdbc 连接的更好位置是?

java - 使用 .contains 检测单词的多个实例

c# - 取消 token 源和嵌套任务

c++ - 使用线程时 Windows WriteFile 问题