使用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();
}
答案 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线程要求,但我最终使用的解决方案如下;
使用SwingWorker执行后台非EDT任务(1&amp; 2),然后在EDT线程上完成后执行第3步。