【发布时间】:2014-09-06 21:36:15
【问题描述】:
所有从用户点击以外的地方更新我的 swing GUI 的处理器都是使用 EventQueue.invokeLater 执行的(例如,从长时间运行的后台非 EDT 线程进程生成的输出)。
在我当前的场景中,我有一个 TCPIP 套接字读取后台线程进程,它返回需要更新 JEditorPane 对象的数据。我使用 JEditorPane setText 调用。问题是,将 setText 调用放在 invokeLater 例程中会冻结大文件的 GUI(示例案例测试 19,790 KB)。
我尝试解决这个问题是在非 EDT 后台线程中执行 setText 操作。这似乎解决了问题,但是,我担心最佳实践,因为 java 7(我正在使用的 JDK)中的 JEditorPane setText 不是线程安全的。
然而,通过 JDK 代码拖网,在我看来,这里执行的冗长过程是在 JDK DefaultEditorKit.read 中,并且在该方法中,唯一会影响 GUI 的代码是在 doc.insertString 调用中(除非我是错误)。现在,当您查看 JDK 的 PlainDocument.java insertString 方法时,它记录了它是线程安全的,因此人们会认为这个解决方案是合理的。
但是...
对我的应用程序进行压力测试,我在 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();
}
【问题讨论】:
-
使用 SwingWorker 下载文本并使用 it's done 方法应用它...
-
@MadProgrammer SwingWorker 将应用与上述相同的原则(一旦我确定了上述的正确性,我会将其更改为使用 SwingWorker)。也就是说,setText 在后台而不是在 EDT 中完成(这本质上就是 SwingWorker 的内容,对吧?),然后 EDT 上所需的任何发布操作都在 done 方法中完成。我假设这就是您的意思,否则将 setText 放在 SwingWorker done 方法中会产生与我原来的问题代码相同的效果 - 在 EDT 中执行 setText 会冻结 GUI。想法?
-
没有。 SwingWoker 为您提供发布/处理方法,允许您与 EDT 同步更新。事实上,您可以简单地使用 done 方法,该方法也在 EDT 中调用以更新 UI。请记住,Swing 通常不是线程安全的。
-
@MadProgrammer,但这种方法仍然会导致原来的 GUI 冻结问题。 EDT 线程上的 setText(带有大数据)冻结了 GUI。当然,除非我按照本的解决方案将大数据分解成块,并使用您建议的 SwingWorker 方法在 EDT 上同步这些块 GUI 更新。
-
您仍然可以使用 publish 和 process 将“块”发送到 EDT 并在 doInBackground 方法仍在运行时对其进行处理
标签: java settext jeditorpane