处理长时间运行的JEditorPane setText进程的最佳实践

时间:2014-09-06 21:36:15

标签: java settext jeditorpane

使用EventQueue.invokeLater(例如从长时间运行的后台非EDT线程进程生成的输出)执行从用户点击以外的位置更新swing GUI的所有处理器。

在我当前的场景中,我有一个TCPIP套接字读取后台线程进程,它返回需要更新JEditorPane对象的数据。我使用JEditorPane setText调用。问题是,将setText调用放在invokeLater例程中会冻结大文件的GUI(示例案例测试19,790 KB)。

我尝试解决此问题是在非EDT后台线程中执行setText操作。这似乎解决了这个问题,但我担心最佳实践,因为java 7中的JEditorPane setText(我正在使用的JDK)不是线程安全的。

虽然在JDK代码中拖网,但在我看来,这里执行的漫长过程是在JDKs DefaultEditorKit.read中,并且在该方法中,影响GUI的唯一代码是在doc.insertString调用中(除非我是错误)。现在,当您查看JDK的PlainDocument.java insertString方法时,它会记录IT IS线程安全,因此可以认为此解决方案是合理的。

...无论其

压力测试我的应用程序,我在GUI周围做一些随机点击,目前正在运行树节点动画,并且在下面的大负载期间,它似乎确实减慢了动画的速度,因此我担心我我没有执行最佳解决方案(也非常关注未来的JRE将我搞砸了,因此不依赖于insertString当前是线程安全的。)

我已经调查并看到过这个问题“如何处理长时间运行的JEditorPane setText”之前已被问过,但没有合适的答案。

问题1)有没有人对我目前的观察有所了解?

问题2)有没有人有关于如何实现这一目标的想法?

注意JEditorPane是我唯一的选择,因为我最终会支持IDE外观和感觉的动态字体。

另请注意,在EventQueue.invokeLater例程中调用以下调用,因此初始editorPane工作在EDT中。

public void updateBigDataEditorPane( final JEditorPane editorPane, final String inStr ) {
    // Update editor object and content.
    editorPane.setContentType( "text/plain" );
    editorPane.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
    editorPane.setDocument( editorPane.getEditorKit().createDefaultDocument() );
    // Content update. NOTE in non-EDT thread to stop GUI freeze with large content.
    new Thread( new Runnable() {
        @Override
        public void run() {
            //// synchronized
            synchronized( tabsLock ) {
                // Set content.
                editorPane.setText( inStr );
            } //// synchronized
        }
    }).start();
}

2 个答案:

答案 0 :(得分:0)

您可以使用EditorPane的文档(通过editorPane.getDocument())并在另一个线程中对此文档执行更改(通过insertString(...),而不是使用setText(...))

通过这样做,你可以(种类)动态地(意思是:在阅读时)写内容。

作为示例(将文件从文件添加到Textpane,不冻结UI):
编辑:这个新代码已经过测试,但它应该更好地展示我的建议......):

public void readFileAsync()
{
    final String fileName = "/path/to/file.txt";
    final StyledDocument doc = yourTextPane.getStyledDocument();

    Runnable r = new Runnable()
    {
        public void run()
        {
            try 
            {
               List<String> lines = Files.readAllLines(Paths.get(fileName), Charset.defaultCharset());
               for (String line : lines) 
               {
                  SwingUtilities.invokeLater(new Runnable()
                    {
                        public void run()
                        {
                           doc.insertString(doc.getLength(), line, null );
                        }
                    });
               }
            } catch (IOException e) {
               e.printStackTrace();
            }
        }
    };
    Thread t = new Thread(r);
    t.start();
} 

答案 1 :(得分:0)

虽然提供的答案是有益的,并且将用于解决特定的长期运行的EDT线程要求,但我最终使用的解决方案如下;

  1. 创建新的JEditorPane对象
  2. 执行耗时的setText调用
  3. 完成后,使用新创建的GUI替换GUI上当前活动的JEditorPane对象。
  4. 使用SwingWorker执行后台非EDT任务(1&amp; 2),然后在EDT线程上完成后执行第3步。